diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt index 95c6a188ec5..904d3b0bc1b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt @@ -18,8 +18,8 @@ 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.descriptorUtil.classValueDescriptor +import org.jetbrains.kotlin.resolve.descriptorUtil.companionObjectType import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier @@ -94,19 +94,19 @@ private fun resolveQualifierReferenceTarget( // TODO make decisions about short reference to companion object somewhere else if (qualifier is ClassQualifier) { val classifier = qualifier.classifier - if (selector is CallableDescriptor && - (selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) && - classifier is ClassDescriptor && - classifier.hasClassObjectType - ) { - val companionObjectDescriptor = classifier.companionObjectDescriptor - if (companionObjectDescriptor != null) { - context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, companionObjectDescriptor) + val selectorIsCallable = selector is CallableDescriptor && + (selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) + val referenceTarget = classifier.classValueDescriptor + if (selectorIsCallable && referenceTarget != null) { + val classObjectType = classifier.companionObjectType!! + val classObjectDescriptor = DescriptorUtils.getClassDescriptorForType(classObjectType) + context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, referenceTarget) + context.trace.recordType(qualifier.expression, classObjectType) + if (classifier.companionObjectDescriptor != null) { context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, classifier) - context.trace.recordType(qualifier.expression, classifier.classObjectType) - symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, qualifier.referenceExpression) - return companionObjectDescriptor + symbolUsageValidator.validateTypeUsage(referenceTarget, context.trace, qualifier.referenceExpression) } + return classObjectDescriptor } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java index 57f42fd430c..594c57aba96 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java @@ -137,13 +137,6 @@ public class CallExpressionResolver { } } - //// Generate some diagnostics for qualifier in unexpected position - //DeclarationDescriptor qualifierDescriptor = - // QualifiedExpressionResolveUtilKt.getQualifierDescriptorOrNull(nameExpression, receiver, context); - //if (qualifierDescriptor != null) { - // QualifiedExpressionResolveUtilKt.checkQualifierAsStandaloneExpression(qualifierDescriptor, nameExpression, context); - //} - temporaryForVariable.commit(); result[0] = !resolutionResult.isNothing(); return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt index 2b0d1524d82..a0e1cd669a2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt @@ -169,6 +169,7 @@ private object VariableCollector : CallableDescriptorCollector { val result = SmartList() result.addIfNotNull(lexicalScope.findLocalVariable(name)) + // Although local objects are prohibited, we'll include objects declared in current scope so that their usages are still resolved. result.addIfNotNull(getContributedFakeDescriptorForObject(lexicalScope, name, location)) return result } @@ -186,7 +187,7 @@ private object VariableCollector : CallableDescriptorCollector ) { if (qualifier is ClassQualifier) { - val companionObject = qualifierReceiver.companionObjectReceiver ?: return - val classifierDescriptor = qualifierReceiver.classifier + val companionObject = qualifier.companionObjectReceiver ?: return + val classifierDescriptor = qualifier.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) -> { + DescriptorUtils.isEnumEntry(classifierDescriptor) -> { // objects nested in enum should not be accessible via enum entries reference it !is FakeCallableDescriptorForObject } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index 5dce7f2dd7c..38522119622 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.resolve.scopes.receivers import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression @@ -32,10 +31,6 @@ import org.jetbrains.kotlin.resolve.scopes.ChainedScope import org.jetbrains.kotlin.resolve.scopes.FilteringScope import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier -import org.jetbrains.kotlin.resolve.scopes.utils.findPackage -import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope -import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* @@ -78,9 +73,6 @@ class PackageQualifier( override fun getNestedClassesAndPackageMembersScope(): MemberScope = packageView.memberScope override fun toString() = "Package{$packageView}" - - override val companionObjectReceiver: ReceiverValue? - get() = null } abstract class ClassifierQualifier(referenceExpression: KtSimpleNameExpression) : QualifierReceiver(referenceExpression) { @@ -143,9 +135,6 @@ class ClassQualifier( return ChainedScope("Static scope for $name as class or object", *scopes.toTypedArray()) } - fun getClassObjectReceiver(): ReceiverValue = - classifier.classObjectType?.let { ExpressionReceiver(referenceExpression, it) } ?: ReceiverValue.NO_RECEIVER - override fun toString() = "Class{$classifier}" } @@ -157,5 +146,8 @@ fun createClassifierQualifier( val companionObjectReceiver = (classifier as? ClassDescriptor)?.companionObjectType?.let { ExpressionReceiver.create(referenceExpression, it, bindingContext) } - return ClassQualifier(referenceExpression, classifier, companionObjectReceiver) + return if (classifier is ClassDescriptor) + ClassQualifier(referenceExpression, classifier, companionObjectReceiver) + else + ClassifierQualifierWithEmptyScope(referenceExpression, classifier) } \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index b67c703c4ed..cb426c796a6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -73,21 +73,24 @@ public val ClassDescriptor.classId: ClassId public val ClassDescriptor.hasCompanionObject: Boolean get() = companionObjectType != null +public val ClassDescriptor.classValueDescriptor: ClassDescriptor? + get() = if (kind.isSingleton) this else companionObjectDescriptor + +public val ClassDescriptor.classValueTypeDescriptor: ClassDescriptor? + get() = when (kind) { + OBJECT -> this + ENUM_ENTRY -> { + // enum entry has the type of enum class + val container = this.containingDeclaration + assert(container is ClassDescriptor && container.getKind() == ENUM_CLASS) + container as ClassDescriptor + } + else -> companionObjectDescriptor + } + /** If a literal of this class can be used as a value, returns the type of this value */ public val ClassDescriptor.companionObjectType: KotlinType? - get() { - val correspondingDescriptor = when (this.getKind()) { - OBJECT -> this - // enum entry has the type of enum class - ENUM_ENTRY -> { - val container = this.getContainingDeclaration() - assert(container is ClassDescriptor && container.getKind() == ENUM_CLASS) - container as ClassDescriptor - } - else -> getCompanionObjectDescriptor() - } - return correspondingDescriptor?.getDefaultType() - } + get() = classValueTypeDescriptor?.getDefaultType() public val DeclarationDescriptorWithVisibility.isEffectivelyPublicApi: Boolean get() { diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index 0f417b177c7..5c86a54695e 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -28,9 +28,11 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager +import org.jetbrains.kotlin.resolve.descriptorUtil.companionObjectType import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.supertypesWithAny @@ -247,8 +249,13 @@ public fun CallTypeAndReceiver<*, *>.receiverTypes( } val receiverValues = if (receiverExpression != null) { - val expressionType = bindingContext.getType(receiverExpression) - expressionType?.let { listOf(ExpressionReceiver.create(receiverExpression, expressionType, bindingContext)) } ?: return emptyList() + val receiverType = + bindingContext.getType(receiverExpression) ?: + (bindingContext.get(BindingContext.QUALIFIER, receiverExpression) as? ClassQualifier)?.let { + it.classifier.companionObjectType + } ?: + return emptyList() + listOf(ExpressionReceiver.create(receiverExpression, receiverType, bindingContext)) } else { val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt index 4202de9a037..78507b5182b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt @@ -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.descriptorUtil.companionObjectType import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver @@ -111,11 +112,15 @@ sealed class CreateCallableFromCallActionFactory( 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 + val classifierType = receiver.classifier.companionObjectType + if (classifierType != null) return TypeInfo(classifierType, Variance.IN_VARIANCE) + + val javaClassifier = receiver.classifier as? JavaClassDescriptor ?: return null + val javaClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, javaClassifier) as? PsiClass if (javaClass == null || !javaClass.canRefactor()) return null - TypeInfo.StaticContextRequired(TypeInfo(classifier.defaultType, Variance.IN_VARIANCE)) + TypeInfo.StaticContextRequired(TypeInfo(javaClassifier.defaultType, Variance.IN_VARIANCE)) } receiver is ReceiverValue -> TypeInfo(receiver.type, Variance.IN_VARIANCE) else -> throw AssertionError("Unexpected receiver: $receiver")