001    /*
002     * Copyright 2010-2015 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.kotlin.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.kotlin.builtins.KotlinBuiltIns;
025    import org.jetbrains.kotlin.descriptors.*;
026    import org.jetbrains.kotlin.lexer.KtTokens;
027    import org.jetbrains.kotlin.psi.*;
028    import org.jetbrains.kotlin.resolve.BindingContext;
029    import org.jetbrains.kotlin.resolve.BindingTrace;
030    import org.jetbrains.kotlin.resolve.DescriptorUtils;
031    import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
032    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
033    import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
034    import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
035    import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
036    import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
037    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
038    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
039    import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
040    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
041    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
042    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
043    import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
044    import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
045    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
046    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
047    import org.jetbrains.kotlin.resolve.scopes.receivers.*;
048    import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
049    import org.jetbrains.kotlin.types.ErrorUtils;
050    import org.jetbrains.kotlin.types.KotlinType;
051    import org.jetbrains.kotlin.types.TypeUtils;
052    import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer;
053    import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
054    import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
055    import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo;
056    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
057    
058    import javax.inject.Inject;
059    import java.util.Collections;
060    import java.util.Deque;
061    import java.util.List;
062    
063    import static org.jetbrains.kotlin.diagnostics.Errors.*;
064    import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
065    import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
066    
067    public class CallExpressionResolver {
068    
069        private final CallResolver callResolver;
070        private final ConstantExpressionEvaluator constantExpressionEvaluator;
071        private final SymbolUsageValidator symbolUsageValidator;
072        private final DataFlowAnalyzer dataFlowAnalyzer;
073        @NotNull private final KotlinBuiltIns builtIns;
074    
075        public CallExpressionResolver(
076                @NotNull CallResolver callResolver,
077                @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
078                @NotNull SymbolUsageValidator symbolUsageValidator,
079                @NotNull DataFlowAnalyzer dataFlowAnalyzer,
080                @NotNull KotlinBuiltIns builtIns
081        ) {
082            this.callResolver = callResolver;
083            this.constantExpressionEvaluator = constantExpressionEvaluator;
084            this.symbolUsageValidator = symbolUsageValidator;
085            this.dataFlowAnalyzer = dataFlowAnalyzer;
086            this.builtIns = builtIns;
087        }
088    
089        private ExpressionTypingServices expressionTypingServices;
090    
091        // component dependency cycle
092        @Inject
093        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
094            this.expressionTypingServices = expressionTypingServices;
095        }
096    
097        @Nullable
098        public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
099                @NotNull Call call, @NotNull KtExpression callExpression,
100                @NotNull ResolutionContext context, @NotNull CheckArgumentTypesMode checkArguments,
101                @NotNull boolean[] result
102        ) {
103            OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall(
104                    BasicCallResolutionContext.create(context, call, checkArguments));
105            if (!results.isNothing()) {
106                result[0] = true;
107                return OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency);
108            }
109            result[0] = false;
110            return null;
111        }
112    
113        @Nullable
114        private KotlinType getVariableType(
115                @NotNull KtSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
116                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result
117        ) {
118            TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
119                    context, "trace to resolve as local variable or property", nameExpression);
120            Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression);
121            BasicCallResolutionContext contextForVariable = BasicCallResolutionContext.create(
122                    context.replaceTraceAndCache(temporaryForVariable),
123                    call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS);
124            OverloadResolutionResults<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty(contextForVariable);
125    
126            // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
127            boolean isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression);
128            if (!resolutionResult.isNothing() && resolutionResult.getResultCode() != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER) {
129                boolean isQualifier = isLHSOfDot && resolutionResult.isSingleResult()
130                                      && resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject;
131                if (!isQualifier) {
132                    result[0] = true;
133                    temporaryForVariable.commit();
134                    return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
135                }
136            }
137    
138            QualifierReceiver qualifier = QualifierKt.createQualifier(nameExpression, receiver, context);
139            if (qualifier != null) {
140                result[0] = true;
141                if (!isLHSOfDot) {
142                    QualifierKt.resolveAsStandaloneExpression(qualifier, context, symbolUsageValidator);
143                }
144                return null;
145            }
146            temporaryForVariable.commit();
147            result[0] = !resolutionResult.isNothing();
148            return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
149        }
150    
151        @NotNull
152        public KotlinTypeInfo getSimpleNameExpressionTypeInfo(
153                @NotNull KtSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
154                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
155        ) {
156            boolean[] result = new boolean[1];
157    
158            TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
159                    context, "trace to resolve as variable", nameExpression);
160            KotlinType type =
161                    getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result);
162            // NB: we have duplicating code in ArgumentTypeResolver.
163            // It would be better to do it in getSelectorTypeInfo, but it breaks call expression analysis
164            // (all safe calls become unnecessary after it)
165            // QualifierReceiver is a thing like Collections. which has no type or value
166            if (receiver.exists() && !(receiver instanceof QualifierReceiver)) {
167                DataFlowValue receiverDataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context);
168                if (callOperationNode != null && callOperationNode.getElementType() == KtTokens.SAFE_ACCESS) {
169                    context = context.replaceDataFlowInfo(context.dataFlowInfo.disequate(receiverDataFlowValue, DataFlowValue.nullValue(builtIns)));
170                }
171            }
172    
173            if (result[0]) {
174                temporaryForVariable.commit();
175                return TypeInfoFactoryKt.createTypeInfo(type, context);
176            }
177    
178            Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
179            TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
180                    context, "trace to resolve as function", nameExpression);
181            ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
182            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
183                    call, nameExpression, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
184            if (result[0]) {
185                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
186                temporaryForFunction.commit();
187                boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
188                context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
189                type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
190                return TypeInfoFactoryKt.createTypeInfo(type, context);
191            }
192    
193            temporaryForVariable.commit();
194            return TypeInfoFactoryKt.noTypeInfo(context);
195        }
196    
197        @NotNull
198        public KotlinTypeInfo getCallExpressionTypeInfo(
199                @NotNull KtCallExpression callExpression, @NotNull ReceiverValue receiver,
200                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
201        ) {
202            KotlinTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
203            if (context.contextDependency == INDEPENDENT) {
204                dataFlowAnalyzer.checkType(typeInfo.getType(), callExpression, context);
205            }
206            return typeInfo;
207        }
208    
209        /**
210         * Visits a call expression and its arguments.
211         * Determines the result type and data flow information after the call.
212         */
213        @NotNull
214        public KotlinTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
215                @NotNull KtCallExpression callExpression, @NotNull ReceiverValue receiver,
216                @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
217        ) {
218            boolean[] result = new boolean[1];
219            Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
220    
221            TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
222                    context, "trace to resolve as function call", callExpression);
223            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
224                    call, callExpression,
225                    // It's possible start of a call so we should reset safe call chain
226                    context.replaceTraceAndCache(temporaryForFunction).replaceInsideCallChain(false),
227                    CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
228            if (result[0]) {
229                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
230                temporaryForFunction.commit();
231                if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
232                    // there are only type arguments
233                    boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
234                    context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
235                }
236                if (functionDescriptor == null) {
237                    return TypeInfoFactoryKt.noTypeInfo(context);
238                }
239                if (functionDescriptor instanceof ConstructorDescriptor) {
240                    DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
241                    if (DescriptorUtils.isAnnotationClass(containingDescriptor)
242                        && !canInstantiateAnnotationClass(callExpression, context.trace)) {
243                        context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression));
244                    }
245                    if (DescriptorUtils.isEnumClass(containingDescriptor)) {
246                        context.trace.report(ENUM_CLASS_CONSTRUCTOR_CALL.on(callExpression));
247                    }
248                    if (containingDescriptor instanceof ClassDescriptor
249                        && ((ClassDescriptor) containingDescriptor).getModality() == Modality.SEALED) {
250                        context.trace.report(SEALED_CLASS_CONSTRUCTOR_CALL.on(callExpression));
251                    }
252                }
253    
254                KotlinType type = functionDescriptor.getReturnType();
255                // Extracting jump out possible and jump point flow info from arguments, if any
256                List<? extends ValueArgument> arguments = callExpression.getValueArguments();
257                DataFlowInfo resultFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo();
258                DataFlowInfo jumpFlowInfo = resultFlowInfo;
259                boolean jumpOutPossible = false;
260                for (ValueArgument argument: arguments) {
261                    KotlinTypeInfo argTypeInfo = context.trace.get(BindingContext.EXPRESSION_TYPE_INFO, argument.getArgumentExpression());
262                    if (argTypeInfo != null && argTypeInfo.getJumpOutPossible()) {
263                        jumpOutPossible = true;
264                        jumpFlowInfo = argTypeInfo.getJumpFlowInfo();
265                        break;
266                    }
267                }
268                return TypeInfoFactoryKt.createTypeInfo(type, resultFlowInfo, jumpOutPossible, jumpFlowInfo);
269            }
270    
271            KtExpression calleeExpression = callExpression.getCalleeExpression();
272            if (calleeExpression instanceof KtSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
273                TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
274                        context, "trace to resolve as variable with 'invoke' call", callExpression);
275                KotlinType type = getVariableType((KtSimpleNameExpression) calleeExpression, receiver, callOperationNode,
276                                                  context.replaceTraceAndCache(temporaryForVariable), result);
277                Qualifier qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression);
278                if (result[0] && (qualifier == null || qualifier.getPackageView() == null)) {
279                    temporaryForVariable.commit();
280                    context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
281                                                              type != null ? type : ErrorUtils.createErrorType("")));
282                    return TypeInfoFactoryKt.noTypeInfo(context);
283                }
284            }
285            temporaryForFunction.commit();
286            return TypeInfoFactoryKt.noTypeInfo(context);
287        }
288    
289        private static boolean canInstantiateAnnotationClass(@NotNull KtCallExpression expression, @NotNull BindingTrace trace) {
290            //noinspection unchecked
291            PsiElement parent = PsiTreeUtil.getParentOfType(expression, KtValueArgument.class, KtParameter.class);
292            if (parent instanceof KtValueArgument) {
293                return PsiTreeUtil.getParentOfType(parent, KtAnnotationEntry.class) != null;
294            }
295            else if (parent instanceof KtParameter) {
296                KtClass ktClass = PsiTreeUtil.getParentOfType(parent, KtClass.class);
297                if (ktClass != null) {
298                    DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ktClass);
299                    return DescriptorUtils.isAnnotationClass(descriptor);
300                }
301            }
302            return false;
303        }
304    
305        @NotNull
306        private KotlinTypeInfo getSelectorReturnTypeInfo(
307                @NotNull ReceiverValue receiver,
308                @Nullable ASTNode callOperationNode,
309                @Nullable KtExpression selectorExpression,
310                @NotNull ExpressionTypingContext context
311        ) {
312            if (selectorExpression instanceof KtCallExpression) {
313                return getCallExpressionTypeInfoWithoutFinalTypeCheck((KtCallExpression) selectorExpression, receiver,
314                                                                      callOperationNode, context);
315            }
316            else if (selectorExpression instanceof KtSimpleNameExpression) {
317                return getSimpleNameExpressionTypeInfo((KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
318            }
319            else if (selectorExpression != null) {
320                context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
321            }
322            return TypeInfoFactoryKt.noTypeInfo(context);
323        }
324    
325        /**
326         * Visits a qualified expression like x.y or x?.z controlling data flow information changes.
327         *
328         * @return qualified expression type together with data flow information
329         */
330        @NotNull
331        public KotlinTypeInfo getQualifiedExpressionTypeInfo(
332                @NotNull KtQualifiedExpression expression, @NotNull ExpressionTypingContext context
333        ) {
334            ExpressionTypingContext currentContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
335            Deque<CallExpressionElement> elementChain = CallExpressionUnrollerKt.unroll(expression);
336    
337            KotlinTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(elementChain.getFirst().getReceiver(), currentContext);
338            KotlinType receiverType = receiverTypeInfo.getType();
339            DataFlowInfo receiverDataFlowInfo = receiverTypeInfo.getDataFlowInfo();
340            KotlinTypeInfo resultTypeInfo = receiverTypeInfo;
341    
342            boolean unconditional = true;
343            DataFlowInfo unconditionalDataFlowInfo = receiverDataFlowInfo;
344    
345            for (CallExpressionElement element : elementChain) {
346                if (receiverType == null) {
347                    receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
348                }
349                QualifierReceiver qualifierReceiver = (QualifierReceiver) context.trace.get(BindingContext.QUALIFIER, element.getReceiver());
350    
351                ReceiverValue receiver = qualifierReceiver == null ? new ExpressionReceiver(element.getReceiver(), receiverType) : qualifierReceiver;
352    
353                boolean lastStage = element.getQualified() == expression;
354                assert lastStage == (element == elementChain.getLast());
355                // Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage
356                // But receiver data flow info changes should be always applied, while we are inside call chain
357                ExpressionTypingContext baseContext = lastStage ? context : currentContext;
358                currentContext = baseContext.replaceDataFlowInfo(receiverDataFlowInfo);
359    
360                KtExpression selectorExpression = element.getSelector();
361                KotlinTypeInfo selectorReturnTypeInfo =
362                        getSelectorReturnTypeInfo(receiver, element.getNode(), selectorExpression, currentContext);
363                KotlinType selectorReturnType = selectorReturnTypeInfo.getType();
364    
365                resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, element.getQualified(), currentContext);
366                checkNestedClassAccess(element.getQualified(), currentContext);
367    
368                boolean safeCall = element.getSafe();
369                if (safeCall && selectorReturnType != null && TypeUtils.isNullableType(receiverType)) {
370                    selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
371                    selectorReturnTypeInfo = selectorReturnTypeInfo.replaceType(selectorReturnType);
372                }
373    
374                // TODO : this is suspicious: remove this code?
375                if (selectorExpression != null && selectorReturnType != null) {
376                    currentContext.trace.recordType(selectorExpression, selectorReturnType);
377                }
378                resultTypeInfo = selectorReturnTypeInfo;
379                CompileTimeConstant<?> value = constantExpressionEvaluator.evaluateExpression(element.getQualified(), currentContext.trace, currentContext.expectedType);
380                if (value != null && value.isPure()) {
381                    resultTypeInfo =  dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, element.getQualified(), currentContext);
382                    if (lastStage) return resultTypeInfo;
383                }
384                if (currentContext.contextDependency == INDEPENDENT) {
385                    dataFlowAnalyzer.checkType(resultTypeInfo.getType(), element.getQualified(), currentContext);
386                }
387                // For the next stage, if any, current stage selector is the receiver!
388                receiverTypeInfo = selectorReturnTypeInfo;
389                receiverType = selectorReturnType;
390                receiverDataFlowInfo = receiverTypeInfo.getDataFlowInfo();
391                // if we have only dots and not ?. move unconditional data flow info further
392                if (safeCall) {
393                    unconditional = false;
394                }
395                else if (unconditional) {
396                    unconditionalDataFlowInfo = receiverDataFlowInfo;
397                }
398                //noinspection ConstantConditions
399                if (!lastStage && !currentContext.trace.get(BindingContext.PROCESSED, element.getQualified())) {
400                    // Store type information (to prevent problems in call completer)
401                    currentContext.trace.record(BindingContext.PROCESSED, element.getQualified());
402                    currentContext.trace.record(BindingContext.EXPRESSION_TYPE_INFO, element.getQualified(),
403                                                resultTypeInfo.replaceDataFlowInfo(unconditionalDataFlowInfo));
404                    // save scope before analyze and fix debugger: see CodeFragmentAnalyzer.correctContextForExpression
405                    BindingContextUtilsKt.recordScope(currentContext.trace, currentContext.scope, element.getQualified());
406                    BindingContextUtilsKt.recordDataFlowInfo(currentContext.replaceDataFlowInfo(unconditionalDataFlowInfo), element.getQualified());
407                }
408            }
409            // if we are at last stage, we should just take result type info and set unconditional data flow info
410            return resultTypeInfo.replaceDataFlowInfo(unconditionalDataFlowInfo);
411        }
412    
413        private void resolveDeferredReceiverInQualifiedExpression(
414                @Nullable QualifierReceiver qualifierReceiver,
415                @NotNull KtQualifiedExpression qualifiedExpression,
416                @NotNull ExpressionTypingContext context
417        ) {
418            if (qualifierReceiver == null) return;
419            KtExpression calleeExpression =
420                    KtPsiUtil.deparenthesize(CallUtilKt.getCalleeExpressionIfAny(qualifiedExpression.getSelectorExpression()));
421            DeclarationDescriptor selectorDescriptor =
422                    calleeExpression instanceof KtReferenceExpression
423                    ? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null;
424            QualifierKt.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, symbolUsageValidator, selectorDescriptor);
425        }
426    
427        private static void checkNestedClassAccess(
428                @NotNull KtQualifiedExpression expression,
429                @NotNull ExpressionTypingContext context
430        ) {
431            KtExpression selectorExpression = expression.getSelectorExpression();
432            if (selectorExpression == null) return;
433    
434            // A.B - if B is a nested class accessed by outer class, 'A' and 'A.B' were marked as qualifiers
435            // 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)
436    
437            Qualifier expressionQualifier = context.trace.get(BindingContext.QUALIFIER, expression);
438            Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression());
439    
440            if (receiverQualifier == null && expressionQualifier != null) {
441                assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
442                        "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier;
443                context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE
444                                             .on(selectorExpression, (ClassDescriptor) expressionQualifier.getClassifier()));
445            }
446        }
447    }