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                Qualifier qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression);
216                if (result[0] && (qualifier == null || qualifier.getPackageView() == null)) {
217                    temporaryForVariable.commit();
218                    context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
219                                                              type != null ? type : ErrorUtils.createErrorType("")));
220                    return JetTypeInfo.create(null, context.dataFlowInfo);
221                }
222            }
223            temporaryForFunction.commit();
224            return JetTypeInfo.create(null, context.dataFlowInfo);
225        }
226    
227        private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
228            PsiElement parent = expression.getParent();
229            if (parent instanceof JetValueArgument) {
230                return PsiTreeUtil.getParentOfType(parent, JetAnnotationEntry.class) != null;
231            }
232            else if (parent instanceof JetParameter) {
233                JetClass jetClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
234                if (jetClass != null) {
235                    return jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD);
236                }
237            }
238            return false;
239        }
240    
241        private static void checkSuper(
242                @NotNull ReceiverValue receiverValue,
243                @NotNull OverloadResolutionResults<?> results,
244                @NotNull BindingTrace trace,
245                @NotNull JetExpression expression
246        ) {
247            if (!results.isSingleResult()) return;
248            if (!(receiverValue instanceof ExpressionReceiver)) return;
249            JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
250            CallableDescriptor descriptor = results.getResultingDescriptor();
251            if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
252                if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
253                    trace.report(ABSTRACT_SUPER_CALL.on(expression));
254                }
255            }
256        }
257    
258        @NotNull
259        private JetTypeInfo getSelectorReturnTypeInfo(
260                @NotNull ReceiverValue receiver,
261                @Nullable ASTNode callOperationNode,
262                @Nullable JetExpression selectorExpression,
263                @NotNull ExpressionTypingContext context
264        ) {
265            if (selectorExpression instanceof JetCallExpression) {
266                return getCallExpressionTypeInfoWithoutFinalTypeCheck((JetCallExpression) selectorExpression, receiver,
267                                                                      callOperationNode, context);
268            }
269            else if (selectorExpression instanceof JetSimpleNameExpression) {
270                return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
271            }
272            else if (selectorExpression != null) {
273                context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
274            }
275            return JetTypeInfo.create(null, context.dataFlowInfo);
276        }
277    
278        @NotNull
279        public JetTypeInfo getQualifiedExpressionTypeInfo(
280                @NotNull JetQualifiedExpression expression, @NotNull ExpressionTypingContext context
281        ) {
282            // TODO : functions as values
283            JetExpression selectorExpression = expression.getSelectorExpression();
284            JetExpression receiverExpression = expression.getReceiverExpression();
285            ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
286            JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver);
287            JetType receiverType = receiverTypeInfo.getType();
288            QualifierReceiver qualifierReceiver = (QualifierReceiver) context.trace.get(BindingContext.QUALIFIER, receiverExpression);
289    
290            if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
291    
292            context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
293    
294            ReceiverValue receiver = qualifierReceiver == null ? new ExpressionReceiver(receiverExpression, receiverType) : qualifierReceiver;
295            JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
296                    receiver, expression.getOperationTokenNode(), selectorExpression, context);
297            JetType selectorReturnType = selectorReturnTypeInfo.getType();
298    
299            resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context);
300            checkNestedClassAccess(expression, context);
301    
302            //TODO move further
303            if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
304                if (selectorReturnType != null && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
305                    if (TypeUtils.isNullableType(receiverType)) {
306                        selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
307                    }
308                }
309            }
310    
311            // TODO : this is suspicious: remove this code?
312            if (selectorReturnType != null) {
313                context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
314            }
315    
316            CompileTimeConstant<?> value = ConstantExpressionEvaluator.OBJECT$.evaluate(expression, context.trace, context.expectedType);
317            if (value instanceof IntegerValueConstant && ((IntegerValueConstant) value).isPure()) {
318                return BasicExpressionTypingVisitor.createCompileTimeConstantTypeInfo(value, expression, context);
319            }
320    
321            JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
322            if (context.contextDependency == INDEPENDENT) {
323                DataFlowUtils.checkType(typeInfo, expression, context);
324            }
325            return typeInfo;
326        }
327    
328        private static void resolveDeferredReceiverInQualifiedExpression(
329                @Nullable QualifierReceiver qualifierReceiver,
330                @NotNull JetQualifiedExpression qualifiedExpression,
331                @NotNull ExpressionTypingContext context
332        ) {
333            if (qualifierReceiver == null) return;
334            JetExpression calleeExpression =
335                    JetPsiUtil.deparenthesize(CallUtilPackage.getCalleeExpressionIfAny(qualifiedExpression.getSelectorExpression()), false);
336            DeclarationDescriptor selectorDescriptor =
337                    calleeExpression instanceof JetReferenceExpression
338                    ? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null;
339            ReceiversPackage.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
340        }
341    
342        private static void checkNestedClassAccess(
343                @NotNull JetQualifiedExpression expression,
344                @NotNull ExpressionTypingContext context
345        ) {
346            JetExpression selectorExpression = expression.getSelectorExpression();
347            if (selectorExpression == null) return;
348    
349            // A.B - if B is a nested class accessed by outer class, 'A' and 'A.B' were marked as qualifiers
350            // 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)
351    
352            Qualifier expressionQualifier = context.trace.get(BindingContext.QUALIFIER, expression);
353            Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression());
354    
355            if (receiverQualifier == null && expressionQualifier != null) {
356                assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
357                        "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier;
358                context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(selectorExpression, (ClassDescriptor)expressionQualifier.getClassifier()));
359            }
360        }
361    }