Move resolve* methods from Qualifier.kt to QualifiedExpressionResolver.

Further differentiate various qualifiers.
This commit is contained in:
Dmitry Petrov
2015-11-02 15:30:37 +03:00
parent 16dcc0b288
commit 5ff2ffbccc
7 changed files with 198 additions and 175 deletions
@@ -23,16 +23,16 @@ import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
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.ClassifierQualifier
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.receivers.*
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.check
@@ -464,6 +464,94 @@ 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 ClassQualifier && 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
}
}
/*
@@ -28,6 +28,7 @@ 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.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
@@ -45,7 +46,6 @@ 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;
@@ -66,24 +66,24 @@ import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class CallExpressionResolver {
private final CallResolver callResolver;
private final ConstantExpressionEvaluator constantExpressionEvaluator;
private final SymbolUsageValidator symbolUsageValidator;
private final DataFlowAnalyzer dataFlowAnalyzer;
@NotNull private final CallResolver callResolver;
@NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator;
@NotNull private final DataFlowAnalyzer dataFlowAnalyzer;
@NotNull private final KotlinBuiltIns builtIns;
@NotNull private final QualifiedExpressionResolver qualifiedExpressionResolver;
public CallExpressionResolver(
@NotNull CallResolver callResolver,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
@NotNull SymbolUsageValidator symbolUsageValidator,
@NotNull DataFlowAnalyzer dataFlowAnalyzer,
@NotNull KotlinBuiltIns builtIns
@NotNull KotlinBuiltIns builtIns,
@NotNull QualifiedExpressionResolver qualifiedExpressionResolver
) {
this.callResolver = callResolver;
this.constantExpressionEvaluator = constantExpressionEvaluator;
this.symbolUsageValidator = symbolUsageValidator;
this.dataFlowAnalyzer = dataFlowAnalyzer;
this.builtIns = builtIns;
this.qualifiedExpressionResolver = qualifiedExpressionResolver;
}
private ExpressionTypingServices expressionTypingServices;
@@ -139,7 +139,7 @@ public class CallExpressionResolver {
if (qualifier != null) {
result[0] = true;
if (!isLHSOfDot) {
QualifierKt.resolveAsStandaloneExpression(qualifier, context, symbolUsageValidator);
qualifiedExpressionResolver.resolveAsStandaloneExpression(qualifier, context);
}
return null;
}
@@ -211,7 +211,7 @@ public class CallExpressionResolver {
* Determines the result type and data flow information after the call.
*/
@NotNull
public KotlinTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
private KotlinTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
@NotNull KtCallExpression callExpression, @NotNull Receiver receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
) {
@@ -275,7 +275,7 @@ public class CallExpressionResolver {
KotlinType type = getVariableType((KtSimpleNameExpression) calleeExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable), result);
Qualifier qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression);
if (result[0] && (qualifier == null || qualifier.getPackageView() == null)) {
if (result[0] && (qualifier == null || !(qualifier instanceof PackageQualifier))) {
temporaryForVariable.commit();
context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
type != null ? type : ErrorUtils.createErrorType("")));
@@ -423,7 +423,8 @@ public class CallExpressionResolver {
DeclarationDescriptor selectorDescriptor =
calleeExpression instanceof KtReferenceExpression
? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null;
QualifierKt.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, symbolUsageValidator, selectorDescriptor);
qualifiedExpressionResolver.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
}
private static void checkNestedClassAccess(
@@ -440,10 +441,11 @@ public class CallExpressionResolver {
Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression());
if (receiverQualifier == null && expressionQualifier != null) {
assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
assert expressionQualifier instanceof ClassQualifier :
"Only class can (package cannot) be accessed by instance reference: " + expressionQualifier;
context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE
.on(selectorExpression, (ClassDescriptor) expressionQualifier.getClassifier()));
context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(
selectorExpression,
((ClassQualifier) expressionQualifier).getClassifier()));
}
}
}
@@ -37,11 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
@@ -70,23 +66,23 @@ public class TaskPrioritizer(
val result = ResolutionTaskHolder<D, F>(storageManager, context, PriorityProviderImpl<D>(context), tracing)
val taskPrioritizerContext = TaskPrioritizerContext(name, result, context, context.scope, callableDescriptorCollectors)
if (explicitReceiver is QualifierReceiver) {
val qualifierReceiver: QualifierReceiver = explicitReceiver
val receiverScope = LexicalScope.empty(qualifierReceiver.getNestedClassesAndPackageMembersScope().memberScopeAsImportingScope(),
qualifierReceiver.descriptor)
doComputeTasks(NO_RECEIVER, taskPrioritizerContext.replaceScope(receiverScope))
computeTasksForClassObjectReceiver(qualifierReceiver, taskPrioritizerContext)
}
else {
doComputeTasks(explicitReceiver, taskPrioritizerContext)
when (explicitReceiver) {
is QualifierReceiver -> {
val qualifierReceiver: QualifierReceiver = explicitReceiver
val receiverScope = qualifierReceiver.getNestedClassesAndPackageMembersScope().memberScopeAsImportingScope()
doComputeTasks(NO_RECEIVER, taskPrioritizerContext.replaceScope(receiverScope))
computeTasksForClassObjectReceiver(qualifierReceiver, taskPrioritizerContext)
}
is ReceiverValue -> {
doComputeTasks(explicitReceiver, taskPrioritizerContext)
// Temporary fix for code migration (unaryPlus()/unaryMinus())
val unaryConventionName = getUnaryPlusOrMinusOperatorFunctionName(context.call)
if (unaryConventionName != null) {
val deprecatedName = if (name == OperatorNameConventions.UNARY_PLUS)
OperatorNameConventions.PLUS
else
OperatorNameConventions.MINUS
// Temporary fix for code migration (unaryPlus()/unaryMinus())
val unaryConventionName = getUnaryPlusOrMinusOperatorFunctionName(context.call)
if (unaryConventionName != null) {
val deprecatedName = if (name == OperatorNameConventions.UNARY_PLUS)
OperatorNameConventions.PLUS
else
OperatorNameConventions.MINUS
val additionalContext = TaskPrioritizerContext(deprecatedName, result, context, context.scope, callableDescriptorCollectors)
doComputeTasks(explicitReceiver, additionalContext)
@@ -98,24 +94,26 @@ public class TaskPrioritizer(
}
private fun <D : CallableDescriptor, F : D> computeTasksForClassObjectReceiver(
qualifierReceiver: QualifierReceiver,
qualifier: Qualifier,
taskPrioritizerContext: TaskPrioritizerContext<D, F>
) {
val companionObject = qualifierReceiver.companionObjectReceiver ?: return
val classifierDescriptor = qualifierReceiver.classifier
doComputeTasks(companionObject, taskPrioritizerContext.filterCollectors {
when {
classifierDescriptor is ClassDescriptor && classifierDescriptor.getCompanionObjectDescriptor() != null -> {
// nested classes and objects should not be accessible via short reference to companion object
it !is ConstructorDescriptor && it !is FakeCallableDescriptorForObject
if (qualifier is ClassQualifier) {
val companionObject = qualifierReceiver.companionObjectReceiver ?: return
val classifierDescriptor = qualifierReceiver.classifier
doComputeTasks(companionObject, taskPrioritizerContext.filterCollectors {
when {
classifierDescriptor is ClassDescriptor && classifierDescriptor.getCompanionObjectDescriptor() != null -> {
// nested classes and objects should not be accessible via short reference to companion object
it !is ConstructorDescriptor && it !is FakeCallableDescriptorForObject
}
classifierDescriptor != null && DescriptorUtils.isEnumEntry(classifierDescriptor) -> {
// objects nested in enum should not be accessible via enum entries reference
it !is FakeCallableDescriptorForObject
}
else -> true
}
classifierDescriptor != null && DescriptorUtils.isEnumEntry(classifierDescriptor) -> {
// objects nested in enum should not be accessible via enum entries reference
it !is FakeCallableDescriptorForObject
}
else -> true
}
})
})
}
}
private fun <D : CallableDescriptor, F : D> doComputeTasks(receiver: ReceiverValue, c: TaskPrioritizerContext<D, F>) {
@@ -47,12 +47,10 @@ public interface Qualifier: Receiver {
public val expression: KtExpression
public val packageView: PackageViewDescriptor?
public val classifier: ClassifierDescriptor?
public val name: Name
get() = classifier?.getName() ?: packageView!!.getName()
get() = descriptor.name
public val descriptor: DeclarationDescriptor
// package, classifier or companion object descriptor
public val resultingDescriptor: DeclarationDescriptor
@@ -64,15 +62,11 @@ abstract class QualifierReceiver(
val referenceExpression: KtSimpleNameExpression
) : Qualifier {
override val expression: KtExpression = referenceExpression.getTopmostParentQualifiedExpressionForSelector() ?: referenceExpression
val descriptor: DeclarationDescriptor
get() = classifier ?: packageView ?: throw AssertionError("PackageView and classifier both are null")
override val expression: KtExpression
get() = referenceExpression.getTopmostParentQualifiedExpressionForSelector() ?: referenceExpression
override var resultingDescriptor: DeclarationDescriptor by Delegates.notNull()
abstract val companionObjectReceiver: ReceiverValue?
abstract fun getNestedClassesAndPackageMembersScope(): MemberScope
override fun exists() = true
@@ -80,10 +74,11 @@ abstract class QualifierReceiver(
class PackageQualifier(
referenceExpression: KtSimpleNameExpression,
override val packageView: PackageViewDescriptor
public val packageView: PackageViewDescriptor
) : QualifierReceiver(referenceExpression) {
override val classifier: ClassifierDescriptor? get() = null
override val descriptor: DeclarationDescriptor
get() = packageView
override val scope: MemberScope get() = packageView.memberScope
@@ -95,13 +90,28 @@ class PackageQualifier(
get() = null
}
class ClassifierQualifier(
referenceExpression: KtSimpleNameExpression,
override val classifier: ClassifierDescriptor,
override val companionObjectReceiver: ReceiverValue?
) : QualifierReceiver(referenceExpression) {
abstract class ClassifierQualifier(referenceExpression: KtSimpleNameExpression) : QualifierReceiver(referenceExpression) {
abstract val classifier: ClassifierDescriptor
override val packageView: PackageViewDescriptor? get() = null
override val descriptor: DeclarationDescriptor
get() = classifier
}
class ClassifierQualifierWithEmptyScope(
referenceExpression: KtSimpleNameExpression,
override val classifier: ClassifierDescriptor
) : ClassifierQualifier(referenceExpression) {
override fun getNestedClassesAndPackageMembersScope(): MemberScope = scope
override val scope: MemberScope = MemberScope.empty(classifier)
}
class ClassQualifier(
referenceExpression: KtSimpleNameExpression,
override val classifier: ClassDescriptor,
val companionObjectReceiver: ReceiverValue?
) : ClassifierQualifier(referenceExpression) {
override val scope: MemberScope get() {
if (classifier !is ClassDescriptor) {
@@ -140,21 +150,12 @@ class ClassifierQualifier(
return ChainedScope("Static scope for $name as class or object", *scopes.toTypedArray())
}
override fun toString() = "Classifier{$classifier}"
}
fun getClassObjectReceiver(): ReceiverValue =
classifier.classObjectType?.let { ExpressionReceiver(referenceExpression, it) } ?: ReceiverValue.NO_RECEIVER
fun createClassifierQualifier(
referenceExpression: KtSimpleNameExpression,
classifier: ClassifierDescriptor,
bindingContext: BindingContext
): ClassifierQualifier {
val companionObjectReceiver = (classifier as? ClassDescriptor)?.companionObjectType?.let {
ExpressionReceiver.create(referenceExpression, it, bindingContext)
}
return ClassifierQualifier(referenceExpression, classifier, companionObjectReceiver)
override fun toString() = "Class{$classifier}"
}
fun createQualifier(
expression: KtSimpleNameExpression,
receiver: Receiver,
@@ -163,7 +164,8 @@ fun createQualifier(
val receiverScope = when {
!receiver.exists() -> context.scope
receiver is QualifierReceiver -> receiver.scope.memberScopeAsImportingScope()
else -> receiver.getType().getMemberScope().memberScopeAsImportingScope()
receiver is ReceiverValue -> receiver.type.memberScope.memberScopeAsImportingScope()
else -> throw IllegalArgumentException("Unexpected receiver kind: $receiver")
}
val name = expression.getReferencedNameAsName()
@@ -175,7 +177,7 @@ fun createQualifier(
context.trace.recordScope(context.scope, expression)
val qualifier =
if (receiver is PackageQualifier)
if (receiver is PackageQualifier) {
if (packageViewDescriptor != null)
PackageQualifier(expression, packageViewDescriptor)
else
@@ -185,92 +187,19 @@ fun createQualifier(
createClassifierQualifier(expression, classifierDescriptor, context.trace.bindingContext)
else
PackageQualifier(expression, packageViewDescriptor!!)
}
context.trace.record(QUALIFIER, qualifier.expression, qualifier)
return qualifier
}
fun QualifierReceiver.resolveAsStandaloneExpression(
context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator
): KotlinType? {
val classifier = this.classifier
resolveAndRecordReferenceTarget(context, symbolUsageValidator, selector = null)
if (classifier is TypeParameterDescriptor) {
context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(referenceExpression, classifier))
fun createClassifierQualifier(
referenceExpression: KtSimpleNameExpression,
classifier: ClassifierDescriptor,
bindingContext: BindingContext
): ClassifierQualifier {
val companionObjectReceiver = (classifier as? ClassDescriptor)?.companionObjectType?.let {
ExpressionReceiver.create(referenceExpression, it, bindingContext)
}
else if (classifier is ClassDescriptor && !classifier.hasCompanionObject) {
context.trace.report(NO_COMPANION_OBJECT.on(referenceExpression, classifier))
}
else if (packageView != null) {
context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(referenceExpression))
}
return null
}
fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(
context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator,
selector: DeclarationDescriptor?
) {
val classifier = this.classifier
resolveAndRecordReferenceTarget(context, symbolUsageValidator, selector)
if (classifier is TypeParameterDescriptor) {
context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && classifier.hasCompanionObject) {
context.trace.recordType(expression, classifier.companionObjectType)
}
}
private fun QualifierReceiver.resolveAndRecordReferenceTarget(
context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator,
selector: DeclarationDescriptor?
) {
resultingDescriptor = resolveReferenceTarget(context, symbolUsageValidator, selector)
context.trace.record(REFERENCE_TARGET, referenceExpression, resultingDescriptor)
}
private fun QualifierReceiver.resolveReferenceTarget(
context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator,
selector: DeclarationDescriptor?
): DeclarationDescriptor {
val classifier = this.classifier
val packageView = this.packageView
if (classifier is TypeParameterDescriptor) {
return classifier
}
val selectorContainer = when {
selector is ConstructorDescriptor -> selector.getContainingDeclaration().getContainingDeclaration()
else -> selector?.getContainingDeclaration()
}
if (packageView != null && (selectorContainer is PackageFragmentDescriptor || selectorContainer is PackageViewDescriptor)
&& getFqName(packageView) == getFqName(selectorContainer)) {
return packageView
}
val isCallableWithReceiver = selector is CallableDescriptor &&
(selector.getDispatchReceiverParameter() != null || selector.getExtensionReceiverParameter() != null)
val declarationDescriptor = descriptor
if (declarationDescriptor is ClassifierDescriptor)
symbolUsageValidator.validateTypeUsage(declarationDescriptor, context.trace, referenceExpression)
if (isCallableWithReceiver && classifier is ClassDescriptor && classifier.hasCompanionObject) {
val companionObjectDescriptor = classifier.getCompanionObjectDescriptor()
if (companionObjectDescriptor != null) {
context.trace.record(SHORT_REFERENCE_TO_COMPANION_OBJECT, referenceExpression, classifier)
symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, referenceExpression)
return companionObjectDescriptor
}
}
return declarationDescriptor
}
return ClassQualifier(referenceExpression, classifier, companionObjectReceiver)
}
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier;
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier;
import org.jetbrains.kotlin.types.KotlinType;
@@ -78,8 +79,11 @@ public class CodeInsightUtils {
Qualifier qualifier = context.get(BindingContext.QUALIFIER, expression);
if (qualifier != null) {
ClassifierDescriptor classifier = qualifier.getClassifier();
if (!(classifier instanceof ClassDescriptor) || ((ClassDescriptor) classifier).getKind() != ClassKind.OBJECT) return null;
if (!(qualifier instanceof ClassQualifier)) return null;
ClassifierDescriptor classifier = ((ClassQualifier) qualifier).getClassifier();
if (!(classifier instanceof ClassDescriptor) || ((ClassDescriptor) classifier).getKind() != ClassKind.OBJECT) {
return null;
}
}
return expression;
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
@@ -110,7 +111,7 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
receiver is Qualifier -> {
val qualifierType = context.getType(receiver.expression)
if (qualifierType != null) return TypeInfo(qualifierType, Variance.IN_VARIANCE)
if (receiver !is ClassQualifier) return null
val classifier = receiver.classifier as? JavaClassDescriptor ?: return null
val javaClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classifier) as? PsiClass
if (javaClass == null || !javaClass.canRefactor()) return null
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.source.getPsi
@@ -180,7 +181,7 @@ private fun checkExternalUsages(
val resolvedCall = calleeExpr.getResolvedCall(context.resolutionFacade.analyze(calleeExpr)) ?: continue
val callElement = resolvedCall.call.callElement
val dispatchReceiver = resolvedCall.dispatchReceiver
if (!dispatchReceiver.exists() || dispatchReceiver is QualifierReceiver) continue
if (!dispatchReceiver.exists() || dispatchReceiver is Qualifier) continue
val receiverClassDescriptor = dispatchReceiver.type.constructor.declarationDescriptor as? ClassDescriptor ?: continue
if (!DescriptorUtils.isSubclass(receiverClassDescriptor, targetClassDescriptor)) {
conflicts.putValue(callElement, "Pushed member won't be available in '${callElement.text}'")