diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 4a5076272ea..af17585cdef 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -16,6 +16,7 @@ import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.java.JavaNamespaceDescriptor; +import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; @@ -2597,10 +2598,10 @@ If finally block is present, its last expression is the value of try expression. genTypeInfoToProjection(v, argument.getProjectionKind()); v.astore(TYPE_OBJECT); } - v.invokestatic("jet/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/TypeInfo;"); + v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/TypeInfo;"); } else { - v.invokestatic("jet/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/TypeInfo;"); + v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z)Ljet/TypeInfo;"); } } @@ -2654,7 +2655,7 @@ If finally block is present, its last expression is the value of try expression. } else { v.load(0, TYPE_OBJECT); - v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), "getTypeInfo", "()Ljet/TypeInfo;"); + v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;"); } } else { @@ -2663,7 +2664,7 @@ If finally block is present, its last expression is the value of try expression. descriptor = CodegenUtil.getOuterClassDescriptor(descriptor); v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), "getOuterObject", "()Ljet/JetObject;"); } - v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), "getTypeInfo", "()Ljet/TypeInfo;"); + v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;"); } v.aconst(ownerType); v.iconst(typeParameterDescriptor.getIndex()); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index cc003056a60..1417c32108a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -240,6 +240,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method method = typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION).getAsmMethod(); Method originalMethod = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION).getAsmMethod(); MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC|Opcodes.ACC_BRIDGE|Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null); + mv.visitAnnotation(JvmStdlibNames.JET_PROPERTY.getDescriptor(), true).visitEnd(); InstructionAdapter iv = null; if (v.generateCode()) { mv.visitCode(); @@ -259,6 +260,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { method = typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION).getAsmMethod(); originalMethod = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION).getAsmMethod(); mv = v.newMethod(null, Opcodes.ACC_PUBLIC|Opcodes.ACC_BRIDGE|Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null); + mv.visitAnnotation(JvmStdlibNames.JET_PROPERTY.getDescriptor(), true).visitEnd(); if (v.generateCode()) { mv.visitCode(); @@ -838,7 +840,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if(!CodegenUtil.hasDerivedTypeInfoField(defaultType)) { v.newField(myClass, Opcodes.ACC_PROTECTED, "$typeInfo", "Ljet/TypeInfo;", null, null); - MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/TypeInfo;", null, null); + MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;", null, null); if (v.generateCode()) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); @@ -846,7 +848,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.load(0, JetTypeMapper.TYPE_OBJECT); iv.getfield(owner, "$typeInfo", "Ljet/TypeInfo;"); iv.areturn(JetTypeMapper.TYPE_TYPEINFO); - FunctionCodegen.endVisit(iv, "getTypeInfo", myClass); + FunctionCodegen.endVisit(iv, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, myClass); } mv = v.newMethod(myClass, Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, "$setTypeInfo", "(Ljet/TypeInfo;)V", null, null); @@ -869,14 +871,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void genGetStaticGetTypeInfoMethod() { - final MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/TypeInfo;", null, null); + final MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;", null, null); if (v.generateCode()) { mv.visitCode(); InstructionAdapter v = new InstructionAdapter(mv); String owner = typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(); v.getstatic(owner, "$staticTypeInfo", "Ljet/TypeInfo;"); v.areturn(JetTypeMapper.TYPE_TYPEINFO); - FunctionCodegen.endVisit(v, "getTypeInfo", myClass); + FunctionCodegen.endVisit(v, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, myClass); } } @@ -887,7 +889,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { public void generate(InstructionAdapter v) { v.aconst(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION)); v.iconst(0); - v.invokestatic("jet/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/TypeInfo;"); + v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z)Ljet/TypeInfo;"); v.putstatic(typeMapper.mapType(descriptor.getDefaultType(), kind).getInternalName(), "$staticTypeInfo", "Ljet/TypeInfo;"); } }); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 25157eaf5b1..29ec1038894 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; @@ -181,10 +182,10 @@ public class NamespaceCodegen { ExpressionCodegen.genTypeInfoToProjection(v, argument.getProjectionKind()); v.astore(JetTypeMapper.TYPE_OBJECT); } - v.invokestatic("jet/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/TypeInfo;"); + v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/TypeInfo;"); } else { - v.invokestatic("jet/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/TypeInfo;"); + v.invokestatic("jet/TypeInfo", JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "(Ljava/lang/Class;Z)Ljet/TypeInfo;"); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 75ee1e431fd..a4683e2c2ae 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -140,6 +141,7 @@ public class PropertyCodegen { final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor, kind).getAsmMethod().getDescriptor(); String getterName = getterName(propertyDescriptor.getName()); MethodVisitor mv = v.newMethod(origin, flags, getterName, signature, null, null); + mv.visitAnnotation(JvmStdlibNames.JET_PROPERTY.getDescriptor(), true).visitEnd(); if (v.generateCode() && (!isTrait || kind instanceof OwnerKind.DelegateKind)) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); @@ -184,6 +186,7 @@ public class PropertyCodegen { final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor, kind).getAsmMethod().getDescriptor(); MethodVisitor mv = v.newMethod(origin, flags, setterName(propertyDescriptor.getName()), signature, null, null); + mv.visitAnnotation(JvmStdlibNames.JET_PROPERTY.getDescriptor(), true).visitEnd(); if (v.generateCode() && (!isTrait || kind instanceof OwnerKind.DelegateKind)) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java index e23574d29f7..8d38bd3b528 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java @@ -5,6 +5,8 @@ import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -17,7 +19,7 @@ public class ValueTypeInfo implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { codegen.gen(arguments.get(0), JetTypeMapper.TYPE_JET_OBJECT); - v.invokeinterface(JetTypeMapper.TYPE_JET_OBJECT.getInternalName(), "getTypeInfo", "()Ljet/TypeInfo;"); + v.invokeinterface(JetTypeMapper.TYPE_JET_OBJECT.getInternalName(), JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;"); return StackValue.onStack(JetTypeMapper.TYPE_TYPEINFO); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java index 1753b072141..b50c6ec59b0 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java @@ -21,7 +21,7 @@ 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> variables = Maps.newHashMap(); private final Map classifiers = Maps.newHashMap(); private Collection allDescriptors; @@ -77,13 +77,7 @@ public class JavaClassMembersScope implements JetScope { } } - for (PsiField field : psiClass.getAllFields()) { - if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) { - continue; - } - VariableDescriptor variableDescriptor = semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field); - allDescriptors.add(variableDescriptor); - } + allDescriptors.addAll(semanticServices.getDescriptorResolver().resolveFieldGroup(containingDeclaration, psiClass, staticMembers)); } return allDescriptors; } @@ -116,14 +110,14 @@ public class JavaClassMembersScope implements JetScope { @NotNull @Override public Set getProperties(@NotNull String name) { - VariableDescriptor variableDescriptor = variables.get(name); + Set variableDescriptor = variables.get(name); if (variableDescriptor == null) { variableDescriptor = doGetVariable(name); if (variableDescriptor != null) { variables.put(name, variableDescriptor); } } - return variableDescriptor != null ? Collections.singleton(variableDescriptor) : Collections.emptySet(); + return variableDescriptor != null ? variableDescriptor : Collections.emptySet(); } @Override @@ -132,14 +126,15 @@ public class JavaClassMembersScope implements JetScope { } @Nullable - private VariableDescriptor doGetVariable(String name) { + private Set doGetVariable(String name) { PsiField field = psiClass.findFieldByName(name, true); if (field == null) return null; if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) { return null; } - return semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field); + //return semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field); + return semanticServices.getDescriptorResolver().resolveFieldGroupByName(containingDeclaration, psiClass, name, staticMembers); } @NotNull 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 d19cdebc3ef..fb9e23b0585 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.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.DelegatingGlobalSearchScope; @@ -85,8 +86,14 @@ public class JavaDescriptorResolver { this.lowerBoundsForKotlin = lowerBoundsForKotlin; } } + + private static abstract class ResolverScopeData { + @Nullable + private Set properties; + private boolean kotlin; + } - private static class ResolverClassData { + private static class ResolverClassData extends ResolverScopeData { private JavaClassDescriptor classDescriptor; private boolean kotlin; @@ -96,7 +103,7 @@ public class JavaDescriptorResolver { } } - private static class ResolverNamespaceData { + private static class ResolverNamespaceData extends ResolverScopeData { private JavaNamespaceDescriptor namespaceDescriptor; private boolean kotlin; @@ -751,6 +758,7 @@ public class JavaDescriptorResolver { } } + /* public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) { VariableDescriptor variableDescriptor = fieldDescriptorCache.get(field); if (variableDescriptor != null) { @@ -772,6 +780,200 @@ public class JavaDescriptorResolver { fieldDescriptorCache.put(field, propertyDescriptor); return propertyDescriptor; } + */ + + private static class PropertyKey { + @NotNull + private final String name; + @NotNull + private final PsiType type; + + private PropertyKey(String name, PsiType type) { + this.name = name; + this.type = type; + } + + @Override + public boolean equals(Object o) { + // generated by Idea + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + PropertyKey that = (PropertyKey) o; + + if (!name.equals(that.name)) return false; + if (!type.equals(that.type)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + type.hashCode(); + return result; + } + } + + private static class MembersForProperty { + private PsiField field; + private PsiMethod setter; + private PsiMethod getter; + } + + private Map getMembersForProperties(@NotNull PsiClass clazz, boolean staticMembers, boolean kotlin) { + Map membersMap = Maps.newHashMap(); + if (!kotlin) { + for (PsiField field : clazz.getFields()) { + if (field.getModifierList().hasExplicitModifier(PsiModifier.STATIC) != staticMembers) { + continue; + } + + if (field.hasModifierProperty(PsiModifier.PRIVATE)) { + continue; + } + + MembersForProperty members = new MembersForProperty(); + members.field = field; + membersMap.put(new PropertyKey(field.getName(), field.getType()), members); + } + } + + for (PsiMethod method : clazz.getMethods()) { + if (method.getModifierList().hasExplicitModifier(PsiModifier.STATIC) != staticMembers) { + continue; + } + + if (method.hasModifierProperty(PsiModifier.PRIVATE)) { + continue; + } + + // TODO: "is" prefix + if (method.getName().startsWith(JvmAbi.GETTER_PREFIX)) { + // TODO: some java properties too + if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null) { + if (method.getParameterList().getParametersCount() == 0) { + if (method.getName().equals(JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD)) { + continue; + } + + String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.GETTER_PREFIX.length())); + PropertyKey key = new PropertyKey(propertyName, method.getReturnType()); + MembersForProperty members = membersMap.get(key); + if (members == null) { + members = new MembersForProperty(); + membersMap.put(key, members); + } + members.getter = method; + } + } + } else if (method.getName().startsWith(JvmAbi.SETTER_PREFIX)) { + if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null) { + if (method.getParameterList().getParametersCount() == 1) { + String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.SETTER_PREFIX.length())); + PropertyKey key = new PropertyKey(propertyName, method.getParameterList().getParameters()[0].getType()); + MembersForProperty members = membersMap.get(key); + if (members == null) { + members = new MembersForProperty(); + membersMap.put(key, members); + } + members.setter = method; + } + } + } + } + + return membersMap; + } + + public Set resolveFieldGroupByName(@NotNull DeclarationDescriptor owner, PsiClass psiClass, String fieldName, boolean staticMembers) { + Set r = Sets.newHashSet(); + // TODO: slow + Set variables = resolveFieldGroup(owner, psiClass, staticMembers); + for (VariableDescriptor variable : variables) { + if (variable.getName().equals(fieldName)) { + r.add(variable); + } + } + return r; + } + + @NotNull + public Set resolveFieldGroup(@NotNull DeclarationDescriptor owner, PsiClass psiClass, boolean staticMembers) { + + ResolverScopeData scopeData; + if (owner instanceof JavaNamespaceDescriptor) { + scopeData = namespaceDescriptorCacheByFqn.get(((JavaNamespaceDescriptor) owner).getQualifiedName()); + } else if (owner instanceof JavaClassDescriptor) { + scopeData = classDescriptorCache.get(psiClass.getQualifiedName()); + } else { + throw new IllegalStateException(); + } + if (scopeData == null) { + throw new IllegalStateException(); + } + + if (scopeData.properties != null) { + return scopeData.properties; + } + + Set descriptors = Sets.newHashSet(); + for (Map.Entry entry : getMembersForProperties(psiClass, staticMembers, scopeData.kotlin).entrySet()) { + //VariableDescriptor variableDescriptor = fieldDescriptorCache.get(field); + //if (variableDescriptor != null) { + // return variableDescriptor; + //} + String propertyName = entry.getKey().name; + PsiType propertyType = entry.getKey().type; + MembersForProperty members = entry.getValue(); + + JetType type = semanticServices.getTypeTransformer().transformToType(propertyType); + boolean isFinal; + if (members.setter == null && members.getter == null) { + isFinal = members.field.hasModifierProperty(PsiModifier.FINAL); + } else if (members.getter != null) { + isFinal = members.getter.hasModifierProperty(PsiModifier.FINAL); + } else if (members.setter != null) { + isFinal = members.setter.hasModifierProperty(PsiModifier.FINAL); + } else { + isFinal = false; + } + + PsiMember 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 = true; + } else { + isVar = members.setter != null; + } + + PropertyDescriptor propertyDescriptor = new PropertyDescriptor( + owner, + Collections.emptyList(), + isFinal && !staticMembers ? Modality.FINAL : Modality.OPEN, // TODO: abstract + resolveVisibilityFromPsiModifiers(anyMember), + isVar, + null, + DescriptorUtils.getExpectedThisObjectIfNeeded(owner), + propertyName, + type); + semanticServices.getTrace().record(BindingContext.VARIABLE, anyMember, propertyDescriptor); + //fieldDescriptorCache.put(field, propertyDescriptor); + descriptors.add(propertyDescriptor); + } + scopeData.properties = descriptors; + return descriptors; + } @NotNull public Set resolveFunctionGroup(@NotNull DeclarationDescriptor owner, @NotNull PsiClass psiClass, @Nullable ClassDescriptor classDescriptor, @NotNull String methodName, boolean staticMembers) { @@ -870,10 +1072,12 @@ public class JavaDescriptorResolver { // TODO: hide getters and setters properly if (kotlin) { if (method.getName().startsWith(JvmAbi.GETTER_PREFIX) && method.getParameterList().getParametersCount() == 0) { - return null; + if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null) + return null; } if (method.getName().startsWith(JvmAbi.SETTER_PREFIX) && method.getParameterList().getParametersCount() == 1) { - return null; + if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null) + return null; } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 4abedd07c27..5f63f119133 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -90,7 +90,7 @@ public class JavaPackageScope extends JetScopeImpl { } // TODO: cache - return Collections.singleton(semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDescriptor, field)); + return semanticServices.getDescriptorResolver().resolveFieldGroupByName(containingDescriptor, psiClassForPackage, name, true); } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmStdlibNames.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmStdlibNames.java index f94405a8214..355db7e1e68 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmStdlibNames.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmStdlibNames.java @@ -26,6 +26,8 @@ public class JvmStdlibNames { public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType"; public static final String JET_METHOD_RETURN_TYPE_FIELD = "returnType"; public static final String JET_METHOD_TYPE_PARAMETERS_FIELD = "typeParameters"; + + public static final JvmClassName JET_PROPERTY = new JvmClassName("jet.typeinfo.JetProperty"); public static final JvmClassName JET_CLASS = new JvmClassName("jet.typeinfo.JetClass"); @@ -34,6 +36,8 @@ public class JvmStdlibNames { public static final JvmClassName JET_OBJECT = new JvmClassName("jet.JetObject"); + + public static final String JET_OBJECT_GET_TYPEINFO_METHOD = "getTypeInfo"; private JvmStdlibNames() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java index 6c634b3f81c..9716e1234a8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java @@ -118,7 +118,9 @@ public class DataFlowValueFactory { if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false; } else { - assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable"; + if (propertyDescriptor.getModality().isOverridable()) { + throw new IllegalStateException("Property outside a class must not be overridable: " + propertyDescriptor.getName()); + } } return true; } diff --git a/compiler/testData/readClass/fun/nonGeneric/ClassFunGetFoo.kt b/compiler/testData/readClass/fun/nonGeneric/ClassFunGetFoo.kt new file mode 100644 index 00000000000..7ec2abd7585 --- /dev/null +++ b/compiler/testData/readClass/fun/nonGeneric/ClassFunGetFoo.kt @@ -0,0 +1,5 @@ +package test + +class ClassFunGetFoo { + fun getFoo() = 1 +} diff --git a/compiler/testData/readClass/fun/nonGeneric/ClassFunGetFooSetFoo.kt b/compiler/testData/readClass/fun/nonGeneric/ClassFunGetFooSetFoo.kt new file mode 100644 index 00000000000..e6dc4f9402b --- /dev/null +++ b/compiler/testData/readClass/fun/nonGeneric/ClassFunGetFooSetFoo.kt @@ -0,0 +1,6 @@ +package test + +class ClassFunGetFoo { + fun getFoo() = 1 + fun setFoo(p: Int) {} +} diff --git a/compiler/testData/readClass/fun/nonGeneric/ClassFunSetFoo.kt b/compiler/testData/readClass/fun/nonGeneric/ClassFunSetFoo.kt new file mode 100644 index 00000000000..f86435621cf --- /dev/null +++ b/compiler/testData/readClass/fun/nonGeneric/ClassFunSetFoo.kt @@ -0,0 +1,5 @@ +package test + +class ClassFunGetFoo { + fun set(p: Int) { } +} diff --git a/compiler/testData/readClass/fun/nonGeneric/NsFunGetFoo.kt b/compiler/testData/readClass/fun/nonGeneric/NsFunGetFoo.kt new file mode 100644 index 00000000000..ad76ad8f3eb --- /dev/null +++ b/compiler/testData/readClass/fun/nonGeneric/NsFunGetFoo.kt @@ -0,0 +1,3 @@ +package test + +fun getFoo() = 1 diff --git a/compiler/testData/readClass/prop/ClassValAbstract.kt b/compiler/testData/readClass/prop/ClassValAbstract.kt new file mode 100644 index 00000000000..890039b0432 --- /dev/null +++ b/compiler/testData/readClass/prop/ClassValAbstract.kt @@ -0,0 +1,5 @@ +package test + +abstract class ClassValAbstract { + abstract val a: Int +} diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index d91f83f7123..e366691c577 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -125,6 +125,7 @@ public class ReadClassDataTest extends UsefulTestCase { for (DeclarationDescriptor ad : nsa.getMemberScope().getAllDescriptors()) { if (ad instanceof ClassifierDescriptor) { ClassifierDescriptor bd = nsb.getMemberScope().getClassifier(ad.getName()); + Assert.assertTrue("classifier not found: " + ad.getName(), bd != null); compareClassifiers((ClassifierDescriptor) ad, bd); Assert.assertNull(nsb.getMemberScope().getClassifier(ad.getName() + JvmAbi.TRAIT_IMPL_SUFFIX)); @@ -136,7 +137,7 @@ public class ReadClassDataTest extends UsefulTestCase { compareDescriptors(ad, bd); } else if (ad instanceof PropertyDescriptor) { Set properties = nsb.getMemberScope().getProperties(ad.getName()); - Assert.assertTrue(properties.size() >= 1); + Assert.assertTrue("property not found by name: " + ad.getName(), properties.size() >= 1); Assert.assertTrue("not implemented", properties.size() == 1); PropertyDescriptor bd = (PropertyDescriptor) properties.iterator().next(); compareDescriptors(ad, bd); diff --git a/stdlib/src/jet/typeinfo/JetProperty.java b/stdlib/src/jet/typeinfo/JetProperty.java new file mode 100644 index 00000000000..15f1f18084c --- /dev/null +++ b/stdlib/src/jet/typeinfo/JetProperty.java @@ -0,0 +1,14 @@ +package jet.typeinfo; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Stepan Koltsov + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JetProperty { +}