allow two ext properties with same name in one package

This commit is contained in:
Stepan Koltsov
2012-01-18 12:07:03 +04:00
parent 509e018954
commit df9a4c7786
8 changed files with 277 additions and 133 deletions
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass;
@@ -15,9 +16,12 @@ import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiPackage; import com.intellij.psi.PsiPackage;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType; import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter; import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.PsiTypeParameterListOwner; import com.intellij.psi.PsiTypeParameterListOwner;
import com.intellij.psi.PsiTypeVariable;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.DelegatingGlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import jet.typeinfo.TypeInfoVariance; import jet.typeinfo.TypeInfoVariance;
@@ -60,6 +64,7 @@ import org.jetbrains.jet.rt.signature.JetSignatureVisitor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -800,7 +805,7 @@ public class JavaDescriptorResolver {
Map<String, NamedMembers> membersForProperties = scopeData.namedMembersMap; Map<String, NamedMembers> membersForProperties = scopeData.namedMembersMap;
for (Map.Entry<String, NamedMembers> entry : membersForProperties.entrySet()) { for (Map.Entry<String, NamedMembers> entry : membersForProperties.entrySet()) {
NamedMembers namedMembers = entry.getValue(); NamedMembers namedMembers = entry.getValue();
if (namedMembers.properties == null) { if (namedMembers.propertyAccessors == null) {
continue; continue;
} }
@@ -811,126 +816,196 @@ public class JavaDescriptorResolver {
} }
return descriptors; return descriptors;
} }
private Object key(TypeSource typeSource) {
if (typeSource == null) {
return "";
} else if (typeSource.getTypeString().length() > 0) {
return typeSource.getTypeString();
} else {
if (typeSource.getPsiType() instanceof PsiClassType) {
return ((PsiClassType) typeSource.getPsiType()).getClassName();
} else if (typeSource.getPsiType() instanceof PsiPrimitiveType) {
return typeSource.getPsiType().getPresentableText();
} else {
throw new IllegalStateException("" + typeSource.getPsiType().getClass());
}
}
}
private Object propertyKeyForGrouping(PropertyAccessorData propertyAccessor) {
Object type = key(propertyAccessor.getType());
Object receiverType = key(propertyAccessor.getReceiverType());
return Pair.create(type, receiverType);
}
private void resolveNamedGroupProperties(DeclarationDescriptor owner, boolean staticMembers, NamedMembers namedMembers, String propertyName) { private void resolveNamedGroupProperties(DeclarationDescriptor owner, boolean staticMembers, NamedMembers namedMembers, String propertyName) {
if (namedMembers.propertyDescriptors != null) { if (namedMembers.propertyDescriptors != null) {
return; return;
} }
if (namedMembers.properties == null) { if (namedMembers.propertyAccessors == null) {
namedMembers.propertyDescriptors = Collections.emptySet(); namedMembers.propertyDescriptors = Collections.emptySet();
return; return;
} }
TypeSource propertyType = namedMembers.properties.type;
TypeSource receiver = namedMembers.properties.receiverType;
MembersForProperty members = namedMembers.properties;
boolean isFinal;
if (members.setter == null && members.getter == null) {
isFinal = false;
} else if (members.getter != null) {
isFinal = members.getter.isFinal();
} else if (members.setter != null) {
isFinal = members.setter.isFinal();
} else {
isFinal = false;
}
PsiMemberWrapper anyMember;
if (members.getter != null) {
anyMember = members.getter;
} else if (members.field != null) {
anyMember = members.field;
} else if (members.setter != null) {
anyMember = members.setter;
} else {
throw new IllegalStateException();
}
boolean isVar;
if (members.getter == null && members.setter == null) {
isVar = !members.field.isFinal();
} else {
isVar = members.setter != null;
}
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
owner,
Collections.<AnnotationDescriptor>emptyList(),
isFinal && !staticMembers ? Modality.FINAL : Modality.OPEN, // TODO: abstract
resolveVisibilityFromPsiModifiers(anyMember.psiMember),
isVar,
false,
propertyName);
PropertyGetterDescriptor getterDescriptor = null;
PropertySetterDescriptor setterDescriptor = null;
if (members.getter != null) {
getterDescriptor = new PropertyGetterDescriptor(propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false);
}
if (members.setter != null) {
setterDescriptor = new PropertySetterDescriptor(propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false);
}
propertyDescriptor.initialize(getterDescriptor, setterDescriptor);
final List<TypeParameterDescriptor> classTypeParameters; final List<TypeParameterDescriptor> classTypeParameters;
if (anyMember instanceof PsiMethodWrapper && !anyMember.isStatic()) { if (!staticMembers) {
classTypeParameters = ((ClassDescriptor) owner).getTypeConstructor().getParameters(); classTypeParameters = ((ClassDescriptor) owner).getTypeConstructor().getParameters();
} else { } else {
classTypeParameters = new ArrayList<TypeParameterDescriptor>(0); classTypeParameters = new ArrayList<TypeParameterDescriptor>(0);
} }
TypeParameterListTypeVariableResolver typeVariableResolver = new TypeParameterListTypeVariableResolver(classTypeParameters); TypeParameterListTypeVariableResolver typeVariableResolver = new TypeParameterListTypeVariableResolver(classTypeParameters);
List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(0); class GroupingValue {
PropertyAccessorData getter;
if (members.setter != null) { PropertyAccessorData setter;
// call ugly code with side effects PropertyAccessorData field;
typeParameters = resolveMethodTypeParameters(members.setter, propertyDescriptor.getSetter(), typeVariableResolver);
}
if (members.getter != null) {
// call ugly code with side effects
typeParameters = resolveMethodTypeParameters(members.getter, propertyDescriptor.getGetter(), typeVariableResolver);
} }
List<TypeParameterDescriptor> typeParametersForReceiver = new ArrayList<TypeParameterDescriptor>(); Map<Object, GroupingValue> map = new HashMap<Object, GroupingValue>();
typeParametersForReceiver.addAll(classTypeParameters);
typeParametersForReceiver.addAll(typeParameters); for (PropertyAccessorData propertyAccessor : namedMembers.propertyAccessors) {
Object key = propertyKeyForGrouping(propertyAccessor);
GroupingValue value = map.get(key);
if (value == null) {
value = new GroupingValue();
map.put(key, value);
}
if (propertyAccessor.isGetter()) {
if (value.getter != null) {
throw new IllegalStateException("oops, duplicate key");
}
value.getter = propertyAccessor;
} else if (propertyAccessor.isSetter()) {
if (value.setter != null) {
throw new IllegalStateException("oops, duplicate key");
}
value.setter = propertyAccessor;
} else if (propertyAccessor.isField()) {
if (value.field != null) {
throw new IllegalStateException("oops, duplicate key");
}
value.field = propertyAccessor;
} else {
throw new IllegalStateException();
}
}
TypeParameterListTypeVariableResolver typeVariableResolverForPropertyInternals = new TypeParameterListTypeVariableResolver(typeParametersForReceiver);
JetType receiverJetType; Set<VariableDescriptor> r = new HashSet<VariableDescriptor>();
if (receiver == null) {
receiverJetType = null; for (GroupingValue members : map.values()) {
} else if (receiver.getTypeString().length() > 0) { boolean isFinal;
receiverJetType = semanticServices.getTypeTransformer().transformToType(receiver.getTypeString(), typeVariableResolverForPropertyInternals); if (members.setter == null && members.getter == null) {
} else { isFinal = false;
receiverJetType = semanticServices.getTypeTransformer().transformToType(receiver.getPsiType()); } else if (members.getter != null) {
} isFinal = members.getter.getMember().isFinal();
} else if (members.setter != null) {
isFinal = members.setter.getMember().isFinal();
} else {
isFinal = false;
}
JetType type; PropertyAccessorData anyMember;
if (propertyType.getTypeString().length() > 0) { if (members.getter != null) {
type = semanticServices.getTypeTransformer().transformToType(propertyType.getTypeString(), typeVariableResolverForPropertyInternals); anyMember = members.getter;
} else { } else if (members.field != null) {
type = semanticServices.getTypeTransformer().transformToType(propertyType.getPsiType()); anyMember = members.field;
} } else if (members.setter != null) {
anyMember = members.setter;
} else {
throw new IllegalStateException();
}
propertyDescriptor.setType( boolean isVar;
type, if (members.getter == null && members.setter == null) {
typeParameters, isVar = !members.field.getMember().isFinal();
DescriptorUtils.getExpectedThisObjectIfNeeded(owner), } else {
receiverJetType isVar = members.setter != null;
}
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
owner,
Collections.<AnnotationDescriptor>emptyList(),
isFinal && !staticMembers ? Modality.FINAL : Modality.OPEN, // TODO: abstract
resolveVisibilityFromPsiModifiers(anyMember.getMember().psiMember),
isVar,
false,
propertyName);
PropertyGetterDescriptor getterDescriptor = null;
PropertySetterDescriptor setterDescriptor = null;
if (members.getter != null) {
getterDescriptor = new PropertyGetterDescriptor(propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false);
}
if (members.setter != null) {
setterDescriptor = new PropertySetterDescriptor(propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false);
}
propertyDescriptor.initialize(getterDescriptor, setterDescriptor);
List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(0);
if (members.setter != null) {
PsiMethodWrapper method = (PsiMethodWrapper) members.setter.getMember();
if (anyMember == members.setter) {
typeParameters = resolveMethodTypeParameters(method, setterDescriptor, typeVariableResolver);
}
}
if (members.getter != null) {
PsiMethodWrapper method = (PsiMethodWrapper) members.getter.getMember();
if (anyMember == members.getter) {
typeParameters = resolveMethodTypeParameters(method, getterDescriptor, typeVariableResolver);
}
}
List<TypeParameterDescriptor> typeParametersForReceiver = new ArrayList<TypeParameterDescriptor>();
typeParametersForReceiver.addAll(classTypeParameters);
typeParametersForReceiver.addAll(typeParameters);
TypeVariableResolver typeVariableResolverForPropertyInternals = new TypeParameterListTypeVariableResolver(typeParametersForReceiver);
JetType propertyType;
if (anyMember.getType().getTypeString().length() > 0) {
propertyType = semanticServices.getTypeTransformer().transformToType(anyMember.getType().getTypeString(), typeVariableResolverForPropertyInternals);
} else {
propertyType = semanticServices.getTypeTransformer().transformToType(anyMember.getType().getPsiType());
}
JetType receiverType;
if (anyMember.getReceiverType() == null) {
receiverType = null;
} else if (anyMember.getReceiverType().getTypeString().length() > 0) {
receiverType = semanticServices.getTypeTransformer().transformToType(anyMember.getReceiverType().getTypeString(), typeVariableResolverForPropertyInternals);
} else {
receiverType = semanticServices.getTypeTransformer().transformToType(anyMember.getReceiverType().getPsiType());
}
propertyDescriptor.setType(
propertyType,
typeParameters,
DescriptorUtils.getExpectedThisObjectIfNeeded(owner),
receiverType
); );
if (getterDescriptor != null) { if (getterDescriptor != null) {
getterDescriptor.initialize(type); getterDescriptor.initialize(propertyType);
} }
if (setterDescriptor != null) { if (setterDescriptor != null) {
// TODO: initialize // TODO: initialize
}
semanticServices.getTrace().record(BindingContext.VARIABLE, anyMember.getMember().psiMember, propertyDescriptor);
r.add(propertyDescriptor);
} }
semanticServices.getTrace().record(BindingContext.VARIABLE, anyMember.psiMember, propertyDescriptor); namedMembers.propertyDescriptors = r;
namedMembers.propertyDescriptors = Collections.<VariableDescriptor>singleton(propertyDescriptor);
} }
private void resolveNamedGroupFunctions(DeclarationDescriptor owner, PsiClass psiClass, TypeSubstitutor typeSubstitutorForGenericSuperclasses, boolean staticMembers, NamedMembers namedMembers, String functionName) { private void resolveNamedGroupFunctions(DeclarationDescriptor owner, PsiClass psiClass, TypeSubstitutor typeSubstitutorForGenericSuperclasses, boolean staticMembers, NamedMembers namedMembers, String functionName) {
@@ -1145,7 +1220,7 @@ public class JavaDescriptorResolver {
private List<TypeParameterDescriptor> resolveMethodTypeParameters( private List<TypeParameterDescriptor> resolveMethodTypeParameters(
@NotNull PsiMethodWrapper method, @NotNull PsiMethodWrapper method,
@NotNull FunctionDescriptor functionDescriptor, @NotNull DeclarationDescriptor functionDescriptor,
@NotNull TypeVariableResolver classTypeVariableResolver) { @NotNull TypeVariableResolver classTypeVariableResolver) {
if (method.getJetMethod().typeParameters().length() > 0) { if (method.getJetMethod().typeParameters().length() > 0) {
List<TypeParameterDescriptor> r = resolveMethodTypeParametersFromJetSignature( List<TypeParameterDescriptor> r = resolveMethodTypeParametersFromJetSignature(
@@ -1163,7 +1238,7 @@ public class JavaDescriptorResolver {
* @see #resolveClassTypeParametersFromJetSignature(String, com.intellij.psi.PsiClass, MutableClassDescriptorLite) * @see #resolveClassTypeParametersFromJetSignature(String, com.intellij.psi.PsiClass, MutableClassDescriptorLite)
*/ */
private List<TypeParameterDescriptor> resolveMethodTypeParametersFromJetSignature(String jetSignature, final PsiMethod method, private List<TypeParameterDescriptor> resolveMethodTypeParametersFromJetSignature(String jetSignature, final PsiMethod method,
final FunctionDescriptor functionDescriptor, final TypeVariableResolver classTypeVariableResolver) final DeclarationDescriptor functionDescriptor, final TypeVariableResolver classTypeVariableResolver)
{ {
final List<TypeParameterDescriptor> r = new ArrayList<TypeParameterDescriptor>(); final List<TypeParameterDescriptor> r = new ArrayList<TypeParameterDescriptor>();
@@ -54,11 +54,8 @@ class JavaDescriptorResolverHelper {
NamedMembers namedMembers = getNamedMembers(field.getName()); NamedMembers namedMembers = getNamedMembers(field.getName());
MembersForProperty members = new MembersForProperty(); TypeSource type = new TypeSource("", field.getType());
members.field = field; namedMembers.addPropertyAccessor(new PropertyAccessorData(field, type, null));
members.type = new TypeSource("", field.getType());
namedMembers.properties = members;
} }
} }
} }
@@ -110,12 +107,11 @@ class JavaDescriptorResolverHelper {
String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.GETTER_PREFIX.length())); String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.GETTER_PREFIX.length()));
NamedMembers members = getNamedMembers(propertyName); NamedMembers members = getNamedMembers(propertyName);
members.getForProperty().getter = method;
// TODO: check conflicts with setter
// TODO: what if returnType == null? // TODO: what if returnType == null?
members.getForProperty().type = new TypeSource(method.getJetMethod().propertyType(), method.getReturnType()); TypeSource propertyType = new TypeSource(method.getJetMethod().propertyType(), method.getReturnType());
members.getForProperty().receiverType = receiverType;
members.addPropertyAccessor(new PropertyAccessorData(method, true, propertyType, receiverType));
} }
} else if (method.getName().startsWith(JvmAbi.SETTER_PREFIX)) { } else if (method.getName().startsWith(JvmAbi.SETTER_PREFIX)) {
@@ -147,11 +143,8 @@ class JavaDescriptorResolverHelper {
String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.SETTER_PREFIX.length())); String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.SETTER_PREFIX.length()));
NamedMembers members = getNamedMembers(propertyName); NamedMembers members = getNamedMembers(propertyName);
members.getForProperty().setter = method;
// TODO: check conflicts with getter members.addPropertyAccessor(new PropertyAccessorData(method, false, propertyType, receiverType));
members.getForProperty().type = propertyType;
members.getForProperty().receiverType = receiverType;
} }
} }
@@ -1,13 +0,0 @@
package org.jetbrains.jet.lang.resolve.java;
/**
* @author Stepan Koltsov
*/
class MembersForProperty {
PsiFieldWrapper field;
PsiMethodWrapper setter;
PsiMethodWrapper getter;
TypeSource type;
TypeSource receiverType;
}
@@ -17,25 +17,29 @@ import java.util.Set;
class NamedMembers { class NamedMembers {
String name; String name;
List<PsiMethodWrapper> methods; List<PsiMethodWrapper> methods;
@Nullable @Nullable
MembersForProperty properties; PsiFieldWrapper field;
@Nullable
List<PropertyAccessorData> propertyAccessors;
@Nullable @Nullable
private PsiClass nestedClasses; private PsiClass nestedClasses;
Set<VariableDescriptor> propertyDescriptors; Set<VariableDescriptor> propertyDescriptors;
Set<FunctionDescriptor> functionDescriptors; Set<FunctionDescriptor> functionDescriptors;
MembersForProperty getForProperty() {
if (properties == null) {
properties = new MembersForProperty();
}
return properties;
}
void addMethod(PsiMethodWrapper method) { void addMethod(PsiMethodWrapper method) {
if (methods == null) { if (methods == null) {
methods = new ArrayList<PsiMethodWrapper>(); methods = new ArrayList<PsiMethodWrapper>();
} }
methods.add(method); methods.add(method);
} }
void addPropertyAccessor(PropertyAccessorData propertyAccessorData) {
if (propertyAccessors == null) {
propertyAccessors = new ArrayList<PropertyAccessorData>();
}
propertyAccessors.add(propertyAccessorData);
}
} }
@@ -0,0 +1,63 @@
package org.jetbrains.jet.lang.resolve.java;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author Stepan Koltsov
*/
class PropertyAccessorData {
@NotNull
private final PsiMemberWrapper member;
private final boolean getter;
@NotNull
private final TypeSource type;
@Nullable
private final TypeSource receiverType;
PropertyAccessorData(@NotNull PsiMethodWrapper method, boolean getter, @NotNull TypeSource type, @Nullable TypeSource receiverType) {
this.member = method;
this.type = type;
this.receiverType = receiverType;
this.getter = getter;
}
PropertyAccessorData(@NotNull PsiFieldWrapper field, @NotNull TypeSource type, @Nullable TypeSource receiverType) {
this.member = field;
this.type = type;
this.receiverType = receiverType;
this.getter = false;
}
@NotNull
public PsiMemberWrapper getMember() {
return member;
}
@NotNull
public TypeSource getType() {
return type;
}
@Nullable
public TypeSource getReceiverType() {
return receiverType;
}
public boolean isGetter() {
return member instanceof PsiMethodWrapper && getter;
}
public boolean isSetter() {
return member instanceof PsiMethodWrapper && !getter;
}
public boolean isField() {
return member instanceof PsiFieldWrapper;
}
}
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull;
/** /**
* @author Stepan Koltsov * @author Stepan Koltsov
*/ */
public class PsiMemberWrapper { public abstract class PsiMemberWrapper {
@NotNull @NotNull
protected final PsiMember psiMember; protected final PsiMember psiMember;
@@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.jet.lang.types.DescriptorSubstitutor; import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
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.TypeSubstitutor; import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lang.types.Variance;
@@ -37,6 +38,15 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
private List<TypeParameterDescriptor> typeParemeters; private List<TypeParameterDescriptor> typeParemeters;
private PropertyGetterDescriptor getter; private PropertyGetterDescriptor getter;
private PropertySetterDescriptor setter; private PropertySetterDescriptor setter;
private PropertyDescriptor() {
super(ErrorUtils.getErrorClass(), Collections.<AnnotationDescriptor>emptyList(), "dummy");
this.modality = null;
this.visibility = null;
this.isVar = false;
this.isObject = false;
this.original = null;
}
private PropertyDescriptor( private PropertyDescriptor(
@Nullable PropertyDescriptor original, @Nullable PropertyDescriptor original,
@@ -243,4 +253,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab
propertyDescriptor.initialize(newGetter, newSetter); propertyDescriptor.initialize(newGetter, newSetter);
return propertyDescriptor; return propertyDescriptor;
} }
public static PropertyDescriptor createDummy() {
return new PropertyDescriptor();
}
} }
@@ -0,0 +1,8 @@
package test
var Int.junk: Short
get() = throw Exception()
set(p: Short) = throw Exception()
val String.junk: Int
get() = throw Exception()