From dae06f0b67bcb5de243b3f90036f1af3ea67ac9b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 3 May 2011 23:21:56 +0400 Subject: [PATCH] JET-18 Resolve references to value parameters of the primary constructor to parameter or property descriptors according to the semantics --- .../jetbrains/jet/codegen/ClassCodegen.java | 10 +++--- .../jet/codegen/ExpressionCodegen.java | 4 +-- .../jet/lang/annotations/JetPsiChecker.java | 23 ++++++++----- .../jet/lang/resolve/BindingContext.java | 5 ++- .../jet/lang/resolve/BindingTraceContext.java | 34 +++++++++++++++---- .../lang/resolve/ClassDescriptorResolver.java | 2 +- .../lang/resolve/MutableClassDescriptor.java | 4 +++ .../resolve/java/JavaClassMembersScope.java | 22 +++++++++++- .../resolve/java/JavaDescriptorResolver.java | 2 +- .../jet/lang/types/BindingTrace.java | 7 ++++ .../jet/lang/types/BindingTraceAdapter.java | 5 +++ .../jetbrains/jet/resolve/DescriptorUtil.java | 6 ++++ .../jet/resolve/ExpectedResolveData.java | 2 +- 13 files changed, 99 insertions(+), 27 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 1a7ca37c192..c00c7e9ad23 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -307,9 +307,8 @@ public class ClassCodegen { for (JetParameter p : aClass.getPrimaryConstructorParameters()) { if (p.getValOrVarNode() != null) { - VariableDescriptor descriptor = bindingContext.getParameterDescriptor(p); - if (descriptor instanceof PropertyDescriptor) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p); + if (propertyDescriptor != null) { propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); if (propertyDescriptor.isVar()) { propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); @@ -341,9 +340,8 @@ public class ClassCodegen { for (JetParameter p : toClass.getPrimaryConstructorParameters()) { if (p.getValOrVarNode() != null) { - VariableDescriptor descriptor = bindingContext.getParameterDescriptor(p); - if (descriptor instanceof PropertyDescriptor) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p); + if (propertyDescriptor != null) { propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); if (propertyDescriptor.isVar()) { propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 497702e2f5e..6fc02938098 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -222,7 +222,7 @@ public class ExpressionCodegen extends JetVisitor { private void generateForInArray(JetForExpression expression, Type loopRangeType) { final JetParameter loopParameter = expression.getLoopParameter(); - final VariableDescriptor parameterDescriptor = bindingContext.getParameterDescriptor(loopParameter); + final VariableDescriptor parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter); JetType paramType = parameterDescriptor.getOutType(); Type asmParamType = typeMapper.mapType(paramType); @@ -269,7 +269,7 @@ public class ExpressionCodegen extends JetVisitor { private void generateForInIterable(JetForExpression expression, Type loopRangeType) { final JetParameter loopParameter = expression.getLoopParameter(); - final VariableDescriptor parameterDescriptor = bindingContext.getParameterDescriptor(loopParameter); + final VariableDescriptor parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter); JetType paramType = parameterDescriptor.getOutType(); Type asmParamType = typeMapper.mapType(paramType); diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java index 7aebda2d7ff..e83a6c5045b 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java @@ -99,18 +99,18 @@ public class JetPsiChecker implements Annotator { VariableDescriptor propertyDescriptor = bindingContext.getVariableDescriptor(property); if (propertyDescriptor instanceof PropertyDescriptor) { if (bindingContext.hasBackingField((PropertyDescriptor) propertyDescriptor)) { - holder.createInfoAnnotation( - property.getNameIdentifier(), - "This property has a backing field") - .setTextAttributes(JetHighlighter.JET_PROPERTY_WITH_BACKING_FIELD_IDENTIFIER); + putBackingfieldAnnotation(holder, property); } } } -// @Override -// public void visitParameter(JetParameter parameter) { -// bindingContext.get -// } + @Override + public void visitParameter(JetParameter parameter) { + PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(parameter); + if (propertyDescriptor != null && bindingContext.hasBackingField(propertyDescriptor)) { + putBackingfieldAnnotation(holder, parameter); + } + } @Override public void visitJetElement(JetElement elem) { @@ -118,4 +118,11 @@ public class JetPsiChecker implements Annotator { } }); } + + private void putBackingfieldAnnotation(AnnotationHolder holder, JetNamedDeclaration element) { + holder.createInfoAnnotation( + element.getNameIdentifier(), + "This property has a backing field") + .setTextAttributes(JetHighlighter.JET_PROPERTY_WITH_BACKING_FIELD_IDENTIFIER); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 0ffff7aef1f..ce6d09efaa9 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -14,8 +14,11 @@ public interface BindingContext { TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration); FunctionDescriptor getFunctionDescriptor(JetFunction declaration); ConstructorDescriptor getConstructorDescriptor(JetElement declaration); + VariableDescriptor getVariableDescriptor(JetProperty declaration); - VariableDescriptor getParameterDescriptor(JetParameter declaration); + VariableDescriptor getVariableDescriptor(JetParameter declaration); + + PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter); JetType getExpressionType(JetExpression expression); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index 4715488b887..77779926139 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -24,7 +24,8 @@ public class BindingTraceContext implements BindingContext, BindingTrace { private final Map descriptorToDeclarations = new HashMap(); private final Map declarationsToDescriptors = new HashMap(); private final Map constructorDeclarationsToDescriptors = new HashMap(); - private final Map propertyDeclarationsToDescriptors = Maps.newHashMap(); + private final Map namespaceDeclarationsToDescriptors = Maps.newHashMap(); + private final Map primaryConstructorParameterDeclarationsToPropertyDescriptors = Maps.newHashMap(); private final Set blocks = new HashSet(); private final Set statements = new HashSet(); private final Set backingFieldRequired = new HashSet(); @@ -68,9 +69,12 @@ public class BindingTraceContext implements BindingContext, BindingTrace { return null; } - - @Override + public Void visitNamespaceDescriptor(NamespaceDescriptor descriptor, PsiElement declaration) { + namespaceDeclarationsToDescriptors.put(declaration, descriptor); + return null; + } + public Void visitDeclarationDescriptor(DeclarationDescriptor descriptor, PsiElement declaration) { safePut(declarationsToDescriptors, declaration, descriptor.getOriginal()); return null; @@ -78,10 +82,16 @@ public class BindingTraceContext implements BindingContext, BindingTrace { }, declaration); } + @Override + public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) { + safePut(primaryConstructorParameterDeclarationsToPropertyDescriptors, declaration, descriptor); + safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration); + } + private void safePut(Map map, K key, V value) { V oldValue = map.put(key, value); // TODO: -// assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value; + assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value; } @Override @@ -112,7 +122,7 @@ public class BindingTraceContext implements BindingContext, BindingTrace { public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) { - return (NamespaceDescriptor) declarationsToDescriptors.get(declaration); + return namespaceDeclarationsToDescriptors.get(declaration); } @Override @@ -136,10 +146,16 @@ public class BindingTraceContext implements BindingContext, BindingTrace { } @Override - public VariableDescriptor getParameterDescriptor(JetParameter declaration) { + public VariableDescriptor getVariableDescriptor(JetParameter declaration) { return (VariableDescriptor) declarationsToDescriptors.get(declaration); } + @Override + public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) { + PropertyDescriptor descriptor = primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter); + return descriptor; + } + @Override public JetType resolveTypeReference(JetTypeReference typeReference) { return types.get(typeReference); @@ -192,6 +208,12 @@ public class BindingTraceContext implements BindingContext, BindingTrace { @Override public boolean hasBackingField(@NotNull PropertyDescriptor propertyDescriptor) { + PsiElement declarationPsiElement = getDeclarationPsiElement(propertyDescriptor); + if (declarationPsiElement instanceof JetParameter) { + JetParameter jetParameter = (JetParameter) declarationPsiElement; + return jetParameter.getValOrVarNode() != null || + backingFieldRequired.contains(propertyDescriptor); + } if (propertyDescriptor.getModifiers().isAbstract()) return false; PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); PropertySetterDescriptor setter = propertyDescriptor.getSetter(); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 0f667215811..7fc611e93fa 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -509,7 +509,7 @@ public class ClassDescriptorResolver { isMutable ? type : null, type); propertyDescriptor.initialize(null, null); - trace.recordDeclarationResolution(parameter, propertyDescriptor); + trace.recordValueParameterAsPropertyResolution(parameter, propertyDescriptor); return propertyDescriptor; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java index 659cd038c23..195daad51b7 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java @@ -51,6 +51,10 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @NotNull @Override public JetScope getMemberScope(List typeArguments) { + assert typeArguments.size() == typeConstructor.getParameters().size(); + assert unsubstitutedMemberScope != null; + if (typeArguments.isEmpty()) return unsubstitutedMemberScope; + List typeParameters = getTypeConstructor().getParameters(); Map substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments); return new SubstitutingScope(unsubstitutedMemberScope, TypeSubstitutor.create(substitutionContext)); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java index 1872739ac79..bf171e74182 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java @@ -4,7 +4,6 @@ import com.google.common.collect.Maps; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.JetScope; -import org.jetbrains.jet.lang.resolve.WritableFunctionGroup; import org.jetbrains.jet.lang.types.*; import java.util.Collection; @@ -20,6 +19,8 @@ public class JavaClassMembersScope implements JetScope { private final boolean staticMembers; private final DeclarationDescriptor containingDeclaration; private final Map functionGroups = Maps.newHashMap(); + private final Map variables = Maps.newHashMap(); + private final Map classifiers = Maps.newHashMap(); public JavaClassMembersScope(@NotNull DeclarationDescriptor classDescriptor, PsiClass psiClass, JavaSemanticServices semanticServices, boolean staticMembers) { this.containingDeclaration = classDescriptor; @@ -47,6 +48,16 @@ public class JavaClassMembersScope implements JetScope { @Override public ClassifierDescriptor getClassifier(@NotNull String name) { + ClassifierDescriptor classifierDescriptor = classifiers.get(name); + if (classifierDescriptor == null) { + classifierDescriptor = doGetClassifierDescriptor(name); + classifiers.put(name, classifierDescriptor); + } + return classifierDescriptor; + } + + private ClassifierDescriptor doGetClassifierDescriptor(String name) { + // TODO : suboptimal, walk the list only once for (PsiClass innerClass : psiClass.getAllInnerClasses()) { if (name.equals(innerClass.getName())) { if (innerClass.hasModifierProperty(PsiModifier.STATIC) != staticMembers) return null; @@ -58,6 +69,15 @@ public class JavaClassMembersScope implements JetScope { @Override public VariableDescriptor getVariable(@NotNull String name) { + VariableDescriptor variableDescriptor = variables.get(name); + if (variableDescriptor == null) { + variableDescriptor = doGetVariable(name); + variables.put(name, variableDescriptor); + } + return variableDescriptor; + } + + private VariableDescriptor doGetVariable(String name) { PsiField field = psiClass.findFieldByName(name, true); if (field == null) return null; if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 44256474caa..bba08ae3ede 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -93,9 +93,9 @@ public class JavaDescriptorResolver { )); classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor); + classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false)); // UGLY HACK supertypes.addAll(getSupertypes(psiClass)); - classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false)); // NOTE: this writes into constructors after it is remembered by the classDescriptor PsiMethod[] psiConstructors = psiClass.getConstructors(); diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index 13688a8cb52..bc7ef1be26d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -27,6 +27,11 @@ public interface BindingTrace { public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { } + @Override + public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) { + + } + @Override public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type) { } @@ -64,6 +69,8 @@ public interface BindingTrace { public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor); + public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor); + public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type); public void setToplevelScope(JetScope toplevelScope); diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java b/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java index 1a250a5cac8..9ad068f618c 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTraceAdapter.java @@ -31,6 +31,11 @@ public class BindingTraceAdapter implements BindingTrace { originalTrace.recordDeclarationResolution(declaration, descriptor); } + @Override + public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) { + originalTrace.recordValueParameterAsPropertyResolution(declaration, descriptor); + } + public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type) { originalTrace.recordTypeResolution(typeReference, type); } diff --git a/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java b/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java index e4933d4feac..b757ec93fcc 100644 --- a/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java +++ b/idea/src/org/jetbrains/jet/resolve/DescriptorUtil.java @@ -17,6 +17,12 @@ public class DescriptorUtil { StringBuilder stringBuilder = new StringBuilder(); declarationDescriptor.accept( new DeclarationDescriptorVisitor() { + @Override + public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { + builder.append("value-parameter "); + return super.visitValueParameterDescriptor(descriptor, builder); + } + @Override public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { JetType outType = descriptor.getOutType(); diff --git a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java index 2708cf3ea0b..f34087399c0 100644 --- a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java +++ b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java @@ -151,7 +151,7 @@ public class ExpectedResolveData { } } assertNotNull(reference); - assertSame( + assertEquals( "Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".", expected, actual); }