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 }