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
017package org.jetbrains.jet.lang.resolve.calls.util;
018
019import com.google.common.collect.Lists;
020import com.intellij.lang.ASTNode;
021import com.intellij.psi.PsiElement;
022import com.intellij.psi.impl.source.tree.LeafPsiElement;
023import org.jetbrains.annotations.NotNull;
024import org.jetbrains.annotations.Nullable;
025import org.jetbrains.jet.lang.psi.*;
026import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
027import org.jetbrains.jet.lang.psi.Call.CallType;
028
029import java.util.Collections;
030import java.util.List;
031
032public 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}