diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java index 328c2e77b2b..d130b2261d8 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java @@ -39,7 +39,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.GlobalJavaResolverContext; import org.jetbrains.jet.lang.resolve.kotlin.DeserializedDescriptorResolver; import org.jetbrains.jet.lang.resolve.kotlin.DeserializationComponentsForJava; import org.jetbrains.jet.lang.resolve.kotlin.JavaClassDataFinder; -import org.jetbrains.jet.lang.resolve.kotlin.BinaryClassAnnotationAndConstantLoader; +import org.jetbrains.jet.lang.resolve.kotlin.BinaryClassAnnotationAndConstantLoaderImpl; import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; @@ -70,7 +70,7 @@ public class InjectorForJavaDescriptorResolver { private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final DeserializationComponentsForJava deserializationComponentsForJava; private final JavaClassDataFinder javaClassDataFinder; - private final BinaryClassAnnotationAndConstantLoader binaryClassAnnotationAndConstantLoader; + private final BinaryClassAnnotationAndConstantLoaderImpl binaryClassAnnotationAndConstantLoader; public InjectorForJavaDescriptorResolver( @NotNull Project project, @@ -98,7 +98,7 @@ public class InjectorForJavaDescriptorResolver { this.javaDescriptorResolver = new JavaDescriptorResolver(lazyJavaPackageFragmentProvider, getModule()); this.globalSearchScope = com.intellij.psi.search.GlobalSearchScope.allScope(project); this.javaClassDataFinder = new JavaClassDataFinder(virtualFileFinder, deserializedDescriptorResolver); - this.binaryClassAnnotationAndConstantLoader = new BinaryClassAnnotationAndConstantLoader(getModule(), lockBasedStorageManager, virtualFileFinder, traceBasedErrorReporter); + this.binaryClassAnnotationAndConstantLoader = new BinaryClassAnnotationAndConstantLoaderImpl(getModule(), lockBasedStorageManager, virtualFileFinder, traceBasedErrorReporter); this.deserializationComponentsForJava = new DeserializationComponentsForJava(lockBasedStorageManager, getModule(), javaClassDataFinder, binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider); this.javaClassFinder.setProject(project); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForLazyResolveWithJava.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForLazyResolveWithJava.java index 986ee547eaf..d73b1003814 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForLazyResolveWithJava.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForLazyResolveWithJava.java @@ -67,7 +67,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.GlobalJavaResolverContext; import org.jetbrains.jet.lang.resolve.kotlin.DeserializedDescriptorResolver; import org.jetbrains.jet.lang.resolve.kotlin.DeserializationComponentsForJava; import org.jetbrains.jet.lang.resolve.kotlin.JavaClassDataFinder; -import org.jetbrains.jet.lang.resolve.kotlin.BinaryClassAnnotationAndConstantLoader; +import org.jetbrains.jet.lang.resolve.kotlin.BinaryClassAnnotationAndConstantLoaderImpl; import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; @@ -126,7 +126,7 @@ public class InjectorForLazyResolveWithJava { private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final DeserializationComponentsForJava deserializationComponentsForJava; private final JavaClassDataFinder javaClassDataFinder; - private final BinaryClassAnnotationAndConstantLoader binaryClassAnnotationAndConstantLoader; + private final BinaryClassAnnotationAndConstantLoaderImpl binaryClassAnnotationAndConstantLoader; public InjectorForLazyResolveWithJava( @NotNull Project project, @@ -187,7 +187,7 @@ public class InjectorForLazyResolveWithJava { this.scopeProvider = new ScopeProvider(getResolveSession()); this.scriptBodyResolver = new ScriptBodyResolver(); this.javaClassDataFinder = new JavaClassDataFinder(virtualFileFinder, deserializedDescriptorResolver); - this.binaryClassAnnotationAndConstantLoader = new BinaryClassAnnotationAndConstantLoader(module, storageManager, virtualFileFinder, traceBasedErrorReporter); + this.binaryClassAnnotationAndConstantLoader = new BinaryClassAnnotationAndConstantLoaderImpl(module, storageManager, virtualFileFinder, traceBasedErrorReporter); this.deserializationComponentsForJava = new DeserializationComponentsForJava(storageManager, module, javaClassDataFinder, binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider); this.resolveSession.setAnnotationResolve(annotationResolver); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index 3fc6600595d..4d590b5c3eb 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -78,7 +78,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaPackageFragmentProvider; import org.jetbrains.jet.lang.resolve.java.lazy.GlobalJavaResolverContext; import org.jetbrains.jet.lang.resolve.kotlin.DeserializedDescriptorResolver; import org.jetbrains.jet.lang.resolve.kotlin.JavaClassDataFinder; -import org.jetbrains.jet.lang.resolve.kotlin.BinaryClassAnnotationAndConstantLoader; +import org.jetbrains.jet.lang.resolve.kotlin.BinaryClassAnnotationAndConstantLoaderImpl; import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; @@ -148,7 +148,7 @@ public class InjectorForTopDownAnalyzerForJvm { private final GlobalJavaResolverContext globalJavaResolverContext; private final DeserializedDescriptorResolver deserializedDescriptorResolver; private final JavaClassDataFinder javaClassDataFinder; - private final BinaryClassAnnotationAndConstantLoader binaryClassAnnotationAndConstantLoader; + private final BinaryClassAnnotationAndConstantLoaderImpl binaryClassAnnotationAndConstantLoader; public InjectorForTopDownAnalyzerForJvm( @NotNull Project project, @@ -181,7 +181,7 @@ public class InjectorForTopDownAnalyzerForJvm { this.lazyJavaPackageFragmentProvider = new LazyJavaPackageFragmentProvider(globalJavaResolverContext, getModuleDescriptor()); this.javaDescriptorResolver = new JavaDescriptorResolver(lazyJavaPackageFragmentProvider, getModuleDescriptor()); this.javaClassDataFinder = new JavaClassDataFinder(virtualFileFinder, deserializedDescriptorResolver); - this.binaryClassAnnotationAndConstantLoader = new BinaryClassAnnotationAndConstantLoader(getModuleDescriptor(), storageManager, virtualFileFinder, traceBasedErrorReporter); + this.binaryClassAnnotationAndConstantLoader = new BinaryClassAnnotationAndConstantLoaderImpl(getModuleDescriptor(), storageManager, virtualFileFinder, traceBasedErrorReporter); this.deserializationComponentsForJava = new DeserializationComponentsForJava(storageManager, getModuleDescriptor(), javaClassDataFinder, binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider); this.additionalCheckerProvider = org.jetbrains.jet.lang.resolve.kotlin.JavaDeclarationCheckerProvider.INSTANCE$; this.globalSearchScope = com.intellij.psi.search.GlobalSearchScope.allScope(project); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt new file mode 100644 index 00000000000..77cc9860b5c --- /dev/null +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt @@ -0,0 +1,277 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.kotlin + +import org.jetbrains.jet.lang.resolve.name.ClassId +import java.util.ArrayList +import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotatedCallableKind +import org.jetbrains.jet.descriptors.serialization.NameResolver +import org.jetbrains.jet.descriptors.serialization.ProtoBuf +import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf +import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf.* +import org.jetbrains.jet.descriptors.serialization.descriptors.ProtoContainer +import org.jetbrains.jet.storage.StorageManager +import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter +import org.jetbrains.jet.lang.resolve.name.FqName +import java.util.HashMap +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.descriptors.serialization.Flags +import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationAndConstantLoader + +public abstract class AbstractBinaryClassAnnotationAndConstantLoader( + storageManager: StorageManager, + private val kotlinClassFinder: KotlinClassFinder, + private val errorReporter: ErrorReporter +) : AnnotationAndConstantLoader { + private val storage = storageManager.createMemoizedFunction> { + kotlinClass -> + loadAnnotationsAndInitializers(kotlinClass) + } + + protected abstract fun loadConstant(desc: String, initializer: Any): C? + + protected abstract fun loadAnnotation( + annotationClassId: ClassId, + result: MutableList + ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? + + override fun loadClassAnnotations(classProto: ProtoBuf.Class, nameResolver: NameResolver): List { + val classId = nameResolver.getClassId(classProto.getFqName()) + val kotlinClass = findKotlinClassById(classId) + if (kotlinClass == null) { + // This means that the resource we're constructing the descriptor from is no longer present: KotlinClassFinder had found the + // class earlier, but it can't now + errorReporter.reportLoadingError("Kotlin class for loading class annotations is not found: ${classId.asSingleFqName()}", null) + return listOf() + } + + val result = ArrayList(1) + + kotlinClass.loadClassAnnotations(object : KotlinJvmBinaryClass.AnnotationVisitor { + override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + return loadAnnotation(classId, result) + } + + override fun visitEnd() { + } + }) + + return result + } + + override fun loadCallableAnnotations( + container: ProtoContainer, + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind + ): List { + val signature = getCallableSignature(proto, nameResolver, kind) ?: return listOf() + return findClassAndLoadMemberAnnotations(container, proto, nameResolver, kind, signature) + } + + private fun findClassAndLoadMemberAnnotations( + container: ProtoContainer, + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind, + signature: MemberSignature + ): List { + val kotlinClass = findClassWithAnnotationsAndInitializers(container, proto, nameResolver, kind) + if (kotlinClass == null) { + errorReporter.reportLoadingError("Kotlin class for loading member annotations is not found: $container", null) + return listOf() + } + + return storage(kotlinClass).memberAnnotations[signature] ?: listOf() + } + + override fun loadValueParameterAnnotations( + container: ProtoContainer, + callable: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind, + proto: ProtoBuf.Callable.ValueParameter + ): List { + val methodSignature = getCallableSignature(callable, nameResolver, kind) + if (methodSignature != null) { + if (proto.hasExtension(index)) { + val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(methodSignature, proto.getExtension(JavaProtoBuf.index)) + return findClassAndLoadMemberAnnotations(container, callable, nameResolver, kind, paramSignature) + } + } + + return listOf() + } + + override fun loadPropertyConstant( + container: ProtoContainer, + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind + ): C? { + val signature = getCallableSignature(proto, nameResolver, kind) ?: return null + + val kotlinClass = findClassWithAnnotationsAndInitializers(container, proto, nameResolver, kind) + if (kotlinClass == null) { + errorReporter.reportLoadingError("Kotlin class for loading property constant is not found: $container", null) + return null + } + + return storage(kotlinClass).propertyConstants[signature] + } + + private fun findClassWithAnnotationsAndInitializers( + container: ProtoContainer, + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + annotatedCallableKind: AnnotatedCallableKind + ): KotlinJvmBinaryClass? { + val packageFqName = container.packageFqName + if (packageFqName != null) { + return findPackagePartClass(packageFqName, proto, nameResolver) + } + val classProto = container.classProto!! + val classKind = Flags.CLASS_KIND[classProto.getFlags()] + val classId = nameResolver.getClassId(classProto.getFqName()) + if (classKind == ProtoBuf.Class.Kind.CLASS_OBJECT && isStaticFieldInOuter(proto)) { + // Backing fields of properties of a class object are generated in the outer class + return findKotlinClassById(classId.getOuterClassId()) + } + else if (classKind == ProtoBuf.Class.Kind.TRAIT && annotatedCallableKind == AnnotatedCallableKind.PROPERTY) { + if (proto.hasExtension(implClassName)) { + val parentPackageFqName = classId.getPackageFqName() + val tImplName = nameResolver.getName(proto.getExtension(implClassName)) + // TODO: store accurate name for nested traits + return findKotlinClassById(ClassId(parentPackageFqName, tImplName)) + } + return null + } + + return findKotlinClassById(classId) + } + + private fun findPackagePartClass( + packageFqName: FqName, + proto: ProtoBuf.Callable, + nameResolver: NameResolver + ): KotlinJvmBinaryClass? { + if (proto.hasExtension(implClassName)) { + return findKotlinClassById(ClassId(packageFqName, nameResolver.getName(proto.getExtension(implClassName)))) + } + return null + } + + private fun findKotlinClassById(classId: ClassId): KotlinJvmBinaryClass? { + return kotlinClassFinder.findKotlinClass(DeserializedResolverUtils.kotlinClassIdToJavaClassId(classId)) + } + + private fun isStaticFieldInOuter(proto: ProtoBuf.Callable): Boolean { + if (!proto.hasExtension(propertySignature)) return false + val propertySignature = proto.getExtension(propertySignature) + return propertySignature.hasField() && propertySignature.getField().getIsStaticInOuter() + } + + private fun loadAnnotationsAndInitializers(kotlinClass: KotlinJvmBinaryClass): Storage { + val memberAnnotations = HashMap>() + val propertyConstants = HashMap() + + kotlinClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor { + override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? { + return AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name.asString() + desc)) + } + + override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? { + val signature = MemberSignature.fromFieldNameAndDesc(name, desc) + + if (initializer != null) { + val constant = loadConstant(desc, initializer) + if (constant != null) { + propertyConstants[signature] = constant + } + } + return MemberAnnotationVisitor(signature) + } + + inner class AnnotationVisitorForMethod(signature: MemberSignature) : MemberAnnotationVisitor(signature), KotlinJvmBinaryClass.MethodAnnotationVisitor { + + override fun visitParameterAnnotation(index: Int, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(signature, index) + var result = memberAnnotations[paramSignature] + if (result == null) { + result = ArrayList() + memberAnnotations[paramSignature] = result + } + return loadAnnotation(classId, result) + } + } + + open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor { + private val result = ArrayList() + + override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + return loadAnnotation(classId, result) + } + + override fun visitEnd() { + if (result.isNotEmpty()) { + memberAnnotations[signature] = result + } + } + } + }) + + return Storage(memberAnnotations, propertyConstants) + } + + private class Storage( + public val memberAnnotations: Map>, + public val propertyConstants: Map + ) +} + +private fun getCallableSignature( + proto: ProtoBuf.Callable, + nameResolver: NameResolver, + kind: AnnotatedCallableKind +): MemberSignature? { + val deserializer = SignatureDeserializer(nameResolver) + when (kind) { + AnnotatedCallableKind.FUNCTION -> if (proto.hasExtension(methodSignature)) { + return deserializer.methodSignature(proto.getExtension(methodSignature)) + } + AnnotatedCallableKind.PROPERTY_GETTER -> if (proto.hasExtension(propertySignature)) { + return deserializer.methodSignature(proto.getExtension(propertySignature).getGetter()) + } + AnnotatedCallableKind.PROPERTY_SETTER -> if (proto.hasExtension(propertySignature)) { + return deserializer.methodSignature(proto.getExtension(propertySignature).getSetter()) + } + AnnotatedCallableKind.PROPERTY -> if (proto.hasExtension(propertySignature)) { + val propertySignature = proto.getExtension(propertySignature) + + if (propertySignature.hasField()) { + val field = propertySignature.getField() + val type = deserializer.typeDescriptor(field.getType()) + val name = nameResolver.getName(field.getName()) + return MemberSignature.fromFieldNameAndDesc(name, type) + } + else if (propertySignature.hasSyntheticMethod()) { + return deserializer.methodSignature(propertySignature.getSyntheticMethod()) + } + } + } + return null +} \ No newline at end of file diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/BinaryClassAnnotationAndConstantLoader.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/BinaryClassAnnotationAndConstantLoader.kt deleted file mode 100644 index 2d1148c96b4..00000000000 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/BinaryClassAnnotationAndConstantLoader.kt +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright 2010-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.resolve.kotlin - -import org.jetbrains.jet.descriptors.serialization.* -import org.jetbrains.jet.descriptors.serialization.descriptors.* -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.descriptors.annotations.* -import org.jetbrains.jet.lang.resolve.constants.* -import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf.* -import org.jetbrains.jet.lang.resolve.name.* -import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames -import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils -import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter -import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor -import org.jetbrains.jet.lang.types.ErrorUtils -import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.javaClassIdToKotlinClassId -import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.kotlinClassIdToJavaClassId -import org.jetbrains.jet.storage.StorageManager -import kotlin.platform.platformStatic - -import java.util.* - -public class BinaryClassAnnotationAndConstantLoader( - private val module: ModuleDescriptor, - storageManager: StorageManager, - private val kotlinClassFinder: KotlinClassFinder, - private val errorReporter: ErrorReporter -) : AnnotationAndConstantLoader { - - private val storage = storageManager.createMemoizedFunction{ - kotlinClass -> - loadAnnotationsAndInitializers(kotlinClass) - } - - override fun loadClassAnnotations(classProto: ProtoBuf.Class, nameResolver: NameResolver): List { - val classId = nameResolver.getClassId(classProto.getFqName()) - val kotlinClass = findKotlinClassById(classId) - if (kotlinClass == null) { - // This means that the resource we're constructing the descriptor from is no longer present: KotlinClassFinder had found the - // class earlier, but it can't now - errorReporter.reportLoadingError("Kotlin class for loading class annotations is not found: ${classId.asSingleFqName()}", null) - return listOf() - } - - val result = ArrayList(1) - - kotlinClass.loadClassAnnotations(object : KotlinJvmBinaryClass.AnnotationVisitor { - override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - return resolveAnnotation(classId, result, module) - } - - override fun visitEnd() { - } - }) - - return result - } - - override fun loadCallableAnnotations( - container: ProtoContainer, - proto: ProtoBuf.Callable, - nameResolver: NameResolver, - kind: AnnotatedCallableKind - ): List { - val signature = getCallableSignature(proto, nameResolver, kind) ?: return listOf() - return findClassAndLoadMemberAnnotations(container, proto, nameResolver, kind, signature) - } - - private fun findClassAndLoadMemberAnnotations( - container: ProtoContainer, - proto: ProtoBuf.Callable, - nameResolver: NameResolver, - kind: AnnotatedCallableKind, - signature: MemberSignature - ): List { - val kotlinClass = findClassWithAnnotationsAndInitializers(container, proto, nameResolver, kind) - if (kotlinClass == null) { - errorReporter.reportLoadingError("Kotlin class for loading member annotations is not found: $container", null) - return listOf() - } - - return storage(kotlinClass).memberAnnotations[signature] ?: listOf() - } - - override fun loadValueParameterAnnotations( - container: ProtoContainer, - callable: ProtoBuf.Callable, - nameResolver: NameResolver, - kind: AnnotatedCallableKind, - proto: ProtoBuf.Callable.ValueParameter - ): List { - val methodSignature = getCallableSignature(callable, nameResolver, kind) - if (methodSignature != null) { - if (proto.hasExtension(index)) { - val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(methodSignature, proto.getExtension(JavaProtoBuf.index)) - return findClassAndLoadMemberAnnotations(container, callable, nameResolver, kind, paramSignature) - } - } - - return listOf() - } - - class object { - - public fun resolveAnnotation( - classId: ClassId, - result: MutableList, - moduleDescriptor: ModuleDescriptor - ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - if (JvmAnnotationNames.isSpecialAnnotation(classId, true)) return null - - val annotationClass = resolveClass(classId, moduleDescriptor) - - return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor { - private val arguments = HashMap>() - - override fun visit(name: Name?, value: Any?) { - if (name != null) { - setArgumentValueByName(name, createConstant(name, value)) - } - } - - override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) { - setArgumentValueByName(name, enumEntryValue(enumClassId, enumEntryName)) - } - - override fun visitArray(name: Name): AnnotationArrayArgumentVisitor? { - return object : KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor { - private val elements = ArrayList>() - - override fun visit(value: Any?) { - elements.add(createConstant(name, value)) - } - - override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) { - elements.add(enumEntryValue(enumClassId, enumEntryName)) - } - - override fun visitEnd() { - val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) - if (parameter != null) { - elements.trimToSize() - arguments[parameter] = ArrayValue(elements, parameter.getType(), true, false) - } - } - } - } - - private fun enumEntryValue(enumClassId: ClassId, name: Name): CompileTimeConstant<*> { - val enumClass = resolveClass(enumClassId, moduleDescriptor) - if (enumClass.getKind() == ClassKind.ENUM_CLASS) { - val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name) - if (classifier is ClassDescriptor) { - return EnumValue(classifier, false) - } - } - return ErrorValue.create("Unresolved enum entry: $enumClassId.$name") - } - - override fun visitEnd() { - result.add(AnnotationDescriptorImpl(annotationClass.getDefaultType(), arguments)) - } - - private fun createConstant(name: Name?, value: Any?): CompileTimeConstant<*> { - return createCompileTimeConstant(value, true, false, false, null) - ?: ErrorValue.create("Unsupported annotation argument: $name") - } - - private fun setArgumentValueByName(name: Name, argumentValue: CompileTimeConstant<*>) { - val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) - if (parameter != null) { - arguments[parameter] = argumentValue - } - } - } - } - - private fun resolveClass(javaClassId: ClassId, moduleDescriptor: ModuleDescriptor): ClassDescriptor { - val classId = javaClassIdToKotlinClassId(javaClassId) - return moduleDescriptor.findClassAcrossModuleDependencies(classId) - ?: ErrorUtils.createErrorClass(classId.asSingleFqName().asString()) - } - } - - override fun loadPropertyConstant( - container: ProtoContainer, - proto: ProtoBuf.Callable, - nameResolver: NameResolver, - kind: AnnotatedCallableKind - ): CompileTimeConstant<*>? { - val signature = getCallableSignature(proto, nameResolver, kind) ?: return null - - val kotlinClass = findClassWithAnnotationsAndInitializers(container, proto, nameResolver, kind) - if (kotlinClass == null) { - errorReporter.reportLoadingError("Kotlin class for loading property constant is not found: $container", null) - return null - } - - return storage(kotlinClass).propertyConstants[signature] - } - - - protected fun findClassWithAnnotationsAndInitializers( - container: ProtoContainer, - proto: ProtoBuf.Callable, - nameResolver: NameResolver, - annotatedCallableKind: AnnotatedCallableKind - ): KotlinJvmBinaryClass? { - val packageFqName = container.packageFqName - if (packageFqName != null) { - return findPackagePartClass(packageFqName, proto, nameResolver) - } - val classProto = container.classProto!! - val classKind = Flags.CLASS_KIND[classProto.getFlags()] - val classId = nameResolver.getClassId(classProto.getFqName()) - if (classKind == ProtoBuf.Class.Kind.CLASS_OBJECT && isStaticFieldInOuter(proto)) { - // Backing fields of properties of a class object are generated in the outer class - return findKotlinClassById(classId.getOuterClassId()) - } - else if (classKind == ProtoBuf.Class.Kind.TRAIT && annotatedCallableKind == AnnotatedCallableKind.PROPERTY) { - if (proto.hasExtension(implClassName)) { - val parentPackageFqName = classId.getPackageFqName() - val tImplName = nameResolver.getName(proto.getExtension(implClassName)) - // TODO: store accurate name for nested traits - return findKotlinClassById(ClassId(parentPackageFqName, tImplName)) - } - return null - } - - return findKotlinClassById(classId) - } - - private fun findPackagePartClass( - packageFqName: FqName, - proto: ProtoBuf.Callable, - nameResolver: NameResolver - ): KotlinJvmBinaryClass? { - if (proto.hasExtension(implClassName)) { - return findKotlinClassById(ClassId(packageFqName, nameResolver.getName(proto.getExtension(implClassName)))) - } - return null - } - - protected fun findKotlinClassById(classId: ClassId): KotlinJvmBinaryClass? { - return kotlinClassFinder.findKotlinClass(kotlinClassIdToJavaClassId(classId)) - } - - private fun isStaticFieldInOuter(proto: ProtoBuf.Callable): Boolean { - if (!proto.hasExtension(propertySignature)) return false - val propertySignature = proto.getExtension(propertySignature) - return propertySignature.hasField() && propertySignature.getField().getIsStaticInOuter() - } - - fun getCallableSignature( - proto: ProtoBuf.Callable, - nameResolver: NameResolver, - kind: AnnotatedCallableKind - ): MemberSignature? { - val deserializer = SignatureDeserializer(nameResolver) - when (kind) { - AnnotatedCallableKind.FUNCTION -> if (proto.hasExtension(methodSignature)) { - return deserializer.methodSignature(proto.getExtension(methodSignature)) - } - AnnotatedCallableKind.PROPERTY_GETTER -> if (proto.hasExtension(propertySignature)) { - return deserializer.methodSignature(proto.getExtension(propertySignature).getGetter()) - } - AnnotatedCallableKind.PROPERTY_SETTER -> if (proto.hasExtension(propertySignature)) { - return deserializer.methodSignature(proto.getExtension(propertySignature).getSetter()) - } - AnnotatedCallableKind.PROPERTY -> if (proto.hasExtension(propertySignature)) { - val propertySignature = proto.getExtension(propertySignature) - - if (propertySignature.hasField()) { - val field = propertySignature.getField() - val type = deserializer.typeDescriptor(field.getType()) - val name = nameResolver.getName(field.getName()) - return MemberSignature.fromFieldNameAndDesc(name, type) - } - else if (propertySignature.hasSyntheticMethod()) { - return deserializer.methodSignature(propertySignature.getSyntheticMethod()) - } - } - } - return null - } - - private fun loadAnnotationsAndInitializers(kotlinClass: KotlinJvmBinaryClass): Storage { - val memberAnnotations = HashMap>() - val propertyConstants = HashMap>() - - kotlinClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor { - override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? { - return AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name.asString() + desc)) - } - - override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? { - val signature = MemberSignature.fromFieldNameAndDesc(name, desc) - - if (initializer != null) { - val normalizedValue: Any - if (desc in "ZBCS") { - val intValue = initializer as Int - if ("Z" == desc) { - normalizedValue = intValue != 0 - } - else if ("B" == desc) { - normalizedValue = (intValue.toByte()) - } - else if ("C" == desc) { - normalizedValue = (intValue.toChar()) - } - else if ("S" == desc) { - normalizedValue = (intValue.toShort()) - } - else { - throw AssertionError(desc) - } - } - else { - normalizedValue = initializer - } - - propertyConstants[signature] = createCompileTimeConstant( - normalizedValue, canBeUsedInAnnotation = true, isPureIntConstant = true, - usesVariableAsConstant = true, expectedType = null - ) - } - return MemberAnnotationVisitor(signature) - } - - inner class AnnotationVisitorForMethod(signature: MemberSignature) : MemberAnnotationVisitor(signature), KotlinJvmBinaryClass.MethodAnnotationVisitor { - - override fun visitParameterAnnotation(index: Int, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(signature, index) - var result = memberAnnotations[paramSignature] - if (result == null) { - result = ArrayList() - memberAnnotations[paramSignature] = result - } - return BinaryClassAnnotationAndConstantLoader.resolveAnnotation(classId, result, module) - } - } - - open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor { - private val result = ArrayList() - - override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - return BinaryClassAnnotationAndConstantLoader.resolveAnnotation(classId, result, module) - } - - override fun visitEnd() { - if (result.isNotEmpty()) { - memberAnnotations[signature] = result - } - } - } - }) - - return Storage(memberAnnotations, propertyConstants) - } - - class Storage( - public val memberAnnotations: Map>, - public val propertyConstants: Map> - ) { - class object { - public val EMPTY: Storage = Storage(mapOf(), mapOf()) - } - } -} diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt new file mode 100644 index 00000000000..0e93275a843 --- /dev/null +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt @@ -0,0 +1,161 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.kotlin + +import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames +import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils +import org.jetbrains.jet.lang.resolve.java.resolver.ErrorReporter +import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor +import org.jetbrains.jet.lang.types.ErrorUtils +import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils.javaClassIdToKotlinClassId +import org.jetbrains.jet.storage.StorageManager + +import java.util.* +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor +import org.jetbrains.jet.lang.resolve.name.ClassId +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.constants.ArrayValue +import org.jetbrains.jet.lang.descriptors.ClassKind +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.resolve.constants.EnumValue +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl +import org.jetbrains.jet.lang.resolve.constants.ErrorValue +import org.jetbrains.jet.lang.resolve.constants.createCompileTimeConstant +import org.jetbrains.jet.descriptors.serialization.findClassAcrossModuleDependencies +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant + +public class BinaryClassAnnotationAndConstantLoaderImpl( + private val module: ModuleDescriptor, + storageManager: StorageManager, + kotlinClassFinder: KotlinClassFinder, + errorReporter: ErrorReporter +) : AbstractBinaryClassAnnotationAndConstantLoader>( + storageManager, kotlinClassFinder, errorReporter +) { + + override fun loadConstant(desc: String, initializer: Any): CompileTimeConstant? { + val normalizedValue: Any + if (desc in "ZBCS") { + val intValue = initializer as Int + if ("Z" == desc) { + normalizedValue = intValue != 0 + } + else if ("B" == desc) { + normalizedValue = (intValue.toByte()) + } + else if ("C" == desc) { + normalizedValue = (intValue.toChar()) + } + else if ("S" == desc) { + normalizedValue = (intValue.toShort()) + } + else { + throw AssertionError(desc) + } + } + else { + normalizedValue = initializer + } + + val compileTimeConstant = createCompileTimeConstant( + normalizedValue, canBeUsedInAnnotation = true, isPureIntConstant = true, + usesVariableAsConstant = true, expectedType = null + ) + return compileTimeConstant + } + + + override fun loadAnnotation( + annotationClassId: ClassId, + result: MutableList + ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + if (JvmAnnotationNames.isSpecialAnnotation(annotationClassId, true)) return null + + val annotationClass = resolveClass(annotationClassId) + + return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor { + private val arguments = HashMap>() + + override fun visit(name: Name?, value: Any?) { + if (name != null) { + setArgumentValueByName(name, createConstant(name, value)) + } + } + + override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) { + setArgumentValueByName(name, enumEntryValue(enumClassId, enumEntryName)) + } + + override fun visitArray(name: Name): AnnotationArrayArgumentVisitor? { + return object : KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor { + private val elements = ArrayList>() + + override fun visit(value: Any?) { + elements.add(createConstant(name, value)) + } + + override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) { + elements.add(enumEntryValue(enumClassId, enumEntryName)) + } + + override fun visitEnd() { + val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) + if (parameter != null) { + elements.trimToSize() + arguments[parameter] = ArrayValue(elements, parameter.getType(), true, false) + } + } + } + } + + private fun enumEntryValue(enumClassId: ClassId, name: Name): CompileTimeConstant<*> { + val enumClass = resolveClass(enumClassId) + if (enumClass.getKind() == ClassKind.ENUM_CLASS) { + val classifier = enumClass.getUnsubstitutedInnerClassesScope().getClassifier(name) + if (classifier is ClassDescriptor) { + return EnumValue(classifier, false) + } + } + return ErrorValue.create("Unresolved enum entry: $enumClassId.$name") + } + + override fun visitEnd() { + result.add(AnnotationDescriptorImpl(annotationClass.getDefaultType(), arguments)) + } + + private fun createConstant(name: Name?, value: Any?): CompileTimeConstant<*> { + return createCompileTimeConstant(value, true, false, false, null) + ?: ErrorValue.create("Unsupported annotation argument: $name") + } + + private fun setArgumentValueByName(name: Name, argumentValue: CompileTimeConstant<*>) { + val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) + if (parameter != null) { + arguments[parameter] = argumentValue + } + } + } + } + + private fun resolveClass(javaClassId: ClassId): ClassDescriptor { + val classId = javaClassIdToKotlinClassId(javaClassId) + return module.findClassAcrossModuleDependencies(classId) + ?: ErrorUtils.createErrorClass(classId.asSingleFqName().asString()) + } +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializationComponentsForJava.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializationComponentsForJava.kt index 500e00a82cc..1aab8b08c64 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializationComponentsForJava.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializationComponentsForJava.kt @@ -27,7 +27,7 @@ public class DeserializationComponentsForJava( storageManager: StorageManager, moduleDescriptor: ModuleDescriptor, classDataFinder: JavaClassDataFinder, - annotationAndConstantLoader: BinaryClassAnnotationAndConstantLoader, + annotationAndConstantLoader: BinaryClassAnnotationAndConstantLoaderImpl, packageFragmentProvider: LazyJavaPackageFragmentProvider ) { val components = DeserializationComponents( diff --git a/core/serialization/src/org/jetbrains/jet/descriptors/serialization/context/context.kt b/core/serialization/src/org/jetbrains/jet/descriptors/serialization/context/context.kt index 9b576c8be49..6ad22545287 100644 --- a/core/serialization/src/org/jetbrains/jet/descriptors/serialization/context/context.kt +++ b/core/serialization/src/org/jetbrains/jet/descriptors/serialization/context/context.kt @@ -21,12 +21,14 @@ import org.jetbrains.jet.lang.descriptors.* import org.jetbrains.jet.descriptors.serialization.* import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationAndConstantLoader import org.jetbrains.jet.lang.resolve.name.ClassId +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor public class DeserializationComponents( public val storageManager: StorageManager, public val moduleDescriptor: ModuleDescriptor, public val classDataFinder: ClassDataFinder, - public val annotationAndConstantLoader: AnnotationAndConstantLoader, + public val annotationAndConstantLoader: AnnotationAndConstantLoader>, public val packageFragmentProvider: PackageFragmentProvider, public val flexibleTypeCapabilitiesDeserializer: FlexibleTypeCapabilitiesDeserializer ) { diff --git a/core/serialization/src/org/jetbrains/jet/descriptors/serialization/descriptors/AnnotationAndConstantLoader.java b/core/serialization/src/org/jetbrains/jet/descriptors/serialization/descriptors/AnnotationAndConstantLoader.java index e223dd8c605..b4c5c753522 100644 --- a/core/serialization/src/org/jetbrains/jet/descriptors/serialization/descriptors/AnnotationAndConstantLoader.java +++ b/core/serialization/src/org/jetbrains/jet/descriptors/serialization/descriptors/AnnotationAndConstantLoader.java @@ -25,8 +25,9 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import java.util.List; -public interface AnnotationAndConstantLoader { - AnnotationAndConstantLoader UNSUPPORTED = new AnnotationAndConstantLoader() { +public interface AnnotationAndConstantLoader { + AnnotationAndConstantLoader> UNSUPPORTED = + new AnnotationAndConstantLoader>() { @NotNull @Override public List loadClassAnnotations( @@ -77,13 +78,13 @@ public interface AnnotationAndConstantLoader { }; @NotNull - List loadClassAnnotations( + List loadClassAnnotations( @NotNull ProtoBuf.Class classProto, @NotNull NameResolver nameResolver ); @NotNull - List loadCallableAnnotations( + List loadCallableAnnotations( @NotNull ProtoContainer container, @NotNull ProtoBuf.Callable proto, @NotNull NameResolver nameResolver, @@ -91,7 +92,7 @@ public interface AnnotationAndConstantLoader { ); @NotNull - List loadValueParameterAnnotations( + List loadValueParameterAnnotations( @NotNull ProtoContainer container, @NotNull ProtoBuf.Callable callable, @NotNull NameResolver nameResolver, @@ -100,7 +101,7 @@ public interface AnnotationAndConstantLoader { ); @Nullable - CompileTimeConstant loadPropertyConstant( + C loadPropertyConstant( @NotNull ProtoContainer container, @NotNull ProtoBuf.Callable proto, @NotNull NameResolver nameResolver, diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DeserializerForDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DeserializerForDecompiler.kt index 59c4640a4a1..cc45ca4832a 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DeserializerForDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/decompiler/textBuilder/DeserializerForDecompiler.kt @@ -93,7 +93,7 @@ public class DeserializerForDecompiler(val packageDirectory: VirtualFile, val di private val storageManager = LockBasedStorageManager.NO_LOCKS private val annotationAndConstantLoader = - BinaryClassAnnotationAndConstantLoader(moduleDescriptor, storageManager, localClassFinder, LOGGING_REPORTER) + BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, storageManager, localClassFinder, LOGGING_REPORTER) private val classDataFinder = object : ClassDataFinder { override fun findClassData(classId: ClassId): ClassData? {