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.psi.codeFragmentUtil.CodeFragmentUtilPackage;
028    import org.jetbrains.jet.lang.resolve.*;
029    import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
030    import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
031    import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
032    import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache;
033    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
034    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
035    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
036    import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
037    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
038    import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant;
039    import org.jetbrains.jet.lang.resolve.name.Name;
040    import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
041    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
042    import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl;
043    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
044    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
045    import org.jetbrains.jet.lang.types.*;
046    import org.jetbrains.jet.lang.types.expressions.BasicExpressionTypingVisitor;
047    import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
048    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
049    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
050    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
051    import org.jetbrains.jet.lexer.JetTokens;
052    import org.jetbrains.jet.utils.Printer;
053    
054    import javax.inject.Inject;
055    import java.util.ArrayList;
056    import java.util.Collections;
057    import java.util.List;
058    
059    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
060    import static org.jetbrains.jet.lang.psi.JetPsiUtil.isLHSOfDot;
061    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
062    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
063    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
064    import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
065    import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
066    
067    public class CallExpressionResolver {
068        @NotNull
069        private ExpressionTypingServices expressionTypingServices;
070    
071        @Inject
072        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
073            this.expressionTypingServices = expressionTypingServices;
074        }
075    
076        @Nullable
077        private JetType lookupPackageOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) {
078            Name referencedName = expression.getReferencedNameAsName();
079            final ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
080            if (classifier != null) {
081                JetType classObjectType = classifier.getClassObjectType();
082                if (classObjectType != null) {
083                    context.trace.record(REFERENCE_TARGET, expression, classifier);
084                    JetType result = getExtendedClassObjectType(expression, classObjectType, classifier, context);
085                    checkClassObjectVisibility(classifier, expression, context);
086                    return DataFlowUtils.checkType(result, expression, context);
087                }
088            }
089            JetType[] result = new JetType[1];
090            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
091                    context.trace, "trace for package/class object lookup of name", referencedName);
092            if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
093                temporaryTrace.commit();
094                return DataFlowUtils.checkType(result[0], expression, context);
095            }
096            // To report NO_CLASS_OBJECT when no package found
097            if (classifier != null) {
098                if (classifier instanceof TypeParameterDescriptor) {
099                    if (isLHSOfDot(expression)) {
100                        context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, (TypeParameterDescriptor) classifier));
101                    }
102                    else {
103                        context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, (TypeParameterDescriptor) classifier));
104                    }
105                }
106                else if (!isLHSOfDot(expression)) {
107                    context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
108                }
109                context.trace.record(REFERENCE_TARGET, expression, classifier);
110                JetScope scopeForStaticMembersResolution =
111                        classifier instanceof ClassDescriptor
112                        ? getStaticNestedClassesScope((ClassDescriptor) classifier)
113                        : new JetScopeImpl() {
114                                @NotNull
115                                @Override
116                                public DeclarationDescriptor getContainingDeclaration() {
117                                    return classifier;
118                                }
119    
120                                @Override
121                                public String toString() {
122                                    return "Scope for the type parameter on the left hand side of dot";
123                                }
124    
125                                @Override
126                                public void printScopeStructure(@NotNull Printer p) {
127                                    p.println(toString(), " for ", classifier);
128                                }
129                        };
130                return new PackageType(referencedName, scopeForStaticMembersResolution, NO_RECEIVER);
131            }
132            temporaryTrace.commit();
133            return result[0];
134        }
135    
136        private static void checkClassObjectVisibility(
137                @NotNull ClassifierDescriptor classifier,
138                @NotNull JetSimpleNameExpression expression,
139                @NotNull ExpressionTypingContext context
140        ) {
141            if (!(classifier instanceof ClassDescriptor)) return;
142    
143            ClassDescriptor classObject = ((ClassDescriptor) classifier).getClassObjectDescriptor();
144            assert classObject != null : "This check should be done only for classes with class objects: " + classifier;
145            DeclarationDescriptor from = context.containingDeclaration;
146            if (!Visibilities.isVisible(classObject, from)) {
147                context.trace.report(INVISIBLE_MEMBER.on(expression, classObject, classObject.getVisibility(), from));
148            }
149        }
150    
151        @NotNull
152        private static JetType getExtendedClassObjectType(
153                @NotNull JetSimpleNameExpression expression,
154                @NotNull JetType classObjectType,
155                @NotNull ClassifierDescriptor classifier,
156                @NotNull ResolutionContext context
157        ) {
158            if (!isLHSOfDot(expression) || !(classifier instanceof ClassDescriptor)) {
159                return classObjectType;
160            }
161            ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
162    
163            if (classDescriptor.getKind() == ClassKind.ENUM_ENTRY) {
164                return classObjectType;
165            }
166    
167            List<JetScope> scopes = new ArrayList<JetScope>(3);
168    
169            scopes.add(classObjectType.getMemberScope());
170            scopes.add(getStaticNestedClassesScope(classDescriptor));
171    
172            Name referencedName = expression.getReferencedNameAsName();
173            PackageViewDescriptor packageView = context.scope.getPackage(referencedName);
174            if (packageView != null) {
175                //for enums loaded from java binaries
176                scopes.add(packageView.getMemberScope());
177            }
178    
179            JetScope scope = new ChainedScope(
180                    classifier, "Member scope for extended class object type " + classifier, scopes.toArray(new JetScope[scopes.size()])
181            );
182            return new PackageType(referencedName, scope, new ExpressionReceiver(expression, classObjectType));
183        }
184    
185        private boolean furtherNameLookup(
186                @NotNull JetSimpleNameExpression expression,
187                @NotNull JetType[] result,
188                @NotNull ResolutionContext context
189        ) {
190            PackageType packageType = lookupPackageType(expression, context);
191            if (packageType == null) {
192                return false;
193            }
194            if (isLHSOfDot(expression)) {
195                result[0] = packageType;
196                return true;
197            }
198            context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(expression));
199            result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName());
200            return false;
201        }
202    
203        @Nullable
204        private PackageType lookupPackageType(@NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) {
205            Name name = expression.getReferencedNameAsName();
206            PackageViewDescriptor packageView = context.scope.getPackage(name);
207            if (packageView == null) {
208                return null;
209            }
210            context.trace.record(REFERENCE_TARGET, expression, packageView);
211    
212            // Construct a PackageType with everything from the package and with nested classes of the corresponding class (if any)
213            JetScope scope;
214            ClassifierDescriptor classifier = context.scope.getClassifier(name);
215            if (classifier instanceof ClassDescriptor) {
216                scope = new ChainedScope(
217                        packageView, "Package type member scope for " + expression.getText(), packageView.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier)
218                );
219            }
220            else {
221                scope = packageView.getMemberScope();
222            }
223            return new PackageType(name, scope, NO_RECEIVER);
224        }
225    
226        @Nullable
227        public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
228                @NotNull Call call, @NotNull JetExpression callExpression,
229                @NotNull ResolutionContext context, @NotNull CheckValueArgumentsMode checkArguments,
230                @NotNull boolean[] result
231        ) {
232            CallResolver callResolver = expressionTypingServices.getCallResolver();
233            OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall(
234                    BasicCallResolutionContext.create(context, call, checkArguments));
235            if (!results.isNothing()) {
236                checkSuper(call.getExplicitReceiver(), results, context.trace, callExpression);
237                result[0] = true;
238                return OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency);
239            }
240            result[0] = false;
241            return null;
242        }
243    
244        @Nullable
245        private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
246                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result
247        ) {
248            TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
249                    context, "trace to resolve as local variable or property", nameExpression);
250            CallResolver callResolver = expressionTypingServices.getCallResolver();
251            Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression);
252            BasicCallResolutionContext contextForVariable = BasicCallResolutionContext.create(
253                    context.replaceTraceAndCache(temporaryForVariable),
254                    call, CheckValueArgumentsMode.ENABLED);
255            OverloadResolutionResults<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty(contextForVariable);
256            if (resolutionResult.isSuccess()) {
257                temporaryForVariable.commit();
258                checkSuper(receiver, resolutionResult, context.trace, nameExpression);
259                result[0] = true;
260                return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
261            }
262    
263            ExpressionTypingContext newContext = receiver.exists()
264                                                 ? context.replaceScope(receiver.getType().getMemberScope())
265                                                 : context;
266            TemporaryTraceAndCache temporaryForPackageOrClassObject = TemporaryTraceAndCache.create(
267                    context, "trace to resolve as package or class object", nameExpression);
268            JetType jetType = lookupPackageOrClassObject(nameExpression, newContext.replaceTraceAndCache(temporaryForPackageOrClassObject));
269            if (jetType != null) {
270                temporaryForPackageOrClassObject.commit();
271    
272                // Uncommitted changes in temp context
273                context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope);
274                if (context.dataFlowInfo.hasTypeInfoConstraints()) {
275                    context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo);
276                }
277                result[0] = true;
278                return jetType;
279            }
280            temporaryForVariable.commit();
281            result[0] = !resolutionResult.isNothing();
282            return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
283        }
284    
285        @NotNull
286        public JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
287                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
288        ) {
289            boolean[] result = new boolean[1];
290    
291            TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
292                    context, "trace to resolve as variable", nameExpression);
293            JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result);
294            if (result[0]) {
295                temporaryForVariable.commit();
296                if (type instanceof PackageType && !isLHSOfDot(nameExpression)) {
297                    type = null;
298                }
299                return JetTypeInfo.create(type, context.dataFlowInfo);
300            }
301    
302            Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
303            TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
304                    context, "trace to resolve as function", nameExpression);
305            ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
306            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
307                    call, nameExpression, newContext, CheckValueArgumentsMode.ENABLED, result);
308            if (result[0]) {
309                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
310                temporaryForFunction.commit();
311                boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
312                context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
313                type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
314                return JetTypeInfo.create(type, context.dataFlowInfo);
315            }
316    
317            temporaryForVariable.commit();
318            return JetTypeInfo.create(null, context.dataFlowInfo);
319        }
320    
321        @NotNull
322        public JetTypeInfo getCallExpressionTypeInfo(
323                @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
324                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
325        ) {
326            JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
327            if (context.contextDependency == INDEPENDENT) {
328                DataFlowUtils.checkType(typeInfo, callExpression, context);
329            }
330            return typeInfo;
331        }
332    
333        @NotNull
334        public JetTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
335                @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
336                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
337        ) {
338            boolean[] result = new boolean[1];
339            Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
340    
341            TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
342                    context, "trace to resolve as function call", callExpression);
343            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
344                    call, callExpression, context.replaceTraceAndCache(temporaryForFunction),
345                    CheckValueArgumentsMode.ENABLED, result);
346            if (result[0]) {
347                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
348                temporaryForFunction.commit();
349                if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
350                    // there are only type arguments
351                    boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
352                    context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
353                }
354                if (functionDescriptor == null) {
355                    return JetTypeInfo.create(null, context.dataFlowInfo);
356                }
357                if (functionDescriptor instanceof ConstructorDescriptor && DescriptorUtils.isAnnotationClass(functionDescriptor.getContainingDeclaration())) {
358                    if (!canInstantiateAnnotationClass(callExpression)) {
359                        context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression));
360                    }
361                }
362    
363                JetType type = functionDescriptor.getReturnType();
364    
365                return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
366            }
367    
368            JetExpression calleeExpression = callExpression.getCalleeExpression();
369            if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
370                TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
371                        context, "trace to resolve as variable with 'invoke' call", callExpression);
372                JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode,
373                                               context.replaceTraceAndCache(temporaryForVariable), result);
374                if (result[0]) {
375                    temporaryForVariable.commit();
376                    context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
377                                                              type != null ? type : ErrorUtils.createErrorType("")));
378                    return JetTypeInfo.create(null, context.dataFlowInfo);
379                }
380            }
381            temporaryForFunction.commit();
382            return JetTypeInfo.create(null, context.dataFlowInfo);
383        }
384    
385        private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
386            PsiElement parent = expression.getParent();
387            if (parent instanceof JetValueArgument) {
388                return PsiTreeUtil.getParentOfType(parent, JetAnnotationEntry.class) != null;
389            }
390            else if (parent instanceof JetParameter) {
391                JetClass jetClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
392                if (jetClass != null) {
393                    return jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD);
394                }
395            }
396            return false;
397        }
398    
399        private static void checkSuper(
400                @NotNull ReceiverValue receiverValue,
401                @NotNull OverloadResolutionResults<?> results,
402                @NotNull BindingTrace trace,
403                @NotNull JetExpression expression
404        ) {
405            if (!results.isSingleResult()) return;
406            if (!(receiverValue instanceof ExpressionReceiver)) return;
407            JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
408            CallableDescriptor descriptor = results.getResultingDescriptor();
409            if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
410                if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
411                    trace.report(ABSTRACT_SUPER_CALL.on(expression));
412                }
413            }
414        }
415    
416        @NotNull
417        private JetTypeInfo getSelectorReturnTypeInfo(
418                @NotNull ReceiverValue receiver,
419                @Nullable ASTNode callOperationNode,
420                @NotNull JetExpression selectorExpression,
421                @NotNull ExpressionTypingContext context
422        ) {
423            if (selectorExpression instanceof JetCallExpression) {
424                return getCallExpressionTypeInfoWithoutFinalTypeCheck((JetCallExpression) selectorExpression, receiver,
425                                                                      callOperationNode, context);
426            }
427            else if (selectorExpression instanceof JetSimpleNameExpression) {
428                return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
429            }
430            else {
431                context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
432            }
433            return JetTypeInfo.create(null, context.dataFlowInfo);
434        }
435    
436        @NotNull
437        public JetTypeInfo getQualifiedExpressionTypeInfo(
438                @NotNull JetQualifiedExpression expression, @NotNull ExpressionTypingContext context
439        ) {
440            // TODO : functions as values
441            JetExpression selectorExpression = expression.getSelectorExpression();
442            JetExpression receiverExpression = expression.getReceiverExpression();
443            ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
444            JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver);
445            JetType receiverType = receiverTypeInfo.getType();
446            if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
447            if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
448    
449            context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
450    
451            JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
452                    new ExpressionReceiver(receiverExpression, receiverType),
453                    expression.getOperationTokenNode(), selectorExpression, context);
454            JetType selectorReturnType = selectorReturnTypeInfo.getType();
455    
456            //TODO move further
457            if (!(receiverType instanceof PackageType) && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
458                if (selectorReturnType != null && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
459                    if (receiverType.isNullable()) {
460                        selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
461                    }
462                }
463            }
464    
465            // TODO : this is suspicious: remove this code?
466            if (selectorReturnType != null) {
467                context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
468            }
469    
470            CompileTimeConstant<?> value = ConstantExpressionEvaluator.object$.evaluate(expression, context.trace, context.expectedType);
471            if (value instanceof IntegerValueConstant && ((IntegerValueConstant) value).isPure()) {
472                return BasicExpressionTypingVisitor.createCompileTimeConstantTypeInfo(value, expression, context);
473            }
474    
475            JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
476            if (context.contextDependency == INDEPENDENT) {
477                DataFlowUtils.checkType(typeInfo, expression, context);
478            }
479            return typeInfo;
480        }
481    }