diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 07bb0a1794d..9da3185ee9d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -34,7 +34,7 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.Qualifier; import org.jetbrains.jet.lang.types.DeferredType; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.CaptureKind; @@ -85,7 +85,10 @@ public interface BindingContext { WritableSlice EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice(DO_NOTHING); WritableSlice DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); - WritableSlice QUALIFIER_RECEIVER = new BasicWritableSlice(DO_NOTHING); + /** + * A qualifier corresponds to a receiver expression (if any). For 'A.B' qualifier is recorded for 'A'. + */ + WritableSlice QUALIFIER = new BasicWritableSlice(DO_NOTHING); WritableSlice REFERENCE_TARGET = new BasicWritableSlice(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java index ba9e4d38431..623cc376f12 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -39,10 +39,7 @@ import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.calls.util.FakeCallableDescriptorForObject; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage; +import org.jetbrains.jet.lang.resolve.scopes.receivers.*; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetTypeInfo; @@ -115,11 +112,11 @@ public class CallExpressionResolver { } } - QualifierReceiver qualifierReceiver = createQualifierReceiver(nameExpression, receiver, context); - if (qualifierReceiver != null) { + QualifierReceiver qualifier = createQualifier(nameExpression, receiver, context); + if (qualifier != null) { result[0] = true; if (!isLHSOfDot) { - resolveAsStandaloneExpression(qualifierReceiver, context); + resolveAsStandaloneExpression(qualifier, context); } return null; } @@ -286,7 +283,7 @@ public class CallExpressionResolver { ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver); JetType receiverType = receiverTypeInfo.getType(); - QualifierReceiver qualifierReceiver = context.trace.get(BindingContext.QUALIFIER_RECEIVER, receiverExpression); + QualifierReceiver qualifierReceiver = (QualifierReceiver) context.trace.get(BindingContext.QUALIFIER, receiverExpression); if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText()); @@ -350,8 +347,8 @@ public class CallExpressionResolver { // A.B - if B is a nested class accessed by outer class, 'A' and 'A.B' were marked as qualifiers // 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) - QualifierReceiver expressionQualifier = context.trace.get(BindingContext.QUALIFIER_RECEIVER, expression); - QualifierReceiver receiverQualifier = context.trace.get(BindingContext.QUALIFIER_RECEIVER, expression.getReceiverExpression()); + Qualifier expressionQualifier = context.trace.get(BindingContext.QUALIFIER, expression); + Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression()); if (receiverQualifier == null && expressionQualifier != null) { assert expressionQualifier.getClassifier() instanceof ClassDescriptor : diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/QualifierReceiver.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/Qualifier.kt similarity index 76% rename from compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/QualifierReceiver.kt rename to compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/Qualifier.kt index 869c0b51243..d018e26df30 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/QualifierReceiver.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/Qualifier.kt @@ -38,27 +38,47 @@ import org.jetbrains.jet.lang.descriptors.impl.PackageFragmentDescriptorImpl import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext import org.jetbrains.jet.lang.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector import org.jetbrains.jet.lang.resolve.descriptorUtil.getClassObjectReferenceTarget +import org.jetbrains.jet.lang.psi.JetExpression +import kotlin.properties.Delegates -public class QualifierReceiver( - val expression: JetSimpleNameExpression, - val packageView: PackageViewDescriptor?, - val classifier: ClassifierDescriptor? -) : ReceiverValue { +public trait Qualifier { + + val expression: JetExpression + + val packageView: PackageViewDescriptor? + + val classifier: ClassifierDescriptor? val name: Name get() = classifier?.getName() ?: packageView!!.getName() - fun getClassObjectReceiver(): ReceiverValue = - classifier?.getClassObjectType()?.let { ExpressionReceiver(expression, it) } ?: ReceiverValue.NO_RECEIVER + // package, classifier or class object descriptor + val resultingDescriptor: DeclarationDescriptor + + val scope: JetScope +} + +class QualifierReceiver ( + val referenceExpression: JetSimpleNameExpression, + override val packageView: PackageViewDescriptor?, + override val classifier: ClassifierDescriptor? +) : Qualifier, ReceiverValue { + + override val expression: JetExpression = referenceExpression.getTopmostParentQualifiedExpressionForSelector() ?: referenceExpression val descriptor: DeclarationDescriptor get() = classifier ?: packageView ?: throw AssertionError("PackageView and classifier both are null") - fun getScope(): JetScope { + override var resultingDescriptor: DeclarationDescriptor by Delegates.notNull() + + override val scope: JetScope get() { val scopes = listOf(classifier?.getClassObjectType()?.getMemberScope(), getNestedClassesAndPackageMembersScope()).filterNotNull().copyToArray() return ChainedScope(descriptor, "Member scope for " + name + " as package or class or object", *scopes as Array) } + fun getClassObjectReceiver(): ReceiverValue = + classifier?.getClassObjectType()?.let { ExpressionReceiver(referenceExpression, it) } ?: ReceiverValue.NO_RECEIVER + fun getNestedClassesAndPackageMembersScope(): JetScope { val scopes = ArrayList(3) @@ -84,14 +104,14 @@ public class QualifierReceiver( override fun toString() = "Package{$packageView} OR Class{$classifier}" } -fun createQualifierReceiver( +fun createQualifier( expression: JetSimpleNameExpression, receiver: ReceiverValue, context: ExpressionTypingContext ): QualifierReceiver? { val receiverScope = when { !receiver.exists() -> context.scope - receiver is QualifierReceiver -> receiver.getScope() + receiver is QualifierReceiver -> receiver.scope else -> receiver.getType().getMemberScope() } @@ -106,36 +126,41 @@ fun createQualifierReceiver( context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, expression, context.dataFlowInfo) } - val qualifierReceiver = QualifierReceiver(expression, packageViewDescriptor, classifierDescriptor) - context.trace.record(QUALIFIER_RECEIVER, expression.getTopmostParentQualifiedExpressionForSelector() ?: expression, qualifierReceiver) - return qualifierReceiver + val qualifier = QualifierReceiver(expression, packageViewDescriptor, classifierDescriptor) + context.trace.record(QUALIFIER, qualifier.expression, qualifier) + return qualifier } private fun QualifierReceiver.resolveAsStandaloneExpression(context: ExpressionTypingContext): JetType? { - context.trace.record(REFERENCE_TARGET, expression, resolveReferenceTarget(selector = null)) + resolveAndRecordReferenceTarget(context, selector = null) if (classifier is TypeParameterDescriptor) { - context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, classifier)) + context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(referenceExpression, classifier)) } else if (classifier is ClassDescriptor && classifier.getClassObjectType() == null) { - context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)) + context.trace.report(NO_CLASS_OBJECT.on(referenceExpression, classifier)) } else if (packageView != null) { - context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(expression)) + context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(referenceExpression)) } return null } private fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(context: ExpressionTypingContext, selector: DeclarationDescriptor?) { - context.trace.record(REFERENCE_TARGET, expression, resolveReferenceTarget(selector)) + resolveAndRecordReferenceTarget(context, selector) if (classifier is TypeParameterDescriptor) { - context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, classifier as TypeParameterDescriptor)) + context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(referenceExpression, classifier as TypeParameterDescriptor)) } else if (classifier is ClassDescriptor && classifier.getClassObjectDescriptor() != null) { checkClassObjectVisibility(context) - context.trace.record(EXPRESSION_TYPE, expression, classifier.getClassObjectType()) + context.trace.record(EXPRESSION_TYPE, referenceExpression, classifier.getClassObjectType()) } } +private fun QualifierReceiver.resolveAndRecordReferenceTarget(context: ExpressionTypingContext, selector: DeclarationDescriptor?) { + resultingDescriptor = resolveReferenceTarget(selector) + context.trace.record(REFERENCE_TARGET, referenceExpression, resultingDescriptor) +} + private fun QualifierReceiver.resolveReferenceTarget(selector: DeclarationDescriptor?): DeclarationDescriptor { if (classifier is TypeParameterDescriptor) { return classifier @@ -168,7 +193,7 @@ private fun QualifierReceiver.checkClassObjectVisibility(context: ExpressionTypi val classObject = classifier.getClassObjectDescriptor() assert(classObject != null) { "This check should be done only for classes with class objects: " + classifier } if (!Visibilities.isVisible(classObject!!, scopeContainer)) { - context.trace.report(INVISIBLE_MEMBER.on(expression, classObject, classObject.getVisibility(), scopeContainer)) + context.trace.report(INVISIBLE_MEMBER.on(referenceExpression, classObject, classObject.getVisibility(), scopeContainer)) } } diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java index ed42c6f94e3..ad4987dc85c 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java @@ -23,10 +23,7 @@ import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor; -import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -35,7 +32,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.Qualifier; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; @@ -56,19 +53,18 @@ public final class TipsManager { PsiElement parent = expression.getParent(); boolean inPositionForCompletionWithReceiver = parent instanceof JetCallExpression || parent instanceof JetQualifiedExpression; if (receiverExpression != null && inPositionForCompletionWithReceiver) { + Set descriptors = new HashSet(); // Process as call expression JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); - QualifierReceiver qualifierReceiver = context.get(BindingContext.QUALIFIER_RECEIVER, receiverExpression); - if (qualifierReceiver != null && resolutionScope != null) { - return includeExternalCallableExtensions( - excludePrivateDescriptors(qualifierReceiver.getScope().getAllDescriptors()), - resolutionScope, qualifierReceiver); + Qualifier qualifier = context.get(BindingContext.QUALIFIER, receiverExpression); + if (qualifier != null && resolutionScope != null) { + // It's impossible to add extension function for package or class (if it's class object, expression type is not null) + descriptors.addAll(new HashSet(excludePrivateDescriptors(qualifier.getScope().getAllDescriptors()))); } JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression); if (expressionType != null && resolutionScope != null && !expressionType.isError()) { ExpressionReceiver receiverValue = new ExpressionReceiver(receiverExpression, expressionType); - Set descriptors = new HashSet(); DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression); if (info == null) { @@ -83,9 +79,8 @@ public final class TipsManager { resolutionScope, receiverValue)); } - return descriptors; } - return Collections.emptyList(); + return descriptors; } else { return getVariantsNoReceiver(expression, context); @@ -196,10 +191,6 @@ public final class TipsManager { @NotNull JetScope externalScope, @NotNull final ReceiverValue receiverValue ) { - // It's impossible to add extension function for package - if (receiverValue instanceof QualifierReceiver) { - return new HashSet(descriptors); - } Set descriptorsSet = Sets.newHashSet(descriptors); descriptorsSet.addAll( diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt index 04f05943721..14a1af470b0 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt @@ -91,7 +91,7 @@ public open class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntent val bindingContext = AnalyzerFacadeWithCache.getContextForElement(parent) val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] if (receiverType == null) { - if (bindingContext[BindingContext.QUALIFIER_RECEIVER, receiver] != null) { + if (bindingContext[BindingContext.QUALIFIER, receiver] != null) { intentionFailed(editor, "package.call") return } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java index 2b4a0dcdf0c..938c592e079 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java @@ -139,7 +139,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { } } - if (expressionType == null && bindingContext.get(BindingContext.QUALIFIER_RECEIVER, expression) != null) { + if (expressionType == null && bindingContext.get(BindingContext.QUALIFIER, expression) != null) { showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.package.expression")); return; }