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.DebugTextPackage;
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 JetExpression expression;
038    
039            private final JetElement reportErrorsOn;
040    
041            private final boolean isExternal;
042    
043            private ExpressionValueArgument(
044                    @Nullable JetExpression expression,
045                    @NotNull JetElement 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 JetExpression 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 JetElement 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 JetElement callElement;
105            private final ReceiverValue explicitReceiver;
106            private final ASTNode callOperationNode;
107            private final JetExpression calleeExpression;
108            private final List<? extends ValueArgument> valueArguments;
109            private final Call.CallType callType;
110    
111            protected CallImpl(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, @Nullable JetExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments) {
112                this(callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments, CallType.DEFAULT);
113            }
114    
115            protected CallImpl(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode,
116                    @Nullable JetExpression 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 JetExpression 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 JetElement getCallElement() {
156                return callElement;
157            }
158    
159            @Override
160            public JetValueArgumentList 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<JetTypeProjection> getTypeArguments() {
172                return Collections.emptyList();
173            }
174    
175            @Override
176            public JetTypeArgumentList 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 JetElement callElement, @NotNull ReceiverValue explicitReceiver,
194                                                   @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression,
195                                                   @NotNull List<JetExpression> argumentExpressions) {
196            return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, CallType.DEFAULT);
197        }
198    
199        @NotNull
200        public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver,
201                                                   @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression,
202                                                   @NotNull List<JetExpression> argumentExpressions, @NotNull CallType callType) {
203            List<ValueArgument> arguments = new ArrayList<ValueArgument>(argumentExpressions.size());
204            for (JetExpression 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(JetElement callElement, ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, JetExpression calleeExpression, List<? extends ValueArgument> arguments) {
212            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, CallType.DEFAULT);
213        }
214    
215        @NotNull
216        public static Call makeCall(JetElement callElement, ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode,
217                JetExpression calleeExpression, List<? extends ValueArgument> arguments, CallType callType) {
218            return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
219        }
220    
221        @NotNull
222        public static Call makeCall(@NotNull ReceiverValue leftAsReceiver, JetBinaryExpression expression) {
223            return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight()));
224        }
225    
226        @NotNull
227        public static Call makeCall(@NotNull ReceiverValue baseAsReceiver, JetUnaryExpression expression) {
228            return makeCall(expression, baseAsReceiver, null, expression.getOperationReference(), Collections.<ValueArgument>emptyList());
229        }
230    
231        @NotNull
232        public static Call makeArraySetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull JetArrayAccessExpression arrayAccessExpression,
233                @NotNull JetExpression rightHandSide, @NotNull CallType callType) {
234            List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
235            arguments.add(rightHandSide);
236            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments, callType);
237        }
238    
239        @NotNull
240        public static Call makeArrayGetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull JetArrayAccessExpression arrayAccessExpression,
241                @NotNull CallType callType) {
242            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions(), callType);
243        }
244    
245        @NotNull
246        public static ValueArgument makeValueArgument(@NotNull JetExpression expression) {
247            return makeValueArgument(expression, expression);
248        }
249    
250        @NotNull
251        public static ValueArgument makeValueArgument(@Nullable JetExpression expression, @NotNull JetElement reportErrorsOn) {
252            return new ExpressionValueArgument(expression, reportErrorsOn, false);
253        }
254    
255        @NotNull
256        public static ValueArgument makeExternalValueArgument(@NotNull JetExpression expression) {
257            return new ExpressionValueArgument(expression, expression, true);
258        }
259    
260        @NotNull
261        public static Call makePropertyCall(@NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) {
262            return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.<JetExpression>emptyList());
263        }
264    
265        @NotNull
266        public static Call makeCall(@NotNull final ReceiverValue explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final JetCallElement callElement) {
267            return new Call() {
268                @Override
269                public ASTNode getCallOperationNode() {
270                    return callOperationNode;
271                }
272    
273                @NotNull
274                @Override
275                public ReceiverValue getExplicitReceiver() {
276                    return explicitReceiver;
277                }
278    
279                @NotNull
280                @Override
281                public ReceiverValue getDispatchReceiver() {
282                    return ReceiverValue.NO_RECEIVER;
283                }
284    
285                @Override
286                @Nullable
287                public JetExpression getCalleeExpression() {
288                    return callElement.getCalleeExpression();
289                }
290    
291                @Override
292                @Nullable
293                public JetValueArgumentList getValueArgumentList() {
294                    return callElement.getValueArgumentList();
295                }
296    
297                @Override
298                @NotNull
299                public List<? extends ValueArgument> getValueArguments() {
300                    return callElement.getValueArguments();
301                }
302    
303                @Override
304                @NotNull
305                public List<? extends FunctionLiteralArgument> getFunctionLiteralArguments() {
306                    return callElement.getFunctionLiteralArguments();
307                }
308    
309                @Override
310                @NotNull
311                public List<JetTypeProjection> getTypeArguments() {
312                    return callElement.getTypeArguments();
313                }
314    
315                @Override
316                @Nullable
317                public JetTypeArgumentList getTypeArgumentList() {
318                    return callElement.getTypeArgumentList();
319                }
320    
321                @NotNull
322                @Override
323                public JetElement getCallElement() {
324                    return callElement;
325                }
326    
327                @Override
328                public String toString() {
329                    return DebugTextPackage.getDebugText(callElement);
330                }
331    
332                @NotNull
333                @Override
334                public CallType getCallType() {
335                    return CallType.DEFAULT;
336                }
337            };
338        }
339    
340        @NotNull
341        public static Call makeCall(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver) {
342            return new CallImpl(callElement, explicitReceiver, null, null, Collections.<ValueArgument>emptyList());
343        }
344    }