Refactoring: extracted interface Qualifier (that is not a ReceiverValue)

This commit is contained in:
Svetlana Isakova
2014-08-23 11:18:22 +04:00
parent bc3f6e200a
commit 4e8f10b8ab
6 changed files with 68 additions and 52 deletions
@@ -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.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; 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.DeferredType;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.CaptureKind; import org.jetbrains.jet.lang.types.expressions.CaptureKind;
@@ -85,7 +85,10 @@ public interface BindingContext {
WritableSlice<JetExpression, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(DO_NOTHING); WritableSlice<JetExpression, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); WritableSlice<JetExpression, DataFlowInfo> DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice();
WritableSlice<JetExpression, QualifierReceiver> QUALIFIER_RECEIVER = new BasicWritableSlice<JetExpression, QualifierReceiver>(DO_NOTHING); /**
* A qualifier corresponds to a receiver expression (if any). For 'A.B' qualifier is recorded for 'A'.
*/
WritableSlice<JetExpression, Qualifier> QUALIFIER = new BasicWritableSlice<JetExpression, Qualifier>(DO_NOTHING);
WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET = WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET =
new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>(DO_NOTHING); new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>(DO_NOTHING);
@@ -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.calls.util.FakeCallableDescriptorForObject;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant; 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.*;
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.types.ErrorUtils; import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInfo; import org.jetbrains.jet.lang.types.JetTypeInfo;
@@ -115,11 +112,11 @@ public class CallExpressionResolver {
} }
} }
QualifierReceiver qualifierReceiver = createQualifierReceiver(nameExpression, receiver, context); QualifierReceiver qualifier = createQualifier(nameExpression, receiver, context);
if (qualifierReceiver != null) { if (qualifier != null) {
result[0] = true; result[0] = true;
if (!isLHSOfDot) { if (!isLHSOfDot) {
resolveAsStandaloneExpression(qualifierReceiver, context); resolveAsStandaloneExpression(qualifier, context);
} }
return null; return null;
} }
@@ -286,7 +283,7 @@ public class CallExpressionResolver {
ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver); JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver);
JetType receiverType = receiverTypeInfo.getType(); 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()); 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 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) // 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); Qualifier expressionQualifier = context.trace.get(BindingContext.QUALIFIER, expression);
QualifierReceiver receiverQualifier = context.trace.get(BindingContext.QUALIFIER_RECEIVER, expression.getReceiverExpression()); Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression());
if (receiverQualifier == null && expressionQualifier != null) { if (receiverQualifier == null && expressionQualifier != null) {
assert expressionQualifier.getClassifier() instanceof ClassDescriptor : assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
@@ -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.types.expressions.ExpressionTypingContext
import org.jetbrains.jet.lang.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector import org.jetbrains.jet.lang.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector
import org.jetbrains.jet.lang.resolve.descriptorUtil.getClassObjectReferenceTarget import org.jetbrains.jet.lang.resolve.descriptorUtil.getClassObjectReferenceTarget
import org.jetbrains.jet.lang.psi.JetExpression
import kotlin.properties.Delegates
public class QualifierReceiver( public trait Qualifier {
val expression: JetSimpleNameExpression,
val packageView: PackageViewDescriptor?, val expression: JetExpression
val classifier: ClassifierDescriptor?
) : ReceiverValue { val packageView: PackageViewDescriptor?
val classifier: ClassifierDescriptor?
val name: Name val name: Name
get() = classifier?.getName() ?: packageView!!.getName() get() = classifier?.getName() ?: packageView!!.getName()
fun getClassObjectReceiver(): ReceiverValue = // package, classifier or class object descriptor
classifier?.getClassObjectType()?.let { ExpressionReceiver(expression, it) } ?: ReceiverValue.NO_RECEIVER 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 val descriptor: DeclarationDescriptor
get() = classifier ?: packageView ?: throw AssertionError("PackageView and classifier both are null") 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() 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<JetScope?>) return ChainedScope(descriptor, "Member scope for " + name + " as package or class or object", *scopes as Array<JetScope?>)
} }
fun getClassObjectReceiver(): ReceiverValue =
classifier?.getClassObjectType()?.let { ExpressionReceiver(referenceExpression, it) } ?: ReceiverValue.NO_RECEIVER
fun getNestedClassesAndPackageMembersScope(): JetScope { fun getNestedClassesAndPackageMembersScope(): JetScope {
val scopes = ArrayList<JetScope>(3) val scopes = ArrayList<JetScope>(3)
@@ -84,14 +104,14 @@ public class QualifierReceiver(
override fun toString() = "Package{$packageView} OR Class{$classifier}" override fun toString() = "Package{$packageView} OR Class{$classifier}"
} }
fun createQualifierReceiver( fun createQualifier(
expression: JetSimpleNameExpression, expression: JetSimpleNameExpression,
receiver: ReceiverValue, receiver: ReceiverValue,
context: ExpressionTypingContext context: ExpressionTypingContext
): QualifierReceiver? { ): QualifierReceiver? {
val receiverScope = when { val receiverScope = when {
!receiver.exists() -> context.scope !receiver.exists() -> context.scope
receiver is QualifierReceiver -> receiver.getScope() receiver is QualifierReceiver -> receiver.scope
else -> receiver.getType().getMemberScope() else -> receiver.getType().getMemberScope()
} }
@@ -106,36 +126,41 @@ fun createQualifierReceiver(
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, expression, context.dataFlowInfo) context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, expression, context.dataFlowInfo)
} }
val qualifierReceiver = QualifierReceiver(expression, packageViewDescriptor, classifierDescriptor) val qualifier = QualifierReceiver(expression, packageViewDescriptor, classifierDescriptor)
context.trace.record(QUALIFIER_RECEIVER, expression.getTopmostParentQualifiedExpressionForSelector() ?: expression, qualifierReceiver) context.trace.record(QUALIFIER, qualifier.expression, qualifier)
return qualifierReceiver return qualifier
} }
private fun QualifierReceiver.resolveAsStandaloneExpression(context: ExpressionTypingContext): JetType? { private fun QualifierReceiver.resolveAsStandaloneExpression(context: ExpressionTypingContext): JetType? {
context.trace.record(REFERENCE_TARGET, expression, resolveReferenceTarget(selector = null)) resolveAndRecordReferenceTarget(context, selector = null)
if (classifier is TypeParameterDescriptor) { 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) { 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) { else if (packageView != null) {
context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(expression)) context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(referenceExpression))
} }
return null return null
} }
private fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(context: ExpressionTypingContext, selector: DeclarationDescriptor?) { private fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(context: ExpressionTypingContext, selector: DeclarationDescriptor?) {
context.trace.record(REFERENCE_TARGET, expression, resolveReferenceTarget(selector)) resolveAndRecordReferenceTarget(context, selector)
if (classifier is TypeParameterDescriptor) { 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) { else if (classifier is ClassDescriptor && classifier.getClassObjectDescriptor() != null) {
checkClassObjectVisibility(context) 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 { private fun QualifierReceiver.resolveReferenceTarget(selector: DeclarationDescriptor?): DeclarationDescriptor {
if (classifier is TypeParameterDescriptor) { if (classifier is TypeParameterDescriptor) {
return classifier return classifier
@@ -168,7 +193,7 @@ private fun QualifierReceiver.checkClassObjectVisibility(context: ExpressionTypi
val classObject = classifier.getClassObjectDescriptor() val classObject = classifier.getClassObjectDescriptor()
assert(classObject != null) { "This check should be done only for classes with class objects: " + classifier } assert(classObject != null) { "This check should be done only for classes with class objects: " + classifier }
if (!Visibilities.isVisible(classObject!!, scopeContainer)) { 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))
} }
} }
@@ -23,10 +23,7 @@ import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.*;
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.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage; import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.resolve.BindingContext; 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.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; 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.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.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
@@ -56,19 +53,18 @@ public final class TipsManager {
PsiElement parent = expression.getParent(); PsiElement parent = expression.getParent();
boolean inPositionForCompletionWithReceiver = parent instanceof JetCallExpression || parent instanceof JetQualifiedExpression; boolean inPositionForCompletionWithReceiver = parent instanceof JetCallExpression || parent instanceof JetQualifiedExpression;
if (receiverExpression != null && inPositionForCompletionWithReceiver) { if (receiverExpression != null && inPositionForCompletionWithReceiver) {
Set<DeclarationDescriptor> descriptors = new HashSet<DeclarationDescriptor>();
// Process as call expression // Process as call expression
JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
QualifierReceiver qualifierReceiver = context.get(BindingContext.QUALIFIER_RECEIVER, receiverExpression); Qualifier qualifier = context.get(BindingContext.QUALIFIER, receiverExpression);
if (qualifierReceiver != null && resolutionScope != null) { if (qualifier != null && resolutionScope != null) {
return includeExternalCallableExtensions( // It's impossible to add extension function for package or class (if it's class object, expression type is not null)
excludePrivateDescriptors(qualifierReceiver.getScope().getAllDescriptors()), descriptors.addAll(new HashSet<DeclarationDescriptor>(excludePrivateDescriptors(qualifier.getScope().getAllDescriptors())));
resolutionScope, qualifierReceiver);
} }
JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression); JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
if (expressionType != null && resolutionScope != null && !expressionType.isError()) { if (expressionType != null && resolutionScope != null && !expressionType.isError()) {
ExpressionReceiver receiverValue = new ExpressionReceiver(receiverExpression, expressionType); ExpressionReceiver receiverValue = new ExpressionReceiver(receiverExpression, expressionType);
Set<DeclarationDescriptor> descriptors = new HashSet<DeclarationDescriptor>();
DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression); DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression);
if (info == null) { if (info == null) {
@@ -83,9 +79,8 @@ public final class TipsManager {
resolutionScope, receiverValue)); resolutionScope, receiverValue));
} }
return descriptors;
} }
return Collections.emptyList(); return descriptors;
} }
else { else {
return getVariantsNoReceiver(expression, context); return getVariantsNoReceiver(expression, context);
@@ -196,10 +191,6 @@ public final class TipsManager {
@NotNull JetScope externalScope, @NotNull JetScope externalScope,
@NotNull final ReceiverValue receiverValue @NotNull final ReceiverValue receiverValue
) { ) {
// It's impossible to add extension function for package
if (receiverValue instanceof QualifierReceiver) {
return new HashSet<DeclarationDescriptor>(descriptors);
}
Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors); Set<DeclarationDescriptor> descriptorsSet = Sets.newHashSet(descriptors);
descriptorsSet.addAll( descriptorsSet.addAll(
@@ -91,7 +91,7 @@ public open class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntent
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(parent) val bindingContext = AnalyzerFacadeWithCache.getContextForElement(parent)
val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver]
if (receiverType == null) { if (receiverType == null) {
if (bindingContext[BindingContext.QUALIFIER_RECEIVER, receiver] != null) { if (bindingContext[BindingContext.QUALIFIER, receiver] != null) {
intentionFailed(editor, "package.call") intentionFailed(editor, "package.call")
return return
} }
@@ -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")); showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.package.expression"));
return; return;
} }