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.psi.*
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.scopes.ImportingScope
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.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.validation.SymbolUsageValidator
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)
}
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.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
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.evaluate.ConstantExpressionEvaluator;
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.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
@@ -70,19 +68,22 @@ public class CallExpressionResolver {
@NotNull private final DataFlowAnalyzer dataFlowAnalyzer;
@NotNull private final KotlinBuiltIns builtIns;
@NotNull private final QualifiedExpressionResolver qualifiedExpressionResolver;
@NotNull private final SymbolUsageValidator symbolUsageValidator;
public CallExpressionResolver(
@NotNull CallResolver callResolver,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
@NotNull DataFlowAnalyzer dataFlowAnalyzer,
@NotNull KotlinBuiltIns builtIns,
@NotNull QualifiedExpressionResolver qualifiedExpressionResolver
@NotNull QualifiedExpressionResolver qualifiedExpressionResolver,
@NotNull SymbolUsageValidator symbolUsageValidator
) {
this.callResolver = callResolver;
this.constantExpressionEvaluator = constantExpressionEvaluator;
this.dataFlowAnalyzer = dataFlowAnalyzer;
this.builtIns = builtIns;
this.qualifiedExpressionResolver = qualifiedExpressionResolver;
this.symbolUsageValidator = symbolUsageValidator;
}
private ExpressionTypingServices expressionTypingServices;
@@ -95,7 +96,7 @@ public class CallExpressionResolver {
@Nullable
public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
@NotNull Call call, @NotNull KtExpression callExpression,
@NotNull Call call,
@NotNull ResolutionContext context, @NotNull CheckArgumentTypesMode checkArguments,
@NotNull boolean[] result
) {
@@ -138,7 +139,7 @@ public class CallExpressionResolver {
if (qualifier != null) {
result[0] = true;
if (!isLHSOfDot) {
qualifiedExpressionResolver.resolveAsStandaloneExpression(qualifier, context);
QualifiedExpressionResolveUtilKt.resolveAsStandaloneExpression(qualifier, context, symbolUsageValidator);
}
return null;
}
@@ -179,7 +180,7 @@ public class CallExpressionResolver {
context, "trace to resolve as function", nameExpression);
ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
call, nameExpression, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
if (result[0]) {
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
temporaryForFunction.commit();
@@ -220,7 +221,7 @@ public class CallExpressionResolver {
TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
context, "trace to resolve as function call", callExpression);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
call, callExpression,
call,
// It's possible start of a call so we should reset safe call chain
context.replaceTraceAndCache(temporaryForFunction).replaceInsideCallChain(false),
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, result);
@@ -425,7 +426,7 @@ public class CallExpressionResolver {
calleeExpression instanceof KtReferenceExpression
? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null;
qualifiedExpressionResolver.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
QualifiedExpressionResolveUtilKt.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor, symbolUsageValidator);
}
private static void checkNestedClassAccess(
@@ -12,7 +12,7 @@ class TopLevel {
}
fun useNested() {
val <!UNUSED_VARIABLE!>d<!> = TopLevel.<!DEPRECATION, DEPRECATION!>Nested<!>.use()
TopLevel.<!DEPRECATION, DEPRECATION!>Nested<!>.Nested2()
TopLevel.<!DEPRECATION, DEPRECATION!>Nested<!>.<!UNRESOLVED_REFERENCE!>CompanionNested2<!>()
val <!UNUSED_VARIABLE!>d<!> = TopLevel.<!DEPRECATION!>Nested<!>.use()
TopLevel.<!DEPRECATION!>Nested<!>.Nested2()
TopLevel.<!DEPRECATION!>Nested<!>.<!UNRESOLVED_REFERENCE!>CompanionNested2<!>()
}
@@ -15,13 +15,13 @@ fun first() {
}
fun useObject() {
<!DEPRECATION, DEPRECATION!>Obsolete<!>.use()
<!DEPRECATION!>Obsolete<!>.use()
val <!UNUSED_VARIABLE!>x<!> = <!DEPRECATION!>Obsolete<!>
}
fun useCompanion() {
val <!UNUSED_VARIABLE!>d<!> = <!DEPRECATION!>Another<!>
val <!UNUSED_VARIABLE!>x<!> = Another.<!DEPRECATION!>Companion<!>
Another.<!DEPRECATION, DEPRECATION!>Companion<!>.use()
Another.<!DEPRECATION!>Companion<!>.use()
<!DEPRECATION!>Another<!>.use()
}