From 57d209f599f67a1eabae91880b145fed91985f46 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 11 Aug 2017 17:36:28 +0500 Subject: [PATCH] Kapt: Do not use awkward ('$' -> '/') logic for KAPT3 class builder mode So (for the most often reproduction case) #KT-19433 Fixed Before this commit, internal names for nested classes were written as test/Foo/Bar (comparing to test/Foo$Bar in the normal mode), as getting qualified names from such internal names was trivial. But, because of IC, we needed to write class files to the disk, so our decompiler could find such "broken" classes and read it in a wrong way. --- .../codegen/state/KotlinTypeMapper.java | 16 +- .../testData/codegen/kapt/innerClasses.txt | 64 +++--- .../testData/codegen/kapt/interfaceImpls.txt | 14 +- .../load/kotlin/typeSignatureMapping.kt | 4 +- .../jetbrains/kotlin/kapt3/Kapt3Extension.kt | 4 +- .../org/jetbrains/kotlin/kapt3/KaptContext.kt | 4 +- .../kotlin/kapt3/javac/KaptTreeMaker.kt | 90 +++++++- .../stubs/ClassFileToSourceStubConverter.kt | 15 +- .../kapt3/stubs/SignatureParserVisitor.kt | 2 +- .../kotlin/kapt3/stubs/errorTypeConversion.kt | 2 +- .../kapt3/test/AbstractKotlinKapt3Test.kt | 2 +- ...ileToSourceStubConverterTestGenerated.java | 12 ++ .../kotlin/kapt3/test/JavaKaptContextTest.kt | 2 + .../kapt3/test/KotlinKapt3IntegrationTests.kt | 8 +- .../testData/converter/nestedClasses2.kt | 78 +++++++ .../testData/converter/nestedClasses2.txt | 192 +++++++++++++++++ .../converter/nestedClassesNonRootPackage.kt | 84 ++++++++ .../converter/nestedClassesNonRootPackage.txt | 198 ++++++++++++++++++ 18 files changed, 708 insertions(+), 83 deletions(-) create mode 100644 plugins/kapt3/testData/converter/nestedClasses2.kt create mode 100644 plugins/kapt3/testData/converter/nestedClasses2.txt create mode 100644 plugins/kapt3/testData/converter/nestedClassesNonRootPackage.kt create mode 100644 plugins/kapt3/testData/converter/nestedClassesNonRootPackage.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 2e235b10e5e..3f5935897b7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -99,20 +99,6 @@ public class KotlinTypeMapper { private final boolean isJvm8TargetWithDefaults; private final TypeMappingConfiguration typeMappingConfiguration = new TypeMappingConfiguration() { - private final Function2 defaultClassNameFactory - = TypeMappingConfiguration.Companion.getDEFAULT_INNER_CLASS_NAME_FACTORY(); - - private final Function2 innerClassNameFactory = new Function2() { - @Override - public String invoke(String outer, String inner) { - if (classBuilderMode == ClassBuilderMode.KAPT3) { - return outer + '/' + inner; - } - - return defaultClassNameFactory.invoke(outer, inner); - } - }; - @NotNull @Override public KotlinType commonSupertype(@NotNull Collection types) { @@ -122,7 +108,7 @@ public class KotlinTypeMapper { @NotNull @Override public Function2 getInnerClassNameFactory() { - return innerClassNameFactory; + return TypeMappingConfiguration.DefaultImpls.getInnerClassNameFactory(this); } @Nullable diff --git a/compiler/testData/codegen/kapt/innerClasses.txt b/compiler/testData/codegen/kapt/innerClasses.txt index 67452ed0579..9a572929bae 100644 --- a/compiler/testData/codegen/kapt/innerClasses.txt +++ b/compiler/testData/codegen/kapt/innerClasses.txt @@ -1,23 +1,6 @@ @kotlin.Metadata -public final class test/TopLevel { - public final static field Companion: test.TopLevel.Companion - private final static @org.jetbrains.annotations.NotNull field q: java.lang.String - private final @org.jetbrains.annotations.NotNull field x: java.lang.String - private final field y: int - inner class test/TopLevel/Companion - inner class test/TopLevel/InnerInterface - inner class test/TopLevel/InnerObject - inner class test/TopLevel/NestedClass - public method (): void - public final method b(): void - public final static @org.jetbrains.annotations.NotNull method getQ(): java.lang.String - public final @org.jetbrains.annotations.NotNull method getX(): java.lang.String - public final method getY(): int -} - -@kotlin.Metadata -public final class test/TopLevel/Companion { - inner class test/TopLevel/Companion +public final class test/TopLevel$Companion { + inner class test/TopLevel$Companion private method (): void public final method a(): void public final @org.jetbrains.annotations.NotNull method getQ(): java.lang.String @@ -25,28 +8,45 @@ public final class test/TopLevel/Companion { } @kotlin.Metadata -public interface test/TopLevel/InnerInterface { - inner class test/TopLevel/InnerInterface +public interface test/TopLevel$InnerInterface { + inner class test/TopLevel$InnerInterface } @kotlin.Metadata -public final class test/TopLevel/InnerObject { - public final static field INSTANCE: test.TopLevel.InnerObject - inner class test/TopLevel/InnerObject +public final class test/TopLevel$InnerObject { + public final static field INSTANCE: test.TopLevel$InnerObject + inner class test/TopLevel$InnerObject private method (): void } @kotlin.Metadata -public final class test/TopLevel/NestedClass { - inner class test/TopLevel/NestedClass - inner class test/TopLevel/NestedClass/NestedInnerClass +public final class test/TopLevel$NestedClass$NestedInnerClass { + synthetic final field this$0: test.TopLevel$NestedClass + inner class test/TopLevel$NestedClass + inner class test/TopLevel$NestedClass$NestedInnerClass + public method (p0: test.TopLevel$NestedClass): void +} + +@kotlin.Metadata +public final class test/TopLevel$NestedClass { + inner class test/TopLevel$NestedClass + inner class test/TopLevel$NestedClass$NestedInnerClass public method (): void } @kotlin.Metadata -public final class test/TopLevel/NestedClass/NestedInnerClass { - synthetic final field this$0: test.TopLevel.NestedClass - inner class test/TopLevel/NestedClass - inner class test/TopLevel/NestedClass/NestedInnerClass - public method (p0: test.TopLevel.NestedClass): void +public final class test/TopLevel { + public final static field Companion: test.TopLevel$Companion + private final static @org.jetbrains.annotations.NotNull field q: java.lang.String + private final @org.jetbrains.annotations.NotNull field x: java.lang.String + private final field y: int + inner class test/TopLevel$Companion + inner class test/TopLevel$InnerInterface + inner class test/TopLevel$InnerObject + inner class test/TopLevel$NestedClass + public method (): void + public final method b(): void + public final static @org.jetbrains.annotations.NotNull method getQ(): java.lang.String + public final @org.jetbrains.annotations.NotNull method getX(): java.lang.String + public final method getY(): int } diff --git a/compiler/testData/codegen/kapt/interfaceImpls.txt b/compiler/testData/codegen/kapt/interfaceImpls.txt index f4be136a40a..3a3b6c30b13 100644 --- a/compiler/testData/codegen/kapt/interfaceImpls.txt +++ b/compiler/testData/codegen/kapt/interfaceImpls.txt @@ -1,14 +1,14 @@ @kotlin.Metadata -public interface A { - inner class A/DefaultImpls - public abstract method a(): void - public abstract method b(): void +public final class A$DefaultImpls { + inner class A$DefaultImpls + public static method a(p0: A): void } @kotlin.Metadata -public final class A/DefaultImpls { - inner class A/DefaultImpls - public static method a(p0: A): void +public interface A { + inner class A$DefaultImpls + public abstract method a(): void + public abstract method b(): void } @kotlin.Metadata diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt index 821b274e034..065be129497 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt @@ -47,8 +47,8 @@ private fun JvmTypeFactory.boxTypeIfNeeded(possiblyPrimitiveType: T if (needBoxedType) boxType(possiblyPrimitiveType) else possiblyPrimitiveType interface TypeMappingConfiguration { - companion object { - val DEFAULT_INNER_CLASS_NAME_FACTORY = fun(outer: String, inner: String) = outer + "$" + inner + private companion object { + private val DEFAULT_INNER_CLASS_NAME_FACTORY = fun(outer: String, inner: String) = outer + "$" + inner } val innerClassNameFactory: (outer: String, inner: String) -> String diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index 2f1871380c0..8980ad395b5 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -186,7 +186,7 @@ abstract class AbstractKapt3Extension( private fun generateStubs(project: Project, module: ModuleDescriptor, context: BindingContext, files: Collection): KaptContext<*> { if (!aptMode.generateStubs) { - return KaptContext(logger, BindingContext.EMPTY, emptyList(), emptyMap(), null, options, javacOptions) + return KaptContext(logger, project, BindingContext.EMPTY, emptyList(), emptyMap(), null, options, javacOptions) } logger.info { "Kotlin files to compile: " + files.map { it.virtualFile?.name ?: "" } } @@ -241,7 +241,7 @@ abstract class AbstractKapt3Extension( logger.info { "Stubs compilation took $classFilesCompilationTime ms" } logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } } - return KaptContext(logger, bindingContext, compiledClasses, origins, generationState, options, javacOptions) + return KaptContext(logger, project, bindingContext, compiledClasses, origins, generationState, options, javacOptions) } private fun generateKotlinSourceStubs(kaptContext: KaptContext) { diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt index 77913e2c005..65e7590661e 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptContext.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.kapt3 +import com.intellij.openapi.project.Project import com.sun.tools.javac.file.JavacFileManager import com.sun.tools.javac.jvm.ClassReader import com.sun.tools.javac.main.JavaCompiler @@ -34,6 +35,7 @@ import javax.tools.JavaFileManager class KaptContext( val logger: KaptLogger, + val project: Project, val bindingContext: BindingContext, val compiledClasses: List, val origins: Map, @@ -50,7 +52,7 @@ class KaptContext( init { KaptJavaLog.preRegister(context, logger.messageCollector) JavacFileManager.preRegister(context) - KaptTreeMaker.preRegister(context) + KaptTreeMaker.preRegister(context, this) KaptJavaCompiler.preRegister(context) fileManager = context.get(JavaFileManager::class.java) as JavacFileManager diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt index dd11f9a3d20..d5956400613 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt @@ -16,28 +16,34 @@ package org.jetbrains.kotlin.kapt3.javac +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import com.intellij.psi.search.GlobalSearchScope import com.sun.tools.javac.code.TypeTag import com.sun.tools.javac.tree.JCTree import com.sun.tools.javac.tree.TreeMaker import com.sun.tools.javac.util.Context +import com.sun.tools.javac.util.Name import com.sun.tools.javac.util.Names import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.kapt3.KaptContext import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type.* +import org.jetbrains.org.objectweb.asm.tree.ClassNode -class KaptTreeMaker(context: Context) : TreeMaker(context) { - val nameTable = Names.instance(context).table +class KaptTreeMaker(context: Context, private val kaptContext: KaptContext<*>) : TreeMaker(context) { + val nameTable: Name.Table = Names.instance(context).table fun Type(type: Type): JCTree.JCExpression { convertBuiltinType(type)?.let { return it } if (type.sort == ARRAY) { return TypeArray(Type(AsmUtil.correctElementType(type))) } - return FqName(type.className) + return FqName(type.internalName) } fun FqName(internalOrFqName: String): JCTree.JCExpression { - val path = internalOrFqName.replace('/', '.').convertSpecialFqName().split('.') + val path = getQualifiedName(internalOrFqName.replace('/', '.')).convertSpecialFqName().split('.') assert(path.isNotEmpty()) if (path.size == 1) return SimpleName(path.single()) @@ -48,6 +54,74 @@ class KaptTreeMaker(context: Context) : TreeMaker(context) { return expr } + fun getQualifiedName(type: Type) = getQualifiedName(type.internalName) + + fun getSimpleName(clazz: ClassNode) = getQualifiedName(clazz.name).substringAfterLast('.') + + fun getQualifiedName(internalName: String): String { + val nameWithDots = internalName.replace('/', '.') + // This is a top-level class + if ('$' !in nameWithDots) return nameWithDots + + // Maybe it's in our sources? + val classFromSources = kaptContext.compiledClasses.firstOrNull { it.name == internalName } + if (classFromSources != null) { + // Get inner class node pointing to the outer class + val innerClassNode = classFromSources.innerClasses.firstOrNull { it.name == classFromSources.name } + return innerClassNode?.let { getQualifiedName(it.outerName) + "." + it.innerName } ?: nameWithDots + } + + // Search in the classpath + val javaPsiFacade = JavaPsiFacade.getInstance(kaptContext.project) + val scope = GlobalSearchScope.allScope(javaPsiFacade.project) + + val fqNameFromClassWithPreciseName = javaPsiFacade.findClass(nameWithDots, scope)?.qualifiedName + if (fqNameFromClassWithPreciseName != null) { + return fqNameFromClassWithPreciseName + } + + nameWithDots.iterateDollars { outerName, innerName -> + if (innerName.isEmpty()) return@iterateDollars // We already checked an exact match + + val outerClass = javaPsiFacade.findClass(outerName, scope) ?: return@iterateDollars + return tryToFindNestedClass(outerClass, innerName)?.qualifiedName ?: return@iterateDollars + } + + return nameWithDots + } + + private fun tryToFindNestedClass(outerClass: PsiClass, innerClassName: String): PsiClass? { + outerClass.findInnerClassByName(innerClassName, false)?.let { return it } + + innerClassName.iterateDollars { name1, name2 -> + if (name2.isEmpty()) return outerClass.findInnerClassByName(name1, false) + + val nestedClass = outerClass.findInnerClassByName(name1, false) + if (nestedClass != null) { + tryToFindNestedClass(nestedClass, name2)?.let { return it } + } + } + + return null + } + + private inline fun String.iterateDollars(variantHandler: (outerName: String, innerName: String) -> Unit) { + var dollarIndex = this.indexOf('$') + if (dollarIndex < 0) { + variantHandler(this, "") + return + } + + while (dollarIndex > 0 && dollarIndex < this.lastIndex) { + val outerName = this.take(dollarIndex) + val innerName = this.drop(dollarIndex + 1) + + variantHandler(outerName, innerName) + + dollarIndex = this.indexOf('$', startIndex = dollarIndex + 1) + } + } + private fun String.convertSpecialFqName(): String { // Hard-coded in ImplementationBodyCodegen, KOTLIN_MARKER_INTERFACES if (this == "kotlin.jvm.internal.markers.KMutableMap\$Entry") { @@ -57,7 +131,7 @@ class KaptTreeMaker(context: Context) : TreeMaker(context) { return this } - fun convertBuiltinType(type: Type): JCTree.JCExpression? { + private fun convertBuiltinType(type: Type): JCTree.JCExpression? { val typeTag = when (type) { BYTE_TYPE -> TypeTag.BYTE BOOLEAN_TYPE -> TypeTag.BOOLEAN @@ -75,11 +149,11 @@ class KaptTreeMaker(context: Context) : TreeMaker(context) { fun SimpleName(name: String): JCTree.JCExpression = Ident(name(name)) - fun name(name: String) = nameTable.fromString(name) + fun name(name: String): Name = nameTable.fromString(name) companion object { - internal fun preRegister(context: Context) { - context.put(treeMakerKey, Context.Factory(::KaptTreeMaker)) + internal fun preRegister(context: Context, kaptContext: KaptContext<*>) { + context.put(treeMakerKey, Context.Factory { KaptTreeMaker(it, kaptContext) }) } } } \ No newline at end of file diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index ac4ba724e22..4280ff12d10 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -204,7 +204,7 @@ class ClassFileToSourceStubConverter( if (isEnum) ElementKind.ENUM else ElementKind.CLASS, packageFqName, clazz.visibleAnnotations, clazz.invisibleAnnotations) - val isDefaultImpls = clazz.name.endsWith("${descriptor.name.asString()}/DefaultImpls") + val isDefaultImpls = clazz.name.endsWith("${descriptor.name.asString()}\$DefaultImpls") && isPublic(clazz.access) && isFinal(clazz.access) && descriptor is ClassDescriptor && descriptor.kind == ClassKind.INTERFACE @@ -218,10 +218,10 @@ class ClassFileToSourceStubConverter( val interfaces = mapJList(clazz.interfaces) { if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapJList null - treeMaker.FqName(it) + treeMaker.FqName(treeMaker.getQualifiedName(it)) } - val superClass = treeMaker.FqName(clazz.superName) + val superClass = treeMaker.FqName(treeMaker.getQualifiedName(clazz.superName)) val hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces) @@ -322,15 +322,12 @@ class ClassFileToSourceStubConverter( outerClass: ClassNode? = findContainingClassNode(clazz) ): Boolean { if (outerClass == null) return false - if (clazz.simpleName == outerClass.simpleName) return true + if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true // Try to find the containing class for outerClassNode (to check the whole tree recursively) val containingClassForOuterClass = findContainingClassNode(outerClass) ?: return false return checkIfInnerClassNameConflictsWithOuter(clazz, containingClassForOuterClass) } - private val ClassNode.simpleName: String - get() = name.substringAfterLast(".").substringAfterLast("/") - private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean) = when { (descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE -> { // Classes inside interfaces should always be public and static. @@ -373,7 +370,7 @@ class ClassFileToSourceStubConverter( // Enum type must be an identifier (Javac requirement) val typeExpression = if (isEnum(field.access)) - treeMaker.SimpleName(type.className.substringAfterLast('.')) + treeMaker.SimpleName(treeMaker.getQualifiedName(type).substringAfterLast('.')) else anonymousTypeHandler.getNonAnonymousType(descriptor) { getNonErrorType((descriptor as? CallableDescriptor)?.returnType, @@ -606,7 +603,7 @@ class ClassFileToSourceStubConverter( private fun convertAnnotation(annotation: AnnotationNode, packageFqName: String? = "", filtered: Boolean = true): JCAnnotation? { val annotationType = Type.getType(annotation.desc) - val fqName = annotationType.className + val fqName = treeMaker.getQualifiedName(annotationType) if (filtered) { if (BLACKLISTED_ANNOTATIONS.any { fqName.startsWith(it) }) return null diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/SignatureParserVisitor.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/SignatureParserVisitor.kt index a1c6456b529..84b964cb69d 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/SignatureParserVisitor.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/SignatureParserVisitor.kt @@ -203,7 +203,7 @@ class SignatureParser(val treeMaker: KaptTreeMaker) { val innerClasses = mutableListOf() node.split(typeArgs, TypeArgument, innerClasses, InnerClass) - var expression = makeExpressionForClassTypeWithArguments(treeMaker.FqName(node.name!!.replace('/', '.')), typeArgs) + var expression = makeExpressionForClassTypeWithArguments(treeMaker.FqName(node.name!!), typeArgs) if (innerClasses.isEmpty()) return expression for (innerClass in innerClasses) { diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/errorTypeConversion.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/errorTypeConversion.kt index 3e592ba0452..6170487ef1e 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/errorTypeConversion.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/errorTypeConversion.kt @@ -74,7 +74,7 @@ private fun convertUserType(type: KtUserType, converter: ClassFileToSourceStubCo // This could be List or similar. List should be converted to java.util.List in this case. val referenceTarget = converter.kaptContext.bindingContext[BindingContext.REFERENCE_TARGET, type.referenceExpression] if (referenceTarget is ClassDescriptor) { - treeMaker.FqName(converter.kaptContext.generationState.typeMapper.mapType(referenceTarget.defaultType).className) + treeMaker.FqName(converter.kaptContext.generationState.typeMapper.mapType(referenceTarget.defaultType).internalName) } else { treeMaker.SimpleName(referencedName) diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index 953c7857463..8981b1abcf0 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -61,7 +61,7 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() { val generationState = GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, classBuilderFactory) val logger = KaptLogger(isVerbose = true, messageCollector = messageCollector) - val kaptContext = KaptContext(logger, generationState.bindingContext, classBuilderFactory.compiledClasses, + val kaptContext = KaptContext(logger, generationState.project, generationState.bindingContext, classBuilderFactory.compiledClasses, classBuilderFactory.origins, generationState, processorOptions = emptyMap()) try { check(kaptContext, txtFile, wholeFile) diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java index 9e8be9f4008..c6536c0a6e6 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -228,6 +228,18 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi doTest(fileName); } + @TestMetadata("nestedClasses2.kt") + public void testNestedClasses2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/nestedClasses2.kt"); + doTest(fileName); + } + + @TestMetadata("nestedClassesNonRootPackage.kt") + public void testNestedClassesNonRootPackage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/nestedClassesNonRootPackage.kt"); + doTest(fileName); + } + @TestMetadata("nonExistentClass.kt") public void testNonExistentClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/nonExistentClass.kt"); diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt index 67baa69f5e2..806b282f06c 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/JavaKaptContextTest.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.kapt3.test +import com.intellij.openapi.command.impl.DummyProject import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector import org.jetbrains.kotlin.kapt3.KaptContext @@ -80,6 +81,7 @@ class JavaKaptContextTest { private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) { KaptContext(KaptLogger(isVerbose = true, messageCollector = messageCollector), + DummyProject.getInstance(), bindingContext = BindingContext.EMPTY, compiledClasses = emptyList(), origins = emptyMap(), diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt index 26958e31986..84730351aea 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt @@ -52,10 +52,10 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest() { assert(!File(stubsOutputDir, "test/Simple/InnerClass.java").exists()) assert(File(incrementalDataOutputDir, "test/Simple.class").exists()) - assert(File(incrementalDataOutputDir, "test/Simple/Companion.class").exists()) - assert(File(incrementalDataOutputDir, "test/Simple/InnerClass.class").exists()) - assert(File(incrementalDataOutputDir, "test/Simple/NestedClass.class").exists()) - assert(File(incrementalDataOutputDir, "test/Simple/NestedClass/NestedNestedClass.class").exists()) + assert(File(incrementalDataOutputDir, "test/Simple\$Companion.class").exists()) + assert(File(incrementalDataOutputDir, "test/Simple\$InnerClass.class").exists()) + assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass.class").exists()) + assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass\$NestedNestedClass.class").exists()) assert(bindings.any { it.key == "test/Simple" && it.value.name == "test/Simple.java" }) assert(bindings.none { it.key.contains("Companion") }) diff --git a/plugins/kapt3/testData/converter/nestedClasses2.kt b/plugins/kapt3/testData/converter/nestedClasses2.kt new file mode 100644 index 00000000000..e156a4841e3 --- /dev/null +++ b/plugins/kapt3/testData/converter/nestedClasses2.kt @@ -0,0 +1,78 @@ +// FILE: JavaClass.java +public class JavaClass { + public class Foo { + public class Bar {} + } +} + +//FILE: J$B.java +public class J$B { + public class C {} + + public class D$E { + class F {} + class F$G {} + } + + public class D$$E {} + public class D$$$E {} +} + +// FILE: a.kt +interface IFoo { + interface IBar { + annotation class Anno(vararg val value: kotlin.reflect.KClass<*>) + + @Anno(IZoo::class) + interface IZoo + } +} + +class Experiment { + annotation class Type + + @Type + data class Group(s: String) +} + +class Foo { + open class Bar { + object Zoo + } +} + +class `A$B` { + class C + + @JvmField lateinit var c: C + @JvmField lateinit var de: `D$E` + + @JvmField lateinit var jc: `J$B`.C + @JvmField lateinit var jde: `J$B`.`D$E` + + class `D$E` { + class F + class `F$G` + + @JvmField lateinit var f: F + @JvmField lateinit var fg: `F$G` + + @JvmField lateinit var jf: `J$B`.`D$E`.F + @JvmField lateinit var jfg: `J$B`.`D$E`.`F$G` + } + + class `D$$E` + class `D$$$E` + + @JvmField lateinit var dee: `D$$E` + @JvmField lateinit var deee: `D$$$E` + + @JvmField lateinit var jdee: `J$B`.`D$$E` + @JvmField lateinit var jdeee: `J$B`.`D$$$E` +} + +@IFoo.IBar.Anno(IFoo.IBar.IZoo::class, Foo.Bar::class) +class Test1(val zoo: Foo.Bar.Zoo) : Foo.Bar(), IFoo.IBar, IFoo.IBar.IZoo { + fun a(): Thread.State = Thread.State.NEW + fun b(foo: JavaClass.Foo, bar: JavaClass.Foo.Bar) {} +} \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/nestedClasses2.txt b/plugins/kapt3/testData/converter/nestedClasses2.txt new file mode 100644 index 00000000000..aea2d1e950c --- /dev/null +++ b/plugins/kapt3/testData/converter/nestedClasses2.txt @@ -0,0 +1,192 @@ +@kotlin.Metadata() +public final class A$B { + @org.jetbrains.annotations.NotNull() + public A$B.C c; + @org.jetbrains.annotations.NotNull() + public A$B.D$E de; + @org.jetbrains.annotations.NotNull() + public J$B.C jc; + @org.jetbrains.annotations.NotNull() + public J$B.D$E jde; + @org.jetbrains.annotations.NotNull() + public A$B.D$$E dee; + @org.jetbrains.annotations.NotNull() + public A$B.D$$$E deee; + @org.jetbrains.annotations.NotNull() + public J$B.D$$E jdee; + @org.jetbrains.annotations.NotNull() + public J$B.D$$$E jdeee; + + public A$B() { + super(); + } + + @kotlin.Metadata() + public static final class C { + + public C() { + super(); + } + } + + @kotlin.Metadata() + public static final class D$E { + @org.jetbrains.annotations.NotNull() + public A$B.D$E.F f; + @org.jetbrains.annotations.NotNull() + public A$B.D$E.F$G fg; + @org.jetbrains.annotations.NotNull() + public J$B.D$E.F jf; + @org.jetbrains.annotations.NotNull() + public J$B.D$E.F$G jfg; + + public D$E() { + super(); + } + + @kotlin.Metadata() + public static final class F { + + public F() { + super(); + } + } + + @kotlin.Metadata() + public static final class F$G { + + public F$G() { + super(); + } + } + } + + @kotlin.Metadata() + public static final class D$$E { + + public D$$E() { + super(); + } + } + + @kotlin.Metadata() + public static final class D$$$E { + + public D$$$E() { + super(); + } + } +} + +//////////////////// + + +@kotlin.Metadata() +public final class Experiment { + + public Experiment() { + super(); + } + + @kotlin.Metadata() + @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) + public static abstract @interface Type { + } + + @kotlin.Metadata() + @Experiment.Type() + public static final class Group { + + public Group(@org.jetbrains.annotations.NotNull() + java.lang.String s) { + super(); + } + + @org.jetbrains.annotations.NotNull() + public final Experiment.Group copy(@org.jetbrains.annotations.NotNull() + java.lang.String s) { + return null; + } + } +} + +//////////////////// + + +@kotlin.Metadata() +public final class Foo { + + public Foo() { + super(); + } + + @kotlin.Metadata() + public static class Bar { + + public Bar() { + super(); + } + + @kotlin.Metadata() + public static final class Zoo { + public static final Foo.Bar.Zoo INSTANCE = null; + + private Zoo() { + super(); + } + } + } +} + +//////////////////// + + +@kotlin.Metadata() +public abstract interface IFoo { + + @kotlin.Metadata() + public static abstract interface IBar { + + @kotlin.Metadata() + @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) + public static abstract @interface Anno { + + public abstract java.lang.Class[] value(); + } + + @kotlin.Metadata() + @IFoo.IBar.Anno(value = {IFoo.IBar.IZoo.class}) + public static abstract interface IZoo { + } + } +} + +//////////////////// + + +@kotlin.Metadata() +@IFoo.IBar.Anno(value = {IFoo.IBar.IZoo.class, Foo.Bar.class}) +public final class Test1 extends Foo.Bar implements IFoo.IBar, IFoo.IBar.IZoo { + @org.jetbrains.annotations.NotNull() + private final Foo.Bar.Zoo zoo = null; + + @org.jetbrains.annotations.NotNull() + public final java.lang.Thread.State a() { + return null; + } + + public final void b(@org.jetbrains.annotations.NotNull() + JavaClass.Foo foo, @org.jetbrains.annotations.NotNull() + JavaClass.Foo.Bar bar) { + } + + @org.jetbrains.annotations.NotNull() + public final Foo.Bar.Zoo getZoo() { + return null; + } + + public Test1(@org.jetbrains.annotations.NotNull() + Foo.Bar.Zoo zoo) { + super(); + } +} diff --git a/plugins/kapt3/testData/converter/nestedClassesNonRootPackage.kt b/plugins/kapt3/testData/converter/nestedClassesNonRootPackage.kt new file mode 100644 index 00000000000..9a8218aba97 --- /dev/null +++ b/plugins/kapt3/testData/converter/nestedClassesNonRootPackage.kt @@ -0,0 +1,84 @@ +// FILE: test/JavaClass.java +package test; + +class JavaClass { + class Foo { + class Bar {} + } +} + +//FILE: test/J$B.java +package test; + +public class J$B { + public class C {} + + public class D$E { + class F {} + class F$G {} + } + + public class D$$E {} + public class D$$$E {} +} + +// FILE: a.kt +package test + +interface IFoo { + interface IBar { + annotation class Anno(vararg val value: kotlin.reflect.KClass<*>) + + @Anno(IZoo::class) + interface IZoo + } +} + +class Experiment { + annotation class Type + + @Type + data class Group(s: String) +} + +class Foo { + open class Bar { + object Zoo + } +} + +class `A$B` { + class C + + @JvmField lateinit var c: C + @JvmField lateinit var de: `D$E` + + @JvmField lateinit var jc: `J$B`.C + @JvmField lateinit var jde: `J$B`.`D$E` + + class `D$E` { + class F + class `F$G` + + @JvmField lateinit var f: F + @JvmField lateinit var fg: `F$G` + + @JvmField lateinit var jf: `J$B`.`D$E`.F + @JvmField lateinit var jfg: `J$B`.`D$E`.`F$G` + } + + class `D$$E` + class `D$$$E` + + @JvmField lateinit var dee: `D$$E` + @JvmField lateinit var deee: `D$$$E` + + @JvmField lateinit var jdee: `J$B`.`D$$E` + @JvmField lateinit var jdeee: `J$B`.`D$$$E` +} + +@IFoo.IBar.Anno(IFoo.IBar.IZoo::class, Foo.Bar::class) +class Test1(val zoo: Foo.Bar.Zoo) : Foo.Bar(), IFoo.IBar, IFoo.IBar.IZoo { + fun a(): Thread.State = Thread.State.NEW + fun b(foo: JavaClass.Foo, bar: JavaClass.Foo.Bar) {} +} \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/nestedClassesNonRootPackage.txt b/plugins/kapt3/testData/converter/nestedClassesNonRootPackage.txt new file mode 100644 index 00000000000..a9041858fc6 --- /dev/null +++ b/plugins/kapt3/testData/converter/nestedClassesNonRootPackage.txt @@ -0,0 +1,198 @@ +package test; + +@kotlin.Metadata() +public final class A$B { + @org.jetbrains.annotations.NotNull() + public test.A$B.C c; + @org.jetbrains.annotations.NotNull() + public test.A$B.D$E de; + @org.jetbrains.annotations.NotNull() + public test.J$B.C jc; + @org.jetbrains.annotations.NotNull() + public test.J$B.D$E jde; + @org.jetbrains.annotations.NotNull() + public test.A$B.D$$E dee; + @org.jetbrains.annotations.NotNull() + public test.A$B.D$$$E deee; + @org.jetbrains.annotations.NotNull() + public test.J$B.D$$E jdee; + @org.jetbrains.annotations.NotNull() + public test.J$B.D$$$E jdeee; + + public A$B() { + super(); + } + + @kotlin.Metadata() + public static final class C { + + public C() { + super(); + } + } + + @kotlin.Metadata() + public static final class D$E { + @org.jetbrains.annotations.NotNull() + public test.A$B.D$E.F f; + @org.jetbrains.annotations.NotNull() + public test.A$B.D$E.F$G fg; + @org.jetbrains.annotations.NotNull() + public test.J$B.D$E.F jf; + @org.jetbrains.annotations.NotNull() + public test.J$B.D$E.F$G jfg; + + public D$E() { + super(); + } + + @kotlin.Metadata() + public static final class F { + + public F() { + super(); + } + } + + @kotlin.Metadata() + public static final class F$G { + + public F$G() { + super(); + } + } + } + + @kotlin.Metadata() + public static final class D$$E { + + public D$$E() { + super(); + } + } + + @kotlin.Metadata() + public static final class D$$$E { + + public D$$$E() { + super(); + } + } +} + +//////////////////// + +package test; + +@kotlin.Metadata() +public final class Experiment { + + public Experiment() { + super(); + } + + @kotlin.Metadata() + @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) + public static abstract @interface Type { + } + + @kotlin.Metadata() + @test.Experiment.Type() + public static final class Group { + + public Group(@org.jetbrains.annotations.NotNull() + java.lang.String s) { + super(); + } + + @org.jetbrains.annotations.NotNull() + public final test.Experiment.Group copy(@org.jetbrains.annotations.NotNull() + java.lang.String s) { + return null; + } + } +} + +//////////////////// + +package test; + +@kotlin.Metadata() +public final class Foo { + + public Foo() { + super(); + } + + @kotlin.Metadata() + public static class Bar { + + public Bar() { + super(); + } + + @kotlin.Metadata() + public static final class Zoo { + public static final test.Foo.Bar.Zoo INSTANCE = null; + + private Zoo() { + super(); + } + } + } +} + +//////////////////// + +package test; + +@kotlin.Metadata() +public abstract interface IFoo { + + @kotlin.Metadata() + public static abstract interface IBar { + + @kotlin.Metadata() + @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) + public static abstract @interface Anno { + + public abstract java.lang.Class[] value(); + } + + @kotlin.Metadata() + @test.IFoo.IBar.Anno(value = {test.IFoo.IBar.IZoo.class}) + public static abstract interface IZoo { + } + } +} + +//////////////////// + +package test; + +@kotlin.Metadata() +@test.IFoo.IBar.Anno(value = {test.IFoo.IBar.IZoo.class, test.Foo.Bar.class}) +public final class Test1 extends test.Foo.Bar implements test.IFoo.IBar, test.IFoo.IBar.IZoo { + @org.jetbrains.annotations.NotNull() + private final test.Foo.Bar.Zoo zoo = null; + + @org.jetbrains.annotations.NotNull() + public final java.lang.Thread.State a() { + return null; + } + + public final void b(@org.jetbrains.annotations.NotNull() + test.JavaClass.Foo foo, @org.jetbrains.annotations.NotNull() + test.JavaClass.Foo.Bar bar) { + } + + @org.jetbrains.annotations.NotNull() + public final test.Foo.Bar.Zoo getZoo() { + return null; + } + + public Test1(@org.jetbrains.annotations.NotNull() + test.Foo.Bar.Zoo zoo) { + super(); + } +}