001    /*
002     * Copyright 2010-2013 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.jet.lang.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.jet.lang.psi.*;
025    import org.jetbrains.jet.lang.psi.Call.CallType;
026    import org.jetbrains.jet.lang.psi.debugText.DebugTextPackage;
027    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
028    
029    import java.util.Collections;
030    import java.util.List;
031    
032    public class CallMaker {
033    
034        private static class ExpressionValueArgument implements ValueArgument {
035    
036            private final JetExpression expression;
037    
038            private final JetElement reportErrorsOn;
039    
040            private final boolean isExternal;
041    
042            private ExpressionValueArgument(
043                    @Nullable JetExpression expression,
044                    @NotNull JetElement reportErrorsOn,
045                    boolean isExternal
046            ) {
047                this.expression = expression;
048                this.reportErrorsOn = expression == null ? reportErrorsOn : expression;
049                this.isExternal = isExternal;
050            }
051    
052            @Override
053            public boolean isExternal() {
054                return isExternal;
055            }
056    
057            @Override
058            public JetExpression getArgumentExpression() {
059                return expression;
060            }
061    
062            @Override
063            public JetValueArgumentName getArgumentName() {
064                return null;
065            }
066    
067            @Override
068            public boolean isNamed() {
069                return false;
070            }
071    
072            @NotNull
073            @Override
074            public JetElement asElement() {
075                return reportErrorsOn;
076            }
077    
078            @Override
079            public LeafPsiElement getSpreadElement() {
080                return null;
081            }
082    
083            @Override
084            public boolean equals(Object o) {
085                if (this == o) return true;
086                if (o == null || getClass() != o.getClass()) return false;
087    
088                ExpressionValueArgument argument = (ExpressionValueArgument) o;
089    
090                if (expression != null ? !expression.equals(argument.expression) : argument.expression != null) return false;
091    
092                return true;
093            }
094    
095            @Override
096            public int hashCode() {
097                return expression != null ? expression.hashCode() : 0;
098            }
099        }
100    
101        private static class CallImpl implements Call {
102    
103            private final JetElement callElement;
104            private final ReceiverValue explicitReceiver;
105            private final ASTNode callOperationNode;
106            private final JetExpression calleeExpression;
107            private final List<? extends ValueArgument> valueArguments;
108            private final Call.CallType callType;
109    
110            protected CallImpl(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, @Nullable JetExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments) {
111                this(callElement, explicitReceiver, callOperationNode, calleeExpression, valueArguments, CallType.DEFAULT);
112            }
113    
114            protected CallImpl(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode,
115                    @Nullable JetExpression calleeExpression, @NotNull List<? extends ValueArgument> valueArguments, @NotNull CallType callType) {
116                this.callElement = callElement;
117                this.explicitReceiver = explicitReceiver;
118                this.callOperationNode = callOperationNode;
119                this.calleeExpression = calleeExpression;
120                this.valueArguments = valueArguments;
121                this.callType = callType;
122            }
123    
124            @Override
125            public ASTNode getCallOperationNode() {
126                return callOperationNode;
127            }
128    
129            @NotNull
130            @Override
131            public ReceiverValue getExplicitReceiver() {
132                return explicitReceiver;
133            }
134    
135            @NotNull
136            @Override
137            public ReceiverValue getThisObject() {
138                return ReceiverValue.NO_RECEIVER;
139            }
140    
141            @Override
142            public JetExpression getCalleeExpression() {
143                return calleeExpression;
144            }
145    
146            @NotNull
147            @Override
148            public List<? extends ValueArgument> getValueArguments() {
149                return valueArguments;
150            }
151    
152            @NotNull
153            @Override
154            public JetElement getCallElement() {
155                return callElement;
156            }
157    
158            @Override
159            public JetValueArgumentList getValueArgumentList() {
160                return null;
161            }
162    
163            @NotNull
164            @Override
165            public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
166                return Collections.emptyList();
167            }
168            @NotNull
169            @Override
170            public List<JetTypeProjection> getTypeArguments() {
171                return Collections.emptyList();
172            }
173    
174            @Override
175            public JetTypeArgumentList getTypeArgumentList() {
176                return null;
177            }
178    
179            @Override
180            public String toString() {
181                return getCallElement().getText();
182            }
183    
184            @NotNull
185            @Override
186            public CallType getCallType() {
187                return callType;
188            }
189        }
190    
191        @NotNull
192        public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver,
193                                                   @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression,
194                                                   @NotNull List<JetExpression> argumentExpressions) {
195            return makeCallWithExpressions(callElement, explicitReceiver, callOperationNode, calleeExpression, argumentExpressions, CallType.DEFAULT);
196        }
197    
198        @NotNull
199        public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver,
200                                                   @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression,
201                                                   @NotNull List<JetExpression> argumentExpressions, @NotNull CallType callType) {
202            List<ValueArgument> arguments = Lists.newArrayList();
203            for (JetExpression argumentExpression : argumentExpressions) {
204                arguments.add(makeValueArgument(argumentExpression, calleeExpression));
205            }
206            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
207        }
208    
209        @NotNull
210        public static Call makeCall(JetElement callElement, ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, JetExpression calleeExpression, List<? extends ValueArgument> arguments) {
211            return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, CallType.DEFAULT);
212        }
213    
214        @NotNull
215        public static Call makeCall(JetElement callElement, ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode,
216                JetExpression calleeExpression, List<? extends ValueArgument> arguments, CallType callType) {
217            return new CallImpl(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments, callType);
218        }
219    
220        @NotNull
221        public static Call makeCall(@NotNull ReceiverValue leftAsReceiver, JetBinaryExpression expression) {
222            return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight()));
223        }
224    
225        @NotNull
226        public static Call makeCall(@NotNull ReceiverValue baseAsReceiver, JetUnaryExpression expression) {
227            return makeCall(expression, baseAsReceiver, null, expression.getOperationReference(), Collections.<ValueArgument>emptyList());
228        }
229    
230        @NotNull
231        public static Call makeArraySetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull JetArrayAccessExpression arrayAccessExpression,
232                @NotNull JetExpression rightHandSide, @NotNull CallType callType) {
233            List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
234            arguments.add(rightHandSide);
235            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments, callType);
236        }
237    
238        @NotNull
239        public static Call makeArrayGetCall(@NotNull ReceiverValue arrayAsReceiver, @NotNull JetArrayAccessExpression arrayAccessExpression,
240                @NotNull CallType callType) {
241            return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions(), callType);
242        }
243    
244        @NotNull
245        public static ValueArgument makeValueArgument(@NotNull JetExpression expression) {
246            return makeValueArgument(expression, expression);
247        }
248    
249        @NotNull
250        public static ValueArgument makeValueArgument(@Nullable JetExpression expression, @NotNull JetElement reportErrorsOn) {
251            return new ExpressionValueArgument(expression, reportErrorsOn, false);
252        }
253    
254        @NotNull
255        public static ValueArgument makeExternalValueArgument(@NotNull JetExpression expression) {
256            return new ExpressionValueArgument(expression, expression, true);
257        }
258    
259        @NotNull
260        public static Call makePropertyCall(@NotNull ReceiverValue explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) {
261            return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.<JetExpression>emptyList());
262        }
263    
264        @NotNull
265        public static Call makeCall(@NotNull final ReceiverValue explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final JetCallElement callElement) {
266            return new Call() {
267                @Override
268                public ASTNode getCallOperationNode() {
269                    return callOperationNode;
270                }
271    
272                @NotNull
273                @Override
274                public ReceiverValue getExplicitReceiver() {
275                    return explicitReceiver;
276                }
277    
278                @NotNull
279                @Override
280                public ReceiverValue getThisObject() {
281                    return ReceiverValue.NO_RECEIVER;
282                }
283    
284                @Override
285                @Nullable
286                public JetExpression getCalleeExpression() {
287                    return callElement.getCalleeExpression();
288                }
289    
290                @Override
291                @Nullable
292                public JetValueArgumentList getValueArgumentList() {
293                    return callElement.getValueArgumentList();
294                }
295    
296                @Override
297                @NotNull
298                public List<? extends ValueArgument> getValueArguments() {
299                    return callElement.getValueArguments();
300                }
301    
302                @Override
303                @NotNull
304                public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
305                    return callElement.getFunctionLiteralArguments();
306                }
307    
308                @Override
309                @NotNull
310                public List<JetTypeProjection> getTypeArguments() {
311                    return callElement.getTypeArguments();
312                }
313    
314                @Override
315                @Nullable
316                public JetTypeArgumentList getTypeArgumentList() {
317                    return callElement.getTypeArgumentList();
318                }
319    
320                @NotNull
321                @Override
322                public JetElement getCallElement() {
323                    return callElement;
324                }
325    
326                @Override
327                public String toString() {
328                    return DebugTextPackage.getDebugText(callElement);
329                }
330    
331                @NotNull
332                @Override
333                public CallType getCallType() {
334                    return CallType.DEFAULT;
335                }
336            };
337        }
338    
339        @NotNull
340        public static Call makeCall(@NotNull JetElement callElement, @NotNull ReceiverValue explicitReceiver) {
341            return new CallImpl(callElement, explicitReceiver, null, null, Collections.<ValueArgument>emptyList());
342        }
343    }