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.Receiver;
028    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
029    
030    import java.util.ArrayList;
031    import java.util.Collections;
032    import java.util.List;
033    
034    public class CallMaker {
035    
036        private static class ExpressionValueArgument implements ValueArgument {
037    
038            private final KtExpression expression;
039    
040            private final KtElement reportErrorsOn;
041    
042            private final boolean isExternal;
043    
044            private ExpressionValueArgument(
045                    @Nullable KtExpression expression,
046                    @NotNull KtElement reportErrorsOn,
047                    boolean isExternal
048            ) {
049                this.expression = expression;
050                this.reportErrorsOn = expression == null ? reportErrorsOn : expression;
051                this.isExternal = isExternal;
052            }
053    
054            @Override
055            public boolean isExternal() {
056                return isExternal;
057            }
058    
059            @Override
060            public KtExpression getArgumentExpression() {
061                return expression;
062            }
063    
064            @Override
065            public ValueArgumentName getArgumentName() {
066                return null;
067            }
068    
069            @Override
070            public boolean isNamed() {
071                return false;
072            }
073    
074            @NotNull
075            @Override
076            public KtElement asElement() {
077                return reportErrorsOn;
078            }
079    
080            @Override
081            public LeafPsiElement getSpreadElement() {
082                return null;
083            }
084    
085            @Override
086            public boolean equals(Object o) {
087                if (this == o) return true;
088                if (o == null || getClass() != o.getClass()) return false;
089    
090                ExpressionValueArgument argument = (ExpressionValueArgument) o;
091    
092                if (expression != null ? !expression.equals(argument.expression) : argument.expression != null) return false;
093    
094                return true;
095            }
096    
097            @Override
098            public int hashCode() {
099                return expression != null ? expression.hashCode() : 0;
100            }
101        }
102    
103        private static class CallImpl implements Call {
104    
105            private final KtElement callElement;
106            private final Receiver explicitReceiver;
107            private final ASTNode callOperationNode;
108            private final KtExpression calleeExpression;
109            private final List<? extends ValueArgument> valueArguments;
110            private final Call.CallType callType;
111    
112            protected CallImpl(@NotNull KtElement callElement, @NotNull Receiver explicitReceiver, @Nullable ASTNode callOperationNode, @Nullable KtExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments) {
113                this(callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments, CallType.DEFAULT);
114            }
115    
116            protected CallImpl(@NotNull KtElement callElement, @Nullable Receiver explicitReceiver, @Nullable ASTNode callOperationNode,
117                    @Nullable KtExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments, @NotNull CallType callType) {
118                this.callElement = callElement;
119                this.explicitReceiver = explicitReceiver;
120                this.callOperationNode = callOperationNode;
121                this.calleeExpression = calleeExpression;
122                this.valueArguments = valueArguments;
123                this.callType = callType;
124            }
125    
126            @Override
127            public ASTNode getCallOperationNode() {
128                return callOperationNode;
129            }
130    
131            @Nullable
132            @Override
133            public Receiver getExplicitReceiver() {
134                return explicitReceiver;
135            }
136    
137            @Nullable
138            @Override
139            public ReceiverValue getDispatchReceiver() {
140                return null;
141            }
142    
143            @Override
144            public KtExpression getCalleeExpression() {
145                return calleeExpression;
146            }
147    
148            @NotNull
149            @Override
150            public List<? extends ValueArgument> getValueArguments() {
151                return valueArguments;
152            }
153    
154            @NotNull
155            @Override
156            public KtElement getCallElement() {
157                return callElement;
158            }
159    
160            @Override
161            public KtValueArgumentList getValueArgumentList() {
162                return null;
163            }
164    
165            @NotNull
166            @Override
167            public List<LambdaArgument> getFunctionLiteralArguments() {
168                return Collections.emptyList();
169            }
170            @NotNull
171            @Override
172            public List<KtTypeProjection> getTypeArguments() {
173                return Collections.emptyList();
174            }
175    
176            @Override
177            public KtTypeArgumentList getTypeArgumentList() {
178                return null;
179            }
180    
181            @Override
182            public String toString() {
183                return getCallElement().getText();
184            }
185    
186            @NotNull
187            @Override
188            public CallType getCallType() {
189                return callType;
190            }
191        }
192    
193        @NotNull
194        public static Call makeCallWithExpressions(@NotNull KtElement callElement, @Nullable Receiver explicitReceiver,
195                                                   @Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
196                                                   @NotNull List<KtExpression> argumentExpressions) {
197            return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, CallType.DEFAULT);
198        }
199    
200        @NotNull
201        public static Call makeCallWithExpressions(@NotNull KtElement callElement, @Nullable Receiver explicitReceiver,
202                                                   @Nullable ASTNode callOperationNode, @NotNull KtExpression calleeExpression,
203                                                   @NotNull List<KtExpression> argumentExpressions, @NotNull CallType callType) {
204            List<ValueArgument> arguments = new ArrayList<ValueArgument>(argumentExpressions.size());
205            for (KtExpression argumentExpression : argumentExpressions) {
206                arguments.add(makeValueArgument(argumentExpression, calleeExpression));
207            }
208            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
209        }
210    
211        @NotNull
212        public static Call makeCall(KtElement callElement, @Nullable Receiver explicitReceiver, @Nullable ASTNode callOperationNode, KtExpression calleeExpression, List<? extends ValueArgument> arguments) {
213            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, CallType.DEFAULT);
214        }
215    
216        @NotNull
217        public static Call makeCall(
218                KtElement callElement, @Nullable Receiver explicitReceiver, @Nullable ASTNode callOperationNode,
219                KtExpression calleeExpression, List<? extends ValueArgument> arguments, CallType callType) {
220            return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
221        }
222    
223        @NotNull
224        public static Call makeCall(@NotNull ReceiverValue leftAsReceiver, KtBinaryExpression expression) {
225            return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight()));
226        }
227    
228        @NotNull
229        public static Call makeCall(@NotNull ReceiverValue baseAsReceiver, KtUnaryExpression expression) {
230            return makeCall(expression, baseAsReceiver, null, expression.getOperationReference(), Collections.<ValueArgument>emptyList());
231        }
232    
233        @NotNull
234        public static Call makeArraySetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull KtArrayAccessExpression arrayAccessExpression,
235                @NotNull KtExpression rightHandSide, @NotNull CallType callType) {
236            List<KtExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
237            arguments.add(rightHandSide);
238            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments, callType);
239        }
240    
241        @NotNull
242        public static Call makeArrayGetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull KtArrayAccessExpression arrayAccessExpression,
243                @NotNull CallType callType) {
244            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions(), callType);
245        }
246    
247        @NotNull
248        public static ValueArgument makeValueArgument(@NotNull KtExpression expression) {
249            return makeValueArgument(expression, expression);
250        }
251    
252        @NotNull
253        public static ValueArgument makeValueArgument(@Nullable KtExpression expression, @NotNull KtElement reportErrorsOn) {
254            return new ExpressionValueArgument(expression, reportErrorsOn, false);
255        }
256    
257        @NotNull
258        public static ValueArgument makeExternalValueArgument(@NotNull KtExpression expression) {
259            return new ExpressionValueArgument(expression, expression, true);
260        }
261    
262        @NotNull
263        public static Call makePropertyCall(@Nullable Receiver explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull KtSimpleNameExpression nameExpression) {
264            return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.<KtExpression>emptyList());
265        }
266    
267    
268        @NotNull
269        public static Call makeConstructorCallWithoutTypeArguments(@NotNull KtCallElement callElement) {
270            return new DelegatingCall(makeCall(null, null, callElement)) {
271                @NotNull
272                @Override
273                public List<KtTypeProjection> getTypeArguments() {
274                    return Collections.emptyList();
275                }
276    
277                @Nullable
278                @Override
279                public KtTypeArgumentList getTypeArgumentList() {
280                    return null;
281                }
282            };
283        }
284    
285        @NotNull
286        public static Call makeConstructorCallForEnumEntryWithoutInitializer(@NotNull final KtSuperTypeCallEntry callElement) {
287            return new Call() {
288                @Nullable
289                @Override
290                public ASTNode getCallOperationNode() {
291                    return null;
292                }
293    
294                @Nullable
295                @Override
296                public Receiver getExplicitReceiver() {
297                    return null;
298                }
299    
300                @Nullable
301                @Override
302                public ReceiverValue getDispatchReceiver() {
303                    return null;
304                }
305    
306                @Nullable
307                @Override
308                public KtExpression getCalleeExpression() {
309                    return callElement.getCalleeExpression();
310                }
311    
312                @Nullable
313                @Override
314                public KtValueArgumentList getValueArgumentList() {
315                    return callElement.getValueArgumentList();
316                }
317    
318                @NotNull
319                @Override
320                public List<? extends ValueArgument> getValueArguments() {
321                    return callElement.getValueArguments();
322                }
323    
324                @NotNull
325                @Override
326                public List<? extends LambdaArgument> getFunctionLiteralArguments() {
327                    return Collections.emptyList();
328                }
329    
330                @NotNull
331                @Override
332                public List<KtTypeProjection> getTypeArguments() {
333                    return Collections.emptyList();
334                }
335    
336                @Nullable
337                @Override
338                public KtTypeArgumentList getTypeArgumentList() {
339                    return null;
340                }
341    
342                @NotNull
343                @Override
344                public KtElement getCallElement() {
345                    return callElement;
346                }
347    
348                @NotNull
349                @Override
350                public CallType getCallType() {
351                    return CallType.DEFAULT;
352                }
353            };
354        }
355    
356        @NotNull
357        public static Call makeCall(@Nullable final Receiver explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final KtCallElement callElement) {
358            return new Call() {
359                @Override
360                public ASTNode getCallOperationNode() {
361                    return callOperationNode;
362                }
363    
364                @Nullable
365                @Override
366                public Receiver getExplicitReceiver() {
367                    return explicitReceiver;
368                }
369    
370                @Nullable
371                @Override
372                public ReceiverValue getDispatchReceiver() {
373                    return null;
374                }
375    
376                @Override
377                @Nullable
378                public KtExpression getCalleeExpression() {
379                    return callElement.getCalleeExpression();
380                }
381    
382                @Override
383                @Nullable
384                public KtValueArgumentList getValueArgumentList() {
385                    return callElement.getValueArgumentList();
386                }
387    
388                @Override
389                @NotNull
390                public List<? extends ValueArgument> getValueArguments() {
391                    return callElement.getValueArguments();
392                }
393    
394                @Override
395                @NotNull
396                public List<? extends LambdaArgument> getFunctionLiteralArguments() {
397                    return callElement.getLambdaArguments();
398                }
399    
400                @Override
401                @NotNull
402                public List<KtTypeProjection> getTypeArguments() {
403                    return callElement.getTypeArguments();
404                }
405    
406                @Override
407                @Nullable
408                public KtTypeArgumentList getTypeArgumentList() {
409                    return callElement.getTypeArgumentList();
410                }
411    
412                @NotNull
413                @Override
414                public KtElement getCallElement() {
415                    return callElement;
416                }
417    
418                @Override
419                public String toString() {
420                    return DebugTextUtilKt.getDebugText(callElement);
421                }
422    
423                @NotNull
424                @Override
425                public CallType getCallType() {
426                    return CallType.DEFAULT;
427                }
428            };
429        }
430    
431        @NotNull
432        public static Call makeCall(@NotNull KtElement callElement, @NotNull ReceiverValue explicitReceiver) {
433            return new CallImpl(callElement, explicitReceiver, null, null, Collections.<ValueArgument>emptyList());
434        }
435    }