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