001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.resolve.calls.util;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.lang.ASTNode;
021    import com.intellij.psi.impl.source.tree.LeafPsiElement;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.psi.*;
025    import org.jetbrains.kotlin.psi.Call.CallType;
026    import org.jetbrains.kotlin.psi.debugText.DebugTextUtilKt;
027    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
028    
029    import java.util.ArrayList;
030    import java.util.Collections;
031    import java.util.List;
032    
033    public class CallMaker {
034    
035        private static class ExpressionValueArgument implements ValueArgument {
036    
037            private final KtExpression expression;
038    
039            private final KtElement reportErrorsOn;
040    
041            private final boolean isExternal;
042    
043            private ExpressionValueArgument(
044                    @Nullable KtExpression expression,
045                    @NotNull KtElement reportErrorsOn,
046                    boolean isExternal
047            ) {
048                this.expression = expression;
049                this.reportErrorsOn = expression == null ? reportErrorsOn : expression;
050                this.isExternal = isExternal;
051            }
052    
053            @Override
054            public boolean isExternal() {
055                return isExternal;
056            }
057    
058            @Override
059            public KtExpression getArgumentExpression() {
060                return expression;
061            }
062    
063            @Override
064            public ValueArgumentName getArgumentName() {
065                return null;
066            }
067    
068            @Override
069            public boolean isNamed() {
070                return false;
071            }
072    
073            @NotNull
074            @Override
075            public KtElement asElement() {
076                return reportErrorsOn;
077            }
078    
079            @Override
080            public LeafPsiElement getSpreadElement() {
081                return null;
082            }
083    
084            @Override
085            public boolean equals(Object o) {
086                if (this == o) return true;
087                if (o == null || getClass() != o.getClass()) return false;
088    
089                ExpressionValueArgument argument = (ExpressionValueArgument) o;
090    
091                if (expression != null ? !expression.equals(argument.expression) : argument.expression != null) return false;
092    
093                return true;
094            }
095    
096            @Override
097            public int hashCode() {
098                return expression != null ? expression.hashCode() : 0;
099            }
100        }
101    
102        private static class CallImpl implements Call {
103    
104            private final KtElement callElement;
105            private final ReceiverValue explicitReceiver;
106            private final ASTNode callOperationNode;
107            private final KtExpression calleeExpression;
108            private final List<? extends ValueArgument> valueArguments;
109            private final Call.CallType callType;
110    
111            protected CallImpl(@NotNull KtElement callElement, @NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, @Nullable KtExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments) {
112                this(callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments, CallType.DEFAULT);
113            }
114    
115            protected CallImpl(@NotNull KtElement callElement, @NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode,
116                    @Nullable KtExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments, @NotNull CallType callType) {
117                this.callElement = callElement;
118                this.explicitReceiver = explicitReceiver;
119                this.callOperationNode = callOperationNode;
120                this.calleeExpression = calleeExpression;
121                this.valueArguments = valueArguments;
122                this.callType = callType;
123            }
124    
125            @Override
126            public ASTNode getCallOperationNode() {
127                return callOperationNode;
128            }
129    
130            @NotNull
131            @Override
132            public ReceiverValue getExplicitReceiver() {
133                return explicitReceiver;
134            }
135    
136            @NotNull
137            @Override
138            public ReceiverValue getDispatchReceiver() {
139                return ReceiverValue.NO_RECEIVER;
140            }
141    
142            @Override
143            public KtExpression getCalleeExpression() {
144                return calleeExpression;
145            }
146    
147            @NotNull
148            @Override
149            public List<? extends ValueArgument> getValueArguments() {
150                return valueArguments;
151            }
152    
153            @NotNull
154            @Override
155            public KtElement getCallElement() {
156                return callElement;
157            }
158    
159            @Override
160            public KtValueArgumentList getValueArgumentList() {
161                return null;
162            }
163    
164            @NotNull
165            @Override
166            public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
167                return Collections.emptyList();
168            }
169            @NotNull
170            @Override
171            public List<KtTypeProjection> getTypeArguments() {
172                return Collections.emptyList();
173            }
174    
175            @Override
176            public KtTypeArgumentList getTypeArgumentList() {
177                return null;
178            }
179    
180            @Override
181            public String toString() {
182                return getCallElement().getText();
183            }
184    
185            @NotNull
186            @Override
187            public CallType getCallType() {
188                return callType;
189            }
190        }
191    
192        @NotNull
193        public static Call makeCallWithExpressions(@NotNull KtElement callElement, @NotNull ReceiverValue explicitReceiver,
194                                                   @Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
195                                                   @NotNull List<KtExpression> argumentExpressions) {
196            return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, CallType.DEFAULT);
197        }
198    
199        @NotNull
200        public static Call makeCallWithExpressions(@NotNull KtElement callElement, @NotNull ReceiverValue explicitReceiver,
201                                                   @Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
202                                                   @NotNull List<KtExpression> argumentExpressions, @NotNull CallType callType) {
203            List<ValueArgument> arguments = new ArrayList<ValueArgument>(argumentExpressions.size());
204            for (KtExpression argumentExpression : argumentExpressions) {
205                arguments.add(makeValueArgument(argumentExpression, calleeExpression));
206            }
207            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
208        }
209    
210        @NotNull
211        public static Call makeCall(KtElement callElement, ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, KtExpression calleeExpression, List<? extends ValueArgument> arguments) {
212            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, CallType.DEFAULT);
213        }
214    
215        @NotNull
216        public static Call makeCall(
217                KtElement callElement, ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode,
218                KtExpression calleeExpression, List<? extends ValueArgument> arguments, CallType callType) {
219            return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
220        }
221    
222        @NotNull
223        public static Call makeCall(@NotNull ReceiverValue leftAsReceiver, KtBinaryExpression expression) {
224            return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight()));
225        }
226    
227        @NotNull
228        public static Call makeCall(@NotNull ReceiverValue baseAsReceiver, KtUnaryExpression expression) {
229            return makeCall(expression, baseAsReceiver, null, expression.getOperationReference(), Collections.<ValueArgument>emptyList());
230        }
231    
232        @NotNull
233        public static Call makeArraySetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull KtArrayAccessExpression arrayAccessExpression,
234                @NotNull KtExpression rightHandSide, @NotNull CallType callType) {
235            List<KtExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
236            arguments.add(rightHandSide);
237            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments, callType);
238        }
239    
240        @NotNull
241        public static Call makeArrayGetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull KtArrayAccessExpression arrayAccessExpression,
242                @NotNull CallType callType) {
243            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions(), callType);
244        }
245    
246        @NotNull
247        public static ValueArgument makeValueArgument(@NotNull KtExpression expression) {
248            return makeValueArgument(expression, expression);
249        }
250    
251        @NotNull
252        public static ValueArgument makeValueArgument(@Nullable KtExpression expression, @NotNull KtElement reportErrorsOn) {
253            return new ExpressionValueArgument(expression, reportErrorsOn, false);
254        }
255    
256        @NotNull
257        public static ValueArgument makeExternalValueArgument(@NotNull KtExpression expression) {
258            return new ExpressionValueArgument(expression, expression, true);
259        }
260    
261        @NotNull
262        public static Call makePropertyCall(@NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull KtSimpleNameExpression nameExpression) {
263            return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.<KtExpression>emptyList());
264        }
265    
266        @NotNull
267        public static Call makeCall(@NotNull final ReceiverValue explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final KtCallElement callElement) {
268            return new Call() {
269                @Override
270                public ASTNode getCallOperationNode() {
271                    return callOperationNode;
272                }
273    
274                @NotNull
275                @Override
276                public ReceiverValue getExplicitReceiver() {
277                    return explicitReceiver;
278                }
279    
280                @NotNull
281                @Override
282                public ReceiverValue getDispatchReceiver() {
283                    return ReceiverValue.NO_RECEIVER;
284                }
285    
286                @Override
287                @Nullable
288                public KtExpression getCalleeExpression() {
289                    return callElement.getCalleeExpression();
290                }
291    
292                @Override
293                @Nullable
294                public KtValueArgumentList getValueArgumentList() {
295                    return callElement.getValueArgumentList();
296                }
297    
298                @Override
299                @NotNull
300                public List<? extends ValueArgument> getValueArguments() {
301                    return callElement.getValueArguments();
302                }
303    
304                @Override
305                @NotNull
306                public List<? extends FunctionLiteralArgument> getFunctionLiteralArguments() {
307                    return callElement.getFunctionLiteralArguments();
308                }
309    
310                @Override
311                @NotNull
312                public List<KtTypeProjection> getTypeArguments() {
313                    return callElement.getTypeArguments();
314                }
315    
316                @Override
317                @Nullable
318                public KtTypeArgumentList getTypeArgumentList() {
319                    return callElement.getTypeArgumentList();
320                }
321    
322                @NotNull
323                @Override
324                public KtElement getCallElement() {
325                    return callElement;
326                }
327    
328                @Override
329                public String toString() {
330                    return DebugTextUtilKt.getDebugText(callElement);
331                }
332    
333                @NotNull
334                @Override
335                public CallType getCallType() {
336                    return CallType.DEFAULT;
337                }
338            };
339        }
340    
341        @NotNull
342        public static Call makeCall(@NotNull KtElement callElement, @NotNull ReceiverValue explicitReceiver) {
343            return new CallImpl(callElement, explicitReceiver, null, null, Collections.<ValueArgument>emptyList());
344        }
345    }