diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 82527060e2a..1554b9732f5 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; @@ -15,9 +16,12 @@ import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.PsiPackage; +import com.intellij.psi.PsiPrimitiveType; import com.intellij.psi.PsiType; import com.intellij.psi.PsiTypeParameter; 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.GlobalSearchScope; import jet.typeinfo.TypeInfoVariance; @@ -60,6 +64,7 @@ import org.jetbrains.jet.rt.signature.JetSignatureVisitor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -800,7 +805,7 @@ public class JavaDescriptorResolver { Map membersForProperties = scopeData.namedMembersMap; for (Map.Entry entry : membersForProperties.entrySet()) { NamedMembers namedMembers = entry.getValue(); - if (namedMembers.properties == null) { + if (namedMembers.propertyAccessors == null) { continue; } @@ -811,126 +816,196 @@ public class JavaDescriptorResolver { } 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) { if (namedMembers.propertyDescriptors != null) { return; } - if (namedMembers.properties == null) { + if (namedMembers.propertyAccessors == null) { namedMembers.propertyDescriptors = Collections.emptySet(); 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.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.emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false); - } - if (members.setter != null) { - setterDescriptor = new PropertySetterDescriptor(propertyDescriptor, Collections.emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false); - } - - propertyDescriptor.initialize(getterDescriptor, setterDescriptor); - final List classTypeParameters; - if (anyMember instanceof PsiMethodWrapper && !anyMember.isStatic()) { + if (!staticMembers) { classTypeParameters = ((ClassDescriptor) owner).getTypeConstructor().getParameters(); } else { classTypeParameters = new ArrayList(0); } + TypeParameterListTypeVariableResolver typeVariableResolver = new TypeParameterListTypeVariableResolver(classTypeParameters); - - List typeParameters = new ArrayList(0); - - if (members.setter != null) { - // call ugly code with side effects - typeParameters = resolveMethodTypeParameters(members.setter, propertyDescriptor.getSetter(), typeVariableResolver); - } - if (members.getter != null) { - // call ugly code with side effects - typeParameters = resolveMethodTypeParameters(members.getter, propertyDescriptor.getGetter(), typeVariableResolver); + + class GroupingValue { + PropertyAccessorData getter; + PropertyAccessorData setter; + PropertyAccessorData field; } - List typeParametersForReceiver = new ArrayList(); - typeParametersForReceiver.addAll(classTypeParameters); - typeParametersForReceiver.addAll(typeParameters); + Map map = new HashMap(); + + 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; - if (receiver == null) { - receiverJetType = null; - } else if (receiver.getTypeString().length() > 0) { - receiverJetType = semanticServices.getTypeTransformer().transformToType(receiver.getTypeString(), typeVariableResolverForPropertyInternals); - } else { - receiverJetType = semanticServices.getTypeTransformer().transformToType(receiver.getPsiType()); - } + Set r = new HashSet(); + + for (GroupingValue members : map.values()) { + boolean isFinal; + if (members.setter == null && members.getter == null) { + isFinal = false; + } 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; - if (propertyType.getTypeString().length() > 0) { - type = semanticServices.getTypeTransformer().transformToType(propertyType.getTypeString(), typeVariableResolverForPropertyInternals); - } else { - type = semanticServices.getTypeTransformer().transformToType(propertyType.getPsiType()); - } + PropertyAccessorData 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(); + } - propertyDescriptor.setType( - type, - typeParameters, - DescriptorUtils.getExpectedThisObjectIfNeeded(owner), - receiverJetType + boolean isVar; + if (members.getter == null && members.setter == null) { + isVar = !members.field.getMember().isFinal(); + } else { + isVar = members.setter != null; + } + + PropertyDescriptor propertyDescriptor = new PropertyDescriptor( + owner, + Collections.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.emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false); + } + if (members.setter != null) { + setterDescriptor = new PropertySetterDescriptor(propertyDescriptor, Collections.emptyList(), Modality.OPEN, Visibility.PUBLIC, true, false); + } + + propertyDescriptor.initialize(getterDescriptor, setterDescriptor); + + List typeParameters = new ArrayList(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 typeParametersForReceiver = new ArrayList(); + 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) { - getterDescriptor.initialize(type); - } - if (setterDescriptor != null) { - // TODO: initialize + if (getterDescriptor != null) { + getterDescriptor.initialize(propertyType); + } + if (setterDescriptor != null) { + // TODO: initialize + } + + semanticServices.getTrace().record(BindingContext.VARIABLE, anyMember.getMember().psiMember, propertyDescriptor); + + r.add(propertyDescriptor); } - semanticServices.getTrace().record(BindingContext.VARIABLE, anyMember.psiMember, propertyDescriptor); - namedMembers.propertyDescriptors = Collections.singleton(propertyDescriptor); + namedMembers.propertyDescriptors = r; } private void resolveNamedGroupFunctions(DeclarationDescriptor owner, PsiClass psiClass, TypeSubstitutor typeSubstitutorForGenericSuperclasses, boolean staticMembers, NamedMembers namedMembers, String functionName) { @@ -1145,7 +1220,7 @@ public class JavaDescriptorResolver { private List resolveMethodTypeParameters( @NotNull PsiMethodWrapper method, - @NotNull FunctionDescriptor functionDescriptor, + @NotNull DeclarationDescriptor functionDescriptor, @NotNull TypeVariableResolver classTypeVariableResolver) { if (method.getJetMethod().typeParameters().length() > 0) { List r = resolveMethodTypeParametersFromJetSignature( @@ -1163,7 +1238,7 @@ public class JavaDescriptorResolver { * @see #resolveClassTypeParametersFromJetSignature(String, com.intellij.psi.PsiClass, MutableClassDescriptorLite) */ private List resolveMethodTypeParametersFromJetSignature(String jetSignature, final PsiMethod method, - final FunctionDescriptor functionDescriptor, final TypeVariableResolver classTypeVariableResolver) + final DeclarationDescriptor functionDescriptor, final TypeVariableResolver classTypeVariableResolver) { final List r = new ArrayList(); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java index ad6a89d8e78..fb920e33dd5 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolverHelper.java @@ -54,11 +54,8 @@ class JavaDescriptorResolverHelper { NamedMembers namedMembers = getNamedMembers(field.getName()); - MembersForProperty members = new MembersForProperty(); - members.field = field; - members.type = new TypeSource("", field.getType()); - - namedMembers.properties = members; + TypeSource type = new TypeSource("", field.getType()); + namedMembers.addPropertyAccessor(new PropertyAccessorData(field, type, null)); } } } @@ -110,12 +107,11 @@ class JavaDescriptorResolverHelper { String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.GETTER_PREFIX.length())); NamedMembers members = getNamedMembers(propertyName); - members.getForProperty().getter = method; - // TODO: check conflicts with setter // TODO: what if returnType == null? - members.getForProperty().type = new TypeSource(method.getJetMethod().propertyType(), method.getReturnType()); - members.getForProperty().receiverType = receiverType; + TypeSource propertyType = new TypeSource(method.getJetMethod().propertyType(), method.getReturnType()); + + members.addPropertyAccessor(new PropertyAccessorData(method, true, propertyType, receiverType)); } } 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())); NamedMembers members = getNamedMembers(propertyName); - members.getForProperty().setter = method; - // TODO: check conflicts with getter - members.getForProperty().type = propertyType; - members.getForProperty().receiverType = receiverType; + members.addPropertyAccessor(new PropertyAccessorData(method, false, propertyType, receiverType)); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/MembersForProperty.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/MembersForProperty.java deleted file mode 100644 index 99728ccecc1..00000000000 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/MembersForProperty.java +++ /dev/null @@ -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; -} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/NamedMembers.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/NamedMembers.java index 7da0943b814..badb223ae35 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/NamedMembers.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/NamedMembers.java @@ -17,25 +17,29 @@ import java.util.Set; class NamedMembers { String name; List methods; + @Nullable - MembersForProperty properties; + PsiFieldWrapper field; + @Nullable + List propertyAccessors; + @Nullable private PsiClass nestedClasses; Set propertyDescriptors; Set functionDescriptors; - MembersForProperty getForProperty() { - if (properties == null) { - properties = new MembersForProperty(); - } - return properties; - } - void addMethod(PsiMethodWrapper method) { if (methods == null) { methods = new ArrayList(); } methods.add(method); } + + void addPropertyAccessor(PropertyAccessorData propertyAccessorData) { + if (propertyAccessors == null) { + propertyAccessors = new ArrayList(); + } + propertyAccessors.add(propertyAccessorData); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PropertyAccessorData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PropertyAccessorData.java new file mode 100644 index 00000000000..e792ddc510e --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PropertyAccessorData.java @@ -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; + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PsiMemberWrapper.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PsiMemberWrapper.java index 065599d315b..7c6a2b40745 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PsiMemberWrapper.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/PsiMemberWrapper.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; /** * @author Stepan Koltsov */ -public class PsiMemberWrapper { +public abstract class PsiMemberWrapper { @NotNull protected final PsiMember psiMember; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index 6e7420483f1..b535e241b16 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -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.TransientReceiver; 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.TypeSubstitutor; import org.jetbrains.jet.lang.types.Variance; @@ -37,6 +38,15 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab private List typeParemeters; private PropertyGetterDescriptor getter; private PropertySetterDescriptor setter; + + private PropertyDescriptor() { + super(ErrorUtils.getErrorClass(), Collections.emptyList(), "dummy"); + this.modality = null; + this.visibility = null; + this.isVar = false; + this.isObject = false; + this.original = null; + } private PropertyDescriptor( @Nullable PropertyDescriptor original, @@ -243,4 +253,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Callab propertyDescriptor.initialize(newGetter, newSetter); return propertyDescriptor; } + + public static PropertyDescriptor createDummy() { + return new PropertyDescriptor(); + } } diff --git a/compiler/testData/readKotlinBinaryClass/prop/ExtVarl.kt b/compiler/testData/readKotlinBinaryClass/prop/ExtVarl.kt new file mode 100644 index 00000000000..d4900f45565 --- /dev/null +++ b/compiler/testData/readKotlinBinaryClass/prop/ExtVarl.kt @@ -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()