JET-18 Resolve references to value parameters of the primary constructor to parameter or property descriptors according to the semantics

This commit is contained in:
Andrey Breslav
2011-05-03 23:21:56 +04:00
parent fe36a55a94
commit dae06f0b67
13 changed files with 99 additions and 27 deletions
@@ -307,9 +307,8 @@ public class ClassCodegen {
for (JetParameter p : aClass.getPrimaryConstructorParameters()) { for (JetParameter p : aClass.getPrimaryConstructorParameters()) {
if (p.getValOrVarNode() != null) { if (p.getValOrVarNode() != null) {
VariableDescriptor descriptor = bindingContext.getParameterDescriptor(p); PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p);
if (descriptor instanceof PropertyDescriptor) { if (propertyDescriptor != null) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
if (propertyDescriptor.isVar()) { if (propertyDescriptor.isVar()) {
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
@@ -341,9 +340,8 @@ public class ClassCodegen {
for (JetParameter p : toClass.getPrimaryConstructorParameters()) { for (JetParameter p : toClass.getPrimaryConstructorParameters()) {
if (p.getValOrVarNode() != null) { if (p.getValOrVarNode() != null) {
VariableDescriptor descriptor = bindingContext.getParameterDescriptor(p); PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(p);
if (descriptor instanceof PropertyDescriptor) { if (propertyDescriptor != null) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
if (propertyDescriptor.isVar()) { if (propertyDescriptor.isVar()) {
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind); propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, kind);
@@ -222,7 +222,7 @@ public class ExpressionCodegen extends JetVisitor {
private void generateForInArray(JetForExpression expression, Type loopRangeType) { private void generateForInArray(JetForExpression expression, Type loopRangeType) {
final JetParameter loopParameter = expression.getLoopParameter(); final JetParameter loopParameter = expression.getLoopParameter();
final VariableDescriptor parameterDescriptor = bindingContext.getParameterDescriptor(loopParameter); final VariableDescriptor parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter);
JetType paramType = parameterDescriptor.getOutType(); JetType paramType = parameterDescriptor.getOutType();
Type asmParamType = typeMapper.mapType(paramType); Type asmParamType = typeMapper.mapType(paramType);
@@ -269,7 +269,7 @@ public class ExpressionCodegen extends JetVisitor {
private void generateForInIterable(JetForExpression expression, Type loopRangeType) { private void generateForInIterable(JetForExpression expression, Type loopRangeType) {
final JetParameter loopParameter = expression.getLoopParameter(); final JetParameter loopParameter = expression.getLoopParameter();
final VariableDescriptor parameterDescriptor = bindingContext.getParameterDescriptor(loopParameter); final VariableDescriptor parameterDescriptor = bindingContext.getVariableDescriptor(loopParameter);
JetType paramType = parameterDescriptor.getOutType(); JetType paramType = parameterDescriptor.getOutType();
Type asmParamType = typeMapper.mapType(paramType); Type asmParamType = typeMapper.mapType(paramType);
@@ -99,18 +99,18 @@ public class JetPsiChecker implements Annotator {
VariableDescriptor propertyDescriptor = bindingContext.getVariableDescriptor(property); VariableDescriptor propertyDescriptor = bindingContext.getVariableDescriptor(property);
if (propertyDescriptor instanceof PropertyDescriptor) { if (propertyDescriptor instanceof PropertyDescriptor) {
if (bindingContext.hasBackingField((PropertyDescriptor) propertyDescriptor)) { if (bindingContext.hasBackingField((PropertyDescriptor) propertyDescriptor)) {
holder.createInfoAnnotation( putBackingfieldAnnotation(holder, property);
property.getNameIdentifier(),
"This property has a backing field")
.setTextAttributes(JetHighlighter.JET_PROPERTY_WITH_BACKING_FIELD_IDENTIFIER);
} }
} }
} }
// @Override @Override
// public void visitParameter(JetParameter parameter) { public void visitParameter(JetParameter parameter) {
// bindingContext.get PropertyDescriptor propertyDescriptor = bindingContext.getPropertyDescriptor(parameter);
// } if (propertyDescriptor != null && bindingContext.hasBackingField(propertyDescriptor)) {
putBackingfieldAnnotation(holder, parameter);
}
}
@Override @Override
public void visitJetElement(JetElement elem) { 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);
}
} }
@@ -14,8 +14,11 @@ public interface BindingContext {
TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration); TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration);
FunctionDescriptor getFunctionDescriptor(JetFunction declaration); FunctionDescriptor getFunctionDescriptor(JetFunction declaration);
ConstructorDescriptor getConstructorDescriptor(JetElement declaration); ConstructorDescriptor getConstructorDescriptor(JetElement declaration);
VariableDescriptor getVariableDescriptor(JetProperty declaration); VariableDescriptor getVariableDescriptor(JetProperty declaration);
VariableDescriptor getParameterDescriptor(JetParameter declaration); VariableDescriptor getVariableDescriptor(JetParameter declaration);
PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter);
JetType getExpressionType(JetExpression expression); JetType getExpressionType(JetExpression expression);
@@ -24,7 +24,8 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>(); private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>();
private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>(); private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>();
private final Map<PsiElement, ConstructorDescriptor> constructorDeclarationsToDescriptors = new HashMap<PsiElement, ConstructorDescriptor>(); private final Map<PsiElement, ConstructorDescriptor> constructorDeclarationsToDescriptors = new HashMap<PsiElement, ConstructorDescriptor>();
private final Map<PsiElement, PropertyDescriptor> propertyDeclarationsToDescriptors = Maps.newHashMap(); private final Map<PsiElement, NamespaceDescriptor> namespaceDeclarationsToDescriptors = Maps.newHashMap();
private final Map<PsiElement, PropertyDescriptor> primaryConstructorParameterDeclarationsToPropertyDescriptors = Maps.newHashMap();
private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>(); private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>();
private final Set<JetElement> statements = new HashSet<JetElement>(); private final Set<JetElement> statements = new HashSet<JetElement>();
private final Set<PropertyDescriptor> backingFieldRequired = new HashSet<PropertyDescriptor>(); private final Set<PropertyDescriptor> backingFieldRequired = new HashSet<PropertyDescriptor>();
@@ -68,9 +69,12 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
return null; return null;
} }
@Override @Override
public Void visitNamespaceDescriptor(NamespaceDescriptor descriptor, PsiElement declaration) {
namespaceDeclarationsToDescriptors.put(declaration, descriptor);
return null;
}
public Void visitDeclarationDescriptor(DeclarationDescriptor descriptor, PsiElement declaration) { public Void visitDeclarationDescriptor(DeclarationDescriptor descriptor, PsiElement declaration) {
safePut(declarationsToDescriptors, declaration, descriptor.getOriginal()); safePut(declarationsToDescriptors, declaration, descriptor.getOriginal());
return null; return null;
@@ -78,10 +82,16 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
}, declaration); }, declaration);
} }
@Override
public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) {
safePut(primaryConstructorParameterDeclarationsToPropertyDescriptors, declaration, descriptor);
safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration);
}
private <K, V> void safePut(Map<K, V> map, K key, V value) { private <K, V> void safePut(Map<K, V> map, K key, V value) {
V oldValue = map.put(key, value); V oldValue = map.put(key, value);
// TODO: // TODO:
// assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value; assert oldValue == null || oldValue == value : key + ": " + oldValue + " and " + value;
} }
@Override @Override
@@ -112,7 +122,7 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) { public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) {
return (NamespaceDescriptor) declarationsToDescriptors.get(declaration); return namespaceDeclarationsToDescriptors.get(declaration);
} }
@Override @Override
@@ -136,10 +146,16 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
} }
@Override @Override
public VariableDescriptor getParameterDescriptor(JetParameter declaration) { public VariableDescriptor getVariableDescriptor(JetParameter declaration) {
return (VariableDescriptor) declarationsToDescriptors.get(declaration); return (VariableDescriptor) declarationsToDescriptors.get(declaration);
} }
@Override
public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) {
PropertyDescriptor descriptor = primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter);
return descriptor;
}
@Override @Override
public JetType resolveTypeReference(JetTypeReference typeReference) { public JetType resolveTypeReference(JetTypeReference typeReference) {
return types.get(typeReference); return types.get(typeReference);
@@ -192,6 +208,12 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
@Override @Override
public boolean hasBackingField(@NotNull PropertyDescriptor propertyDescriptor) { 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; if (propertyDescriptor.getModifiers().isAbstract()) return false;
PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
PropertySetterDescriptor setter = propertyDescriptor.getSetter(); PropertySetterDescriptor setter = propertyDescriptor.getSetter();
@@ -509,7 +509,7 @@ public class ClassDescriptorResolver {
isMutable ? type : null, isMutable ? type : null,
type); type);
propertyDescriptor.initialize(null, null); propertyDescriptor.initialize(null, null);
trace.recordDeclarationResolution(parameter, propertyDescriptor); trace.recordValueParameterAsPropertyResolution(parameter, propertyDescriptor);
return propertyDescriptor; return propertyDescriptor;
} }
@@ -51,6 +51,10 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@NotNull @NotNull
@Override @Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) { public JetScope getMemberScope(List<TypeProjection> typeArguments) {
assert typeArguments.size() == typeConstructor.getParameters().size();
assert unsubstitutedMemberScope != null;
if (typeArguments.isEmpty()) return unsubstitutedMemberScope;
List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters(); List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments); Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments);
return new SubstitutingScope(unsubstitutedMemberScope, TypeSubstitutor.create(substitutionContext)); return new SubstitutingScope(unsubstitutedMemberScope, TypeSubstitutor.create(substitutionContext));
@@ -4,7 +4,6 @@ import com.google.common.collect.Maps;
import com.intellij.psi.*; import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.JetScope; import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.WritableFunctionGroup;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.Collection; import java.util.Collection;
@@ -20,6 +19,8 @@ public class JavaClassMembersScope implements JetScope {
private final boolean staticMembers; private final boolean staticMembers;
private final DeclarationDescriptor containingDeclaration; private final DeclarationDescriptor containingDeclaration;
private final Map<String, FunctionGroup> functionGroups = Maps.newHashMap(); private final Map<String, FunctionGroup> functionGroups = Maps.newHashMap();
private final Map<String, VariableDescriptor> variables = Maps.newHashMap();
private final Map<String, ClassifierDescriptor> classifiers = Maps.newHashMap();
public JavaClassMembersScope(@NotNull DeclarationDescriptor classDescriptor, PsiClass psiClass, JavaSemanticServices semanticServices, boolean staticMembers) { public JavaClassMembersScope(@NotNull DeclarationDescriptor classDescriptor, PsiClass psiClass, JavaSemanticServices semanticServices, boolean staticMembers) {
this.containingDeclaration = classDescriptor; this.containingDeclaration = classDescriptor;
@@ -47,6 +48,16 @@ public class JavaClassMembersScope implements JetScope {
@Override @Override
public ClassifierDescriptor getClassifier(@NotNull String name) { 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()) { for (PsiClass innerClass : psiClass.getAllInnerClasses()) {
if (name.equals(innerClass.getName())) { if (name.equals(innerClass.getName())) {
if (innerClass.hasModifierProperty(PsiModifier.STATIC) != staticMembers) return null; if (innerClass.hasModifierProperty(PsiModifier.STATIC) != staticMembers) return null;
@@ -58,6 +69,15 @@ public class JavaClassMembersScope implements JetScope {
@Override @Override
public VariableDescriptor getVariable(@NotNull String name) { 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); PsiField field = psiClass.findFieldByName(name, true);
if (field == null) return null; if (field == null) return null;
if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) { if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
@@ -93,9 +93,9 @@ public class JavaDescriptorResolver {
)); ));
classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor); classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor);
classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false));
// UGLY HACK // UGLY HACK
supertypes.addAll(getSupertypes(psiClass)); supertypes.addAll(getSupertypes(psiClass));
classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false));
// NOTE: this writes into constructors after it is remembered by the classDescriptor // NOTE: this writes into constructors after it is remembered by the classDescriptor
PsiMethod[] psiConstructors = psiClass.getConstructors(); PsiMethod[] psiConstructors = psiClass.getConstructors();
@@ -27,6 +27,11 @@ public interface BindingTrace {
public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) {
} }
@Override
public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) {
}
@Override @Override
public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type) { 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 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 recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type);
public void setToplevelScope(JetScope toplevelScope); public void setToplevelScope(JetScope toplevelScope);
@@ -31,6 +31,11 @@ public class BindingTraceAdapter implements BindingTrace {
originalTrace.recordDeclarationResolution(declaration, descriptor); 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) { public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type) {
originalTrace.recordTypeResolution(typeReference, type); originalTrace.recordTypeResolution(typeReference, type);
} }
@@ -17,6 +17,12 @@ public class DescriptorUtil {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
declarationDescriptor.accept( declarationDescriptor.accept(
new DeclarationDescriptorVisitor<Void, StringBuilder>() { new DeclarationDescriptorVisitor<Void, StringBuilder>() {
@Override
public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
builder.append("value-parameter ");
return super.visitValueParameterDescriptor(descriptor, builder);
}
@Override @Override
public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) {
JetType outType = descriptor.getOutType(); JetType outType = descriptor.getOutType();
@@ -151,7 +151,7 @@ public class ExpectedResolveData {
} }
} }
assertNotNull(reference); assertNotNull(reference);
assertSame( assertEquals(
"Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".", "Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".",
expected, actual); expected, actual);
} }