Move auxiliary methods for QualifierReceiver resolution to a separate file

(to be refactored later).
Get rid of duplicate type usage validation.
This commit is contained in:
Dmitry Petrov
2015-11-09 18:22:53 +03:00
parent 3556f9751e
commit eef8c7ae09
5 changed files with 142 additions and 110 deletions
@@ -0,0 +1,122 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.descriptorUtil.classObjectType
import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassObjectType
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
public fun resolveAsReceiverInQualifiedExpression(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?,
symbolUsageValidator: SymbolUsageValidator
) {
resolveAndRecordReferenceTarget(qualifier, context, selector, symbolUsageValidator)
if (qualifier is ClassifierQualifier) {
val classifier = qualifier.classifier
if (classifier is TypeParameterDescriptor) {
context.trace.report(Errors.TYPE_PARAMETER_ON_LHS_OF_DOT.on(qualifier.referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && classifier.hasClassObjectType) {
context.trace.recordType(qualifier.expression, classifier.classObjectType)
}
}
}
public fun resolveAsStandaloneExpression(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator
) {
resolveAndRecordReferenceTarget(qualifier, context, selector = null, symbolUsageValidator = symbolUsageValidator)
if (qualifier is ClassifierQualifier) {
val classifier = qualifier.classifier
if (classifier is TypeParameterDescriptor) {
context.trace.report(Errors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(qualifier.referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && !classifier.hasClassObjectType) {
context.trace.report(Errors.NO_COMPANION_OBJECT.on(qualifier.referenceExpression, classifier))
}
}
else if (qualifier is PackageQualifier) {
context.trace.report(Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND.on(qualifier.referenceExpression))
}
}
private fun resolveAndRecordReferenceTarget(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?,
symbolUsageValidator: SymbolUsageValidator
) {
// TODO get rid of QualifierReceiver::resultingDescriptor. REFERENCE_TARGET should be enough.
qualifier.resultingDescriptor = resolveReferenceTarget(qualifier, context, selector, symbolUsageValidator)
context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, qualifier.resultingDescriptor)
}
private fun resolveReferenceTarget(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?,
symbolUsageValidator: SymbolUsageValidator
): DeclarationDescriptor {
if (qualifier is ClassifierQualifier && qualifier.classifier is TypeParameterDescriptor) {
return qualifier.classifier
}
val selectorContainer = when (selector) {
is ConstructorDescriptor ->
selector.containingDeclaration.containingDeclaration
else ->
selector?.containingDeclaration
}
if (qualifier is PackageQualifier &&
(selectorContainer is PackageFragmentDescriptor || selectorContainer is PackageViewDescriptor) &&
DescriptorUtils.getFqName(qualifier.packageView) == DescriptorUtils.getFqName(selectorContainer)
) {
return qualifier.packageView
}
if (qualifier is ClassQualifier) {
if (selector is CallableDescriptor &&
(selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) &&
qualifier.classifier is ClassDescriptor &&
qualifier.classifier.hasClassObjectType
) {
val companionObjectDescriptor = qualifier.classifier.companionObjectDescriptor
if (companionObjectDescriptor != null) {
context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, qualifier.classifier)
symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, qualifier.referenceExpression)
return companionObjectDescriptor
}
}
}
return qualifier.descriptor
}
@@ -25,16 +25,15 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.CallExpressionElement import org.jetbrains.kotlin.resolve.calls.CallExpressionElement
import org.jetbrains.kotlin.resolve.descriptorUtil.classObjectType
import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassObjectType
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.createClassifierQualifier
import org.jetbrains.kotlin.resolve.scopes.utils.containsFunctionOrVariable import org.jetbrains.kotlin.resolve.scopes.utils.containsFunctionOrVariable
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
import org.jetbrains.kotlin.resolve.scopes.utils.findVariable
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
@@ -598,96 +597,6 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
} }
return Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, shouldBeVisibleFrom) return Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, shouldBeVisibleFrom)
} }
public fun resolveAsReceiverInQualifiedExpression(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?
) {
resolveAndRecordReferenceTarget(qualifier, context, selector)
if (qualifier is ClassifierQualifier) {
val classifier = qualifier.classifier
if (classifier is TypeParameterDescriptor) {
context.trace.report(Errors.TYPE_PARAMETER_ON_LHS_OF_DOT.on(qualifier.referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && classifier.hasClassObjectType) {
context.trace.recordType(qualifier.expression, classifier.classObjectType)
}
}
}
public fun resolveAsStandaloneExpression(qualifier: QualifierReceiver, context: ExpressionTypingContext) {
resolveAndRecordReferenceTarget(qualifier, context, selector = null)
if (qualifier is ClassifierQualifier) {
val classifier = qualifier.classifier
if (classifier is TypeParameterDescriptor) {
context.trace.report(Errors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(qualifier.referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && !classifier.hasClassObjectType) {
context.trace.report(Errors.NO_COMPANION_OBJECT.on(qualifier.referenceExpression, classifier))
}
}
else if (qualifier is PackageQualifier) {
context.trace.report(Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND.on(qualifier.referenceExpression))
}
}
// TODO refactor
private fun resolveAndRecordReferenceTarget(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?
) {
qualifier.resultingDescriptor = resolveReferenceTarget(qualifier, context, selector)
context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, qualifier.resultingDescriptor)
}
// TODO refactor
private fun resolveReferenceTarget(
qualifier: QualifierReceiver,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?
): DeclarationDescriptor {
if (qualifier is ClassifierQualifier && qualifier.classifier is TypeParameterDescriptor) {
return qualifier.classifier
}
val selectorContainer = when (selector) {
is ConstructorDescriptor ->
selector.containingDeclaration.containingDeclaration
else ->
selector?.containingDeclaration
}
if (qualifier is PackageQualifier &&
(selectorContainer is PackageFragmentDescriptor || selectorContainer is PackageViewDescriptor) &&
DescriptorUtils.getFqName(qualifier.packageView) == DescriptorUtils.getFqName(selectorContainer)
) {
return qualifier.packageView
}
if (qualifier is ClassQualifier) {
symbolUsageValidator.validateTypeUsage(qualifier.classifier, context.trace, qualifier.referenceExpression)
if (selector is CallableDescriptor &&
(selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) &&
qualifier.classifier is ClassDescriptor &&
qualifier.classifier.hasClassObjectType
) {
val companionObjectDescriptor = qualifier.classifier.companionObjectDescriptor
if (companionObjectDescriptor != null) {
context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, qualifier.classifier)
symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, qualifier.referenceExpression)
return companionObjectDescriptor
}
}
}
return qualifier.descriptor
}
} }
/* /*
@@ -25,10 +25,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
@@ -46,6 +43,7 @@ import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.scopes.receivers.*; import org.jetbrains.kotlin.resolve.scopes.receivers.*;
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
@@ -70,19 +68,22 @@ public class CallExpressionResolver {
@NotNull private final DataFlowAnalyzer dataFlowAnalyzer; @NotNull private final DataFlowAnalyzer dataFlowAnalyzer;
@NotNull private final KotlinBuiltIns builtIns; @NotNull private final KotlinBuiltIns builtIns;
@NotNull private final QualifiedExpressionResolver qualifiedExpressionResolver; @NotNull private final QualifiedExpressionResolver qualifiedExpressionResolver;
@NotNull private final SymbolUsageValidator symbolUsageValidator;
public CallExpressionResolver( public CallExpressionResolver(
@NotNull CallResolver callResolver, @NotNull CallResolver callResolver,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator, @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
@NotNull DataFlowAnalyzer dataFlowAnalyzer, @NotNull DataFlowAnalyzer dataFlowAnalyzer,
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
@NotNull QualifiedExpressionResolver qualifiedExpressionResolver @NotNull QualifiedExpressionResolver qualifiedExpressionResolver,
@NotNull SymbolUsageValidator symbolUsageValidator
) { ) {
this.callResolver = callResolver; this.callResolver = callResolver;
this.constantExpressionEvaluator = constantExpressionEvaluator; this.constantExpressionEvaluator = constantExpressionEvaluator;
this.dataFlowAnalyzer = dataFlowAnalyzer; this.dataFlowAnalyzer = dataFlowAnalyzer;
this.builtIns = builtIns; this.builtIns = builtIns;
this.qualifiedExpressionResolver = qualifiedExpressionResolver; this.qualifiedExpressionResolver = qualifiedExpressionResolver;
this.symbolUsageValidator = symbolUsageValidator;
} }
private ExpressionTypingServices expressionTypingServices; private ExpressionTypingServices expressionTypingServices;
@@ -95,7 +96,7 @@ public class CallExpressionResolver {
@Nullable @Nullable
public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction( public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
@NotNull Call call, @NotNull KtExpression callExpression, @NotNull Call call,
@NotNull ResolutionContext context, @NotNull CheckArgumentTypesMode checkArguments, @NotNull ResolutionContext context, @NotNull CheckArgumentTypesMode checkArguments,
@NotNull boolean[] result @NotNull boolean[] result
) { ) {
@@ -138,7 +139,7 @@ public class CallExpressionResolver {
if (qualifier != null) { if (qualifier != null) {
result[0] = true; result[0] = true;
if (!isLHSOfDot) { if (!isLHSOfDot) {
qualifiedExpressionResolver.resolveAsStandaloneExpression(qualifier, context); QualifiedExpressionResolveUtilKt.resolveAsStandaloneExpression(qualifier, context, symbolUsageValidator);
} }
return null; return null;
} }
@@ -179,7 +180,7 @@ public class CallExpressionResolver {
context, "trace to resolve as function", nameExpression); context, "trace to resolve as function", nameExpression);
ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction); ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction( ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
call, nameExpression, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result); call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
if (result[0]) { if (result[0]) {
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null; FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
temporaryForFunction.commit(); temporaryForFunction.commit();
@@ -220,7 +221,7 @@ public class CallExpressionResolver {
TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create( TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
context, "trace to resolve as function call", callExpression); context, "trace to resolve as function call", callExpression);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction( ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
call, callExpression, call,
// It's possible start of a call so we should reset safe call chain // It's possible start of a call so we should reset safe call chain
context.replaceTraceAndCache(temporaryForFunction).replaceInsideCallChain(false), context.replaceTraceAndCache(temporaryForFunction).replaceInsideCallChain(false),
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result); CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
@@ -425,7 +426,7 @@ public class CallExpressionResolver {
calleeExpression instanceof KtReferenceExpression calleeExpression instanceof KtReferenceExpression
? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null; ? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null;
qualifiedExpressionResolver.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor); QualifiedExpressionResolveUtilKt.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor, symbolUsageValidator);
} }
private static void checkNestedClassAccess( private static void checkNestedClassAccess(
@@ -12,7 +12,7 @@ class TopLevel {
} }
fun useNested() { fun useNested() {
val <!UNUSED_VARIABLE!>d<!> = TopLevel.<!DEPRECATION, DEPRECATION!>Nested<!>.use() val <!UNUSED_VARIABLE!>d<!> = TopLevel.<!DEPRECATION!>Nested<!>.use()
TopLevel.<!DEPRECATION, DEPRECATION!>Nested<!>.Nested2() TopLevel.<!DEPRECATION!>Nested<!>.Nested2()
TopLevel.<!DEPRECATION, DEPRECATION!>Nested<!>.<!UNRESOLVED_REFERENCE!>CompanionNested2<!>() TopLevel.<!DEPRECATION!>Nested<!>.<!UNRESOLVED_REFERENCE!>CompanionNested2<!>()
} }
@@ -15,13 +15,13 @@ fun first() {
} }
fun useObject() { fun useObject() {
<!DEPRECATION, DEPRECATION!>Obsolete<!>.use() <!DEPRECATION!>Obsolete<!>.use()
val <!UNUSED_VARIABLE!>x<!> = <!DEPRECATION!>Obsolete<!> val <!UNUSED_VARIABLE!>x<!> = <!DEPRECATION!>Obsolete<!>
} }
fun useCompanion() { fun useCompanion() {
val <!UNUSED_VARIABLE!>d<!> = <!DEPRECATION!>Another<!> val <!UNUSED_VARIABLE!>d<!> = <!DEPRECATION!>Another<!>
val <!UNUSED_VARIABLE!>x<!> = Another.<!DEPRECATION!>Companion<!> val <!UNUSED_VARIABLE!>x<!> = Another.<!DEPRECATION!>Companion<!>
Another.<!DEPRECATION, DEPRECATION!>Companion<!>.use() Another.<!DEPRECATION!>Companion<!>.use()
<!DEPRECATION!>Another<!>.use() <!DEPRECATION!>Another<!>.use()
} }