From 1bb58286130b40c93d4454f7b90e1b1a28bf7284 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 30 Dec 2011 00:05:32 +0400 Subject: [PATCH] reading properties info from binary classes Add final modifier to val backing field --- .../jet/codegen/PropertyCodegen.java | 10 +- .../resolve/java/JavaDescriptorResolver.java | 93 ++++++++++++++----- .../resolve/java/JavaNamespaceDescriptor.java | 11 ++- .../lang/resolve/java/JavaPackageScope.java | 47 ++++++++-- .../jet/lang/resolve/java/JvmAbi.java | 2 + compiler/testData/readClass/prop/ClassVal.kt | 5 + compiler/testData/readClass/prop/ClassVar.kt | 5 + compiler/testData/readClass/prop/NsVal.kt | 3 + compiler/testData/readClass/prop/NsVar.kt | 3 + .../org/jetbrains/jet/ReadClassDataTest.java | 14 ++- .../jet/codegen/PropertyGenTest.java | 2 +- 11 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 compiler/testData/readClass/prop/ClassVal.kt create mode 100644 compiler/testData/readClass/prop/ClassVar.kt create mode 100644 compiler/testData/readClass/prop/NsVal.kt create mode 100644 compiler/testData/readClass/prop/NsVar.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 2267922aeb7..75ee1e431fd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.descriptors.VariableDescriptor; 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.lexer.JetTokens; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -65,7 +66,7 @@ public class PropertyCodegen { value = compileTimeValue != null ? compileTimeValue.getValue() : null; } } - final int modifiers; + int modifiers; if (kind == OwnerKind.NAMESPACE) { int access = isExternallyAccessible(p) ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE; modifiers = access | Opcodes.ACC_STATIC; @@ -73,6 +74,9 @@ public class PropertyCodegen { else { modifiers = Opcodes.ACC_PRIVATE; } + if (!propertyDescriptor.isVar()) { + modifiers |= Opcodes.ACC_FINAL; + } v.newField(p, modifiers, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value); } } @@ -212,10 +216,10 @@ public class PropertyCodegen { } public static String getterName(String propertyName) { - return "get" + StringUtil.capitalizeWithJavaBeanConvention(propertyName); + return JvmAbi.GETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName); } public static String setterName(String propertyName) { - return "set" + StringUtil.capitalizeWithJavaBeanConvention(propertyName); + return JvmAbi.SETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName); } } 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 c7b061152d4..1cf784ea2de 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 @@ -96,11 +96,23 @@ public class JavaDescriptorResolver { } } + private static class ResolverNamespaceData { + private JavaNamespaceDescriptor namespaceDescriptor; + private boolean kotlin; + + @NotNull + public NamespaceDescriptor getNamespaceDescriptor() { + return namespaceDescriptor; + } + } + protected final Map classDescriptorCache = Maps.newHashMap(); + protected final Map namespaceDescriptorCacheByFqn = Maps.newHashMap(); + protected final Map namespaceDescriptorCache = Maps.newHashMap(); + protected final Map typeParameterDescriptorCache = Maps.newHashMap(); protected final Map methodDescriptorCache = Maps.newHashMap(); protected final Map fieldDescriptorCache = Maps.newHashMap(); - protected final Map namespaceDescriptorCache = Maps.newHashMap(); protected final JavaPsiFacade javaFacade; protected final GlobalSearchScope javaSearchScope; protected final JavaSemanticServices semanticServices; @@ -535,34 +547,40 @@ public class JavaDescriptorResolver { } private NamespaceDescriptor resolveNamespace(@NotNull PsiPackage psiPackage) { - NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(psiPackage); - if (namespaceDescriptor == null) { - namespaceDescriptor = createJavaNamespaceDescriptor(psiPackage); - namespaceDescriptorCache.put(psiPackage, namespaceDescriptor); + ResolverNamespaceData namespaceData = namespaceDescriptorCache.get(psiPackage); + if (namespaceData == null) { + namespaceData = createJavaNamespaceDescriptor(psiPackage); + namespaceDescriptorCache.put(psiPackage, namespaceData); + namespaceDescriptorCacheByFqn.put(psiPackage.getQualifiedName(), namespaceData); } - return namespaceDescriptor; + return namespaceData.namespaceDescriptor; } private NamespaceDescriptor resolveNamespace(@NotNull PsiClass psiClass) { - NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(psiClass); - if (namespaceDescriptor == null) { - namespaceDescriptor = createJavaNamespaceDescriptor(psiClass); - namespaceDescriptorCache.put(psiClass, namespaceDescriptor); + ResolverNamespaceData namespaceData = namespaceDescriptorCache.get(psiClass); + if (namespaceData == null) { + namespaceData = createJavaNamespaceDescriptor(psiClass); + namespaceDescriptorCache.put(psiClass, namespaceData); + namespaceDescriptorCacheByFqn.put(psiClass.getQualifiedName(), namespaceData); } - return namespaceDescriptor; + return namespaceData.namespaceDescriptor; } - private NamespaceDescriptor createJavaNamespaceDescriptor(@NotNull PsiPackage psiPackage) { + private ResolverNamespaceData createJavaNamespaceDescriptor(@NotNull PsiPackage psiPackage) { + ResolverNamespaceData namespaceData = new ResolverNamespaceData(); String name = psiPackage.getName(); - JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor( + namespaceData.namespaceDescriptor = new JavaNamespaceDescriptor( resolveParentDescriptor(psiPackage), Collections.emptyList(), // TODO - name == null ? JAVA_ROOT : name + name == null ? JAVA_ROOT : name, + name == null ? JAVA_ROOT : psiPackage.getQualifiedName() ); - namespaceDescriptor.setMemberScope(new JavaPackageScope(psiPackage.getQualifiedName(), namespaceDescriptor, semanticServices)); - semanticServices.getTrace().record(BindingContext.NAMESPACE, psiPackage, namespaceDescriptor); - return namespaceDescriptor; + namespaceData.namespaceDescriptor.setMemberScope(new JavaPackageScope(psiPackage.getQualifiedName(), namespaceData.namespaceDescriptor, semanticServices)); + semanticServices.getTrace().record(BindingContext.NAMESPACE, psiPackage, namespaceData.namespaceDescriptor); + // TODO: hack + namespaceData.kotlin = true; + return namespaceData; } private DeclarationDescriptor resolveParentDescriptor(@NotNull PsiPackage psiPackage) { @@ -573,15 +591,17 @@ public class JavaDescriptorResolver { return resolveNamespace(parentPackage); } - private NamespaceDescriptor createJavaNamespaceDescriptor(@NotNull final PsiClass psiClass) { - JavaNamespaceDescriptor namespaceDescriptor = new JavaNamespaceDescriptor( + private ResolverNamespaceData createJavaNamespaceDescriptor(@NotNull final PsiClass psiClass) { + ResolverNamespaceData namespaceData = new ResolverNamespaceData(); + namespaceData.namespaceDescriptor = new JavaNamespaceDescriptor( resolveParentDescriptor(psiClass), Collections.emptyList(), // TODO - psiClass.getName() + psiClass.getName(), + psiClass.getQualifiedName() ); - namespaceDescriptor.setMemberScope(new JavaClassMembersScope(namespaceDescriptor, psiClass, semanticServices, true)); - semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceDescriptor); - return namespaceDescriptor; + namespaceData.namespaceDescriptor.setMemberScope(new JavaClassMembersScope(namespaceData.namespaceDescriptor, psiClass, semanticServices, true)); + semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceData.namespaceDescriptor); + return namespaceData; } private static class ValueParameterDescriptors { @@ -831,6 +851,33 @@ public class JavaDescriptorResolver { } return functionDescriptor; } + + boolean kotlin; + if (owner instanceof JavaNamespaceDescriptor) { + JavaNamespaceDescriptor javaNamespaceDescriptor = (JavaNamespaceDescriptor) owner; + ResolverNamespaceData namespaceData = namespaceDescriptorCacheByFqn.get(javaNamespaceDescriptor.getQualifiedName()); + if (namespaceData == null) { + throw new IllegalStateException("namespaceData not found by name " + javaNamespaceDescriptor.getQualifiedName()); + } + kotlin = namespaceData.kotlin; + } else { + ResolverClassData classData = classDescriptorCache.get(psiClass.getQualifiedName()); + if (classData == null) { + throw new IllegalStateException("classData not found by name " + psiClass.getQualifiedName()); + } + kotlin = classData.kotlin; + } + + // TODO: hide getters and setters properly + if (kotlin) { + if (method.getName().startsWith(JvmAbi.GETTER_PREFIX) && method.getParameterList().getParametersCount() == 0) { + return null; + } + if (method.getName().startsWith(JvmAbi.SETTER_PREFIX) && method.getParameterList().getParametersCount() == 1) { + return null; + } + } + DeclarationDescriptor classDescriptor; final List classTypeParameters; if (method.hasModifierProperty(PsiModifier.STATIC)) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java index 3443ebf0f79..5228ba22e14 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaNamespaceDescriptor.java @@ -13,9 +13,12 @@ import java.util.List; */ public class JavaNamespaceDescriptor extends AbstractNamespaceDescriptorImpl { private JetScope memberScope; - - public JavaNamespaceDescriptor(DeclarationDescriptor containingDeclaration, List annotations, String name) { + private final String qualifiedName; + + public JavaNamespaceDescriptor(DeclarationDescriptor containingDeclaration, List annotations, + @NotNull String name, @NotNull String qualifiedName) { super(containingDeclaration, annotations, name); + this.qualifiedName = qualifiedName; } public void setMemberScope(@NotNull JetScope memberScope) { @@ -27,4 +30,8 @@ public class JavaNamespaceDescriptor extends AbstractNamespaceDescriptorImpl { public JetScope getMemberScope() { return memberScope; } + + public String getQualifiedName() { + return qualifiedName; + } } 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 45613dcb978..1e1c791fc14 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 @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.resolve.java; import com.google.common.collect.Sets; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiField; import com.intellij.psi.PsiModifier; import com.intellij.psi.PsiPackage; import org.jetbrains.annotations.NotNull; @@ -37,29 +38,59 @@ public class JavaPackageScope extends JetScopeImpl { public NamespaceDescriptor getNamespace(@NotNull String name) { return semanticServices.getDescriptorResolver().resolveNamespace(getQualifiedName(name)); } - - @NotNull - @Override - public Set getFunctions(@NotNull String name) { + + private PsiClass getPsiClassForPackage() { // If this package is actually a Kotlin namespace, then we access it through a namespace descriptor, and // Kotlin functions are already there NamespaceDescriptor kotlinNamespaceDescriptor = semanticServices.getKotlinNamespaceDescriptor(packageFQN); if (kotlinNamespaceDescriptor != null) { - return Collections.emptySet(); + return null; } // TODO: what is GlobalSearchScope PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(getQualifiedName("namespace")); if (psiClass == null) { - return Collections.emptySet(); + return null; } if (containingDescriptor == null) { + return null; + } + + return psiClass; + } + + @NotNull + @Override + public Set getFunctions(@NotNull String name) { + PsiClass psiClassForPackage = getPsiClassForPackage(); + + if (psiClassForPackage == null) { return Collections.emptySet(); } - return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClass, null, name, true); -// return Collections.emptySet(); + return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClassForPackage, null, name, true); + } + + @NotNull + @Override + public Set getProperties(@NotNull String name) { + PsiClass psiClassForPackage = getPsiClassForPackage(); + + if (psiClassForPackage == null) { + return Collections.emptySet(); + } + + PsiField field = psiClassForPackage.findFieldByName(name, true); + if (field == null) { + return null; + } + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return null; + } + + // TODO: cache + return Collections.singleton(semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDescriptor, field)); } @NotNull diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java index 0cb5f676a08..6ece6061f63 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java @@ -6,4 +6,6 @@ package org.jetbrains.jet.lang.resolve.java; public class JvmAbi { public static final String TRAIT_IMPL_SUFFIX = "$$TImpl"; public static final String DEFAULT_PARAMS_IMPL_SUFFIX = "$default"; + public static final String GETTER_PREFIX = "get"; + public static final String SETTER_PREFIX = "set"; } diff --git a/compiler/testData/readClass/prop/ClassVal.kt b/compiler/testData/readClass/prop/ClassVal.kt new file mode 100644 index 00000000000..b0303be3744 --- /dev/null +++ b/compiler/testData/readClass/prop/ClassVal.kt @@ -0,0 +1,5 @@ +package test + +class ClassVal() { + val aa = 1 +} diff --git a/compiler/testData/readClass/prop/ClassVar.kt b/compiler/testData/readClass/prop/ClassVar.kt new file mode 100644 index 00000000000..4730972b7dd --- /dev/null +++ b/compiler/testData/readClass/prop/ClassVar.kt @@ -0,0 +1,5 @@ +package test + +class ClassVar() { + var aa = 1 +} diff --git a/compiler/testData/readClass/prop/NsVal.kt b/compiler/testData/readClass/prop/NsVal.kt new file mode 100644 index 00000000000..654f3ad18a0 --- /dev/null +++ b/compiler/testData/readClass/prop/NsVal.kt @@ -0,0 +1,3 @@ +package test + +val nsVal = 1 diff --git a/compiler/testData/readClass/prop/NsVar.kt b/compiler/testData/readClass/prop/NsVar.kt new file mode 100644 index 00000000000..5bc54696acd --- /dev/null +++ b/compiler/testData/readClass/prop/NsVar.kt @@ -0,0 +1,3 @@ +package test + +var nsVal = 1 diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index abc9bab89f8..d91f83f7123 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.codegen.ClassBuilderFactory; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.codegen.PropertyCodegen; import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.*; @@ -132,7 +133,16 @@ public class ReadClassDataTest extends UsefulTestCase { Assert.assertTrue(functions.size() >= 1); Assert.assertTrue("not implemented", functions.size() == 1); FunctionDescriptor bd = functions.iterator().next(); - compareFunctions((FunctionDescriptor) ad, bd); + compareDescriptors(ad, bd); + } else if (ad instanceof PropertyDescriptor) { + Set properties = nsb.getMemberScope().getProperties(ad.getName()); + Assert.assertTrue(properties.size() >= 1); + Assert.assertTrue("not implemented", properties.size() == 1); + PropertyDescriptor bd = (PropertyDescriptor) properties.iterator().next(); + compareDescriptors(ad, bd); + + Assert.assertTrue(nsb.getMemberScope().getFunctions(PropertyCodegen.getterName(ad.getName())).isEmpty()); + Assert.assertTrue(nsb.getMemberScope().getFunctions(PropertyCodegen.setterName(ad.getName())).isEmpty()); } else { throw new AssertionError("Unknown member: " + ad); } @@ -153,7 +163,7 @@ public class ReadClassDataTest extends UsefulTestCase { System.out.println(as); } - private void compareFunctions(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { + private void compareDescriptors(@NotNull DeclarationDescriptor a, @NotNull DeclarationDescriptor b) { StringBuilder sba = new StringBuilder(); StringBuilder sbb = new StringBuilder(); new Serializer(sba).serialize(a); diff --git a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index fc22ac350eb..52ce1309e36 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -58,7 +58,7 @@ public class PropertyGenTest extends CodegenTestCase { final Field field = fields[0]; field.setAccessible(true); assertEquals("x", field.getName()); - assertEquals(Modifier.PRIVATE | Modifier.STATIC, field.getModifiers()); + assertEquals(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, field.getModifiers()); assertEquals(239, field.get(null)); }