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;
018    
019    import com.intellij.lang.ASTNode;
020    import com.intellij.psi.PsiElement;
021    import com.intellij.psi.util.PsiTreeUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
026    import org.jetbrains.jet.lang.psi.*;
027    import org.jetbrains.jet.lang.resolve.BindingContext;
028    import org.jetbrains.jet.lang.resolve.BindingTrace;
029    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
030    import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
031    import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
032    import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
033    import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
034    import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache;
035    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
036    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
037    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
038    import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
039    import org.jetbrains.jet.lang.resolve.calls.util.FakeCallableDescriptorForObject;
040    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
041    import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant;
042    import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
043    import org.jetbrains.jet.lang.types.ErrorUtils;
044    import org.jetbrains.jet.lang.types.JetType;
045    import org.jetbrains.jet.lang.types.JetTypeInfo;
046    import org.jetbrains.jet.lang.types.TypeUtils;
047    import org.jetbrains.jet.lang.types.expressions.BasicExpressionTypingVisitor;
048    import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
049    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
050    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
051    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
052    import org.jetbrains.jet.lexer.JetTokens;
053    
054    import javax.inject.Inject;
055    import java.util.Collections;
056    
057    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
058    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
059    import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage.createQualifier;
060    import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage.resolveAsStandaloneExpression;
061    import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
062    
063    public class CallExpressionResolver {
064        @NotNull
065        private ExpressionTypingServices expressionTypingServices;
066    
067        @Inject
068        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
069            this.expressionTypingServices = expressionTypingServices;
070        }
071    
072        @Nullable
073        public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
074                @NotNull Call call, @NotNull JetExpression callExpression,
075                @NotNull ResolutionContext context, @NotNull CheckValueArgumentsMode checkArguments,
076                @NotNull boolean[] result
077        ) {
078            CallResolver callResolver = expressionTypingServices.getCallResolver();
079            OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall(
080                    BasicCallResolutionContext.create(context, call, checkArguments));
081            if (!results.isNothing()) {
082                checkSuper(call.getExplicitReceiver(), results, context.trace, callExpression);
083                result[0] = true;
084                return OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency);
085            }
086            result[0] = false;
087            return null;
088        }
089    
090        @Nullable
091        private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
092                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result
093        ) {
094            TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
095                    context, "trace to resolve as local variable or property", nameExpression);
096            CallResolver callResolver = expressionTypingServices.getCallResolver();
097            Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression);
098            BasicCallResolutionContext contextForVariable = BasicCallResolutionContext.create(
099                    context.replaceTraceAndCache(temporaryForVariable),
100                    call, CheckValueArgumentsMode.ENABLED);
101            OverloadResolutionResults<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty(contextForVariable);
102    
103            // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
104            boolean isLHSOfDot = JetPsiUtil.isLHSOfDot(nameExpression);
105            if (!resolutionResult.isNothing()) {
106                boolean isQualifier = isLHSOfDot && resolutionResult.isSingleResult()
107                                      && resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject;
108                if (!isQualifier) {
109                    result[0] = true;
110                    temporaryForVariable.commit();
111                    checkSuper(receiver, resolutionResult, context.trace, nameExpression);
112                    return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
113                }
114            }
115    
116            QualifierReceiver qualifier = createQualifier(nameExpression, receiver, context);
117            if (qualifier != null) {
118                result[0] = true;
119                if (!isLHSOfDot) {
120                    resolveAsStandaloneExpression(qualifier, context);
121                }
122                return null;
123            }
124            temporaryForVariable.commit();
125            result[0] = !resolutionResult.isNothing();
126            return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
127        }
128    
129        @NotNull
130        public JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
131                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
132        ) {
133            boolean[] result = new boolean[1];
134    
135            TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
136                    context, "trace to resolve as variable", nameExpression);
137            JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result);
138            if (result[0]) {
139                temporaryForVariable.commit();
140                return JetTypeInfo.create(type, context.dataFlowInfo);
141            }
142    
143            Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
144            TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
145                    context, "trace to resolve as function", nameExpression);
146            ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
147            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
148                    call, nameExpression, newContext, CheckValueArgumentsMode.ENABLED, result);
149            if (result[0]) {
150                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
151                temporaryForFunction.commit();
152                boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
153                context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
154                type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
155                return JetTypeInfo.create(type, context.dataFlowInfo);
156            }
157    
158            temporaryForVariable.commit();
159            return JetTypeInfo.create(null, context.dataFlowInfo);
160        }
161    
162        @NotNull
163        public JetTypeInfo getCallExpressionTypeInfo(
164                @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
165                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
166        ) {
167            JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
168            if (context.contextDependency == INDEPENDENT) {
169                DataFlowUtils.checkType(typeInfo, callExpression, context);
170            }
171            return typeInfo;
172        }
173    
174        @NotNull
175        public JetTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
176                @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
177                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
178        ) {
179            boolean[] result = new boolean[1];
180            Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
181    
182            TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
183                    context, "trace to resolve as function call", callExpression);
184            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
185                    call, callExpression, context.replaceTraceAndCache(temporaryForFunction),
186                    CheckValueArgumentsMode.ENABLED, result);
187            if (result[0]) {
188                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
189                temporaryForFunction.commit();
190                if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
191                    // there are only type arguments
192                    boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
193                    context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
194                }
195                if (functionDescriptor == null) {
196                    return JetTypeInfo.create(null, context.dataFlowInfo);
197                }
198                if (functionDescriptor instanceof ConstructorDescriptor && DescriptorUtils.isAnnotationClass(functionDescriptor.getContainingDeclaration())) {
199                    if (!canInstantiateAnnotationClass(callExpression)) {
200                        context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression));
201                    }
202                }
203    
204                JetType type = functionDescriptor.getReturnType();
205    
206                return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
207            }
208    
209            JetExpression calleeExpression = callExpression.getCalleeExpression();
210            if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
211                TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
212                        context, "trace to resolve as variable with 'invoke' call", callExpression);
213                JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode,
214                                               context.replaceTraceAndCache(temporaryForVariable), result);
215                if (result[0]) {
216                    temporaryForVariable.commit();
217                    context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
218                                                              type != null ? type : ErrorUtils.createErrorType("")));
219                    return JetTypeInfo.create(null, context.dataFlowInfo);
220                }
221            }
222            temporaryForFunction.commit();
223            return JetTypeInfo.create(null, context.dataFlowInfo);
224        }
225    
226        private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
227            PsiElement parent = expression.getParent();
228            if (parent instanceof JetValueArgument) {
229                return PsiTreeUtil.getParentOfType(parent, JetAnnotationEntry.class) != null;
230            }
231            else if (parent instanceof JetParameter) {
232                JetClass jetClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
233                if (jetClass != null) {
234                    return jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD);
235                }
236            }
237            return false;
238        }
239    
240        private static void checkSuper(
241                @NotNull ReceiverValue receiverValue,
242                @NotNull OverloadResolutionResults<?> results,
243                @NotNull BindingTrace trace,
244                @NotNull JetExpression expression
245        ) {
246            if (!results.isSingleResult()) return;
247            if (!(receiverValue instanceof ExpressionReceiver)) return;
248            JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
249            CallableDescriptor descriptor = results.getResultingDescriptor();
250            if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
251                if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
252                    trace.report(ABSTRACT_SUPER_CALL.on(expression));
253                }
254            }
255        }
256    
257        @NotNull
258        private JetTypeInfo getSelectorReturnTypeInfo(
259                @NotNull ReceiverValue receiver,
260                @Nullable ASTNode callOperationNode,
261                @Nullable JetExpression selectorExpression,
262                @NotNull ExpressionTypingContext context
263        ) {
264            if (selectorExpression instanceof JetCallExpression) {
265                return getCallExpressionTypeInfoWithoutFinalTypeCheck((JetCallExpression) selectorExpression, receiver,
266                                                                      callOperationNode, context);
267            }
268            else if (selectorExpression instanceof JetSimpleNameExpression) {
269                return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
270            }
271            else if (selectorExpression != null) {
272                context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
273            }
274            return JetTypeInfo.create(null, context.dataFlowInfo);
275        }
276    
277        @NotNull
278        public JetTypeInfo getQualifiedExpressionTypeInfo(
279                @NotNull JetQualifiedExpression expression, @NotNull ExpressionTypingContext context
280        ) {
281            // TODO : functions as values
282            JetExpression selectorExpression = expression.getSelectorExpression();
283            JetExpression receiverExpression = expression.getReceiverExpression();
284            ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
285            JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver);
286            JetType receiverType = receiverTypeInfo.getType();
287            QualifierReceiver qualifierReceiver = (QualifierReceiver) context.trace.get(BindingContext.QUALIFIER, receiverExpression);
288    
289            if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
290    
291            context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
292    
293            ReceiverValue receiver = qualifierReceiver == null ? new ExpressionReceiver(receiverExpression, receiverType) : qualifierReceiver;
294            JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
295                    receiver, expression.getOperationTokenNode(), selectorExpression, context);
296            JetType selectorReturnType = selectorReturnTypeInfo.getType();
297    
298            resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context);
299            checkNestedClassAccess(expression, context);
300    
301            //TODO move further
302            if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
303                if (selectorReturnType != null && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
304                    if (TypeUtils.isNullableType(receiverType)) {
305                        selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
306                    }
307                }
308            }
309    
310            // TODO : this is suspicious: remove this code?
311            if (selectorReturnType != null) {
312                context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
313            }
314    
315            CompileTimeConstant<?> value = ConstantExpressionEvaluator.OBJECT$.evaluate(expression, context.trace, context.expectedType);
316            if (value instanceof IntegerValueConstant && ((IntegerValueConstant) value).isPure()) {
317                return BasicExpressionTypingVisitor.createCompileTimeConstantTypeInfo(value, expression, context);
318            }
319    
320            JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
321            if (context.contextDependency == INDEPENDENT) {
322                DataFlowUtils.checkType(typeInfo, expression, context);
323            }
324            return typeInfo;
325        }
326    
327        private static void resolveDeferredReceiverInQualifiedExpression(
328                @Nullable QualifierReceiver qualifierReceiver,
329                @NotNull JetQualifiedExpression qualifiedExpression,
330                @NotNull ExpressionTypingContext context
331        ) {
332            if (qualifierReceiver == null) return;
333            JetExpression calleeExpression =
334                    JetPsiUtil.deparenthesize(CallUtilPackage.getCalleeExpressionIfAny(qualifiedExpression.getSelectorExpression()), false);
335            DeclarationDescriptor selectorDescriptor =
336                    calleeExpression instanceof JetReferenceExpression
337                    ? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null;
338            ReceiversPackage.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
339        }
340    
341        private static void checkNestedClassAccess(
342                @NotNull JetQualifiedExpression expression,
343                @NotNull ExpressionTypingContext context
344        ) {
345            JetExpression selectorExpression = expression.getSelectorExpression();
346            if (selectorExpression == null) return;
347    
348            // A.B - if B is a nested class accessed by outer class, 'A' and 'A.B' were marked as qualifiers
349            // a.B - if B is a nested class accessed by instance reference, 'a.B' was marked as a qualifier, but 'a' was not (it's an expression)
350    
351            Qualifier expressionQualifier = context.trace.get(BindingContext.QUALIFIER, expression);
352            Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression());
353    
354            if (receiverQualifier == null && expressionQualifier != null) {
355                assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
356                        "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier;
357                context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(selectorExpression, (ClassDescriptor)expressionQualifier.getClassifier()));
358            }
359        }
360    }