Kapt: Support also erroneous super interface names
This commit is contained in:
+84
-12
@@ -52,7 +52,9 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -322,7 +324,6 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
val superClass = treeMaker.FqName(treeMaker.getQualifiedName(clazz.superName))
|
||||
|
||||
val hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum
|
||||
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
|
||||
|
||||
class EnumValueData(val field: FieldNode, val innerClass: InnerClassNode?, val correspondingClass: ClassNode?)
|
||||
@@ -386,28 +387,99 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
lineMappings.registerClass(clazz)
|
||||
|
||||
val superTypes = calculateSuperTypes(clazz, genericType)
|
||||
|
||||
return treeMaker.ClassDef(
|
||||
modifiers,
|
||||
treeMaker.name(simpleName),
|
||||
genericType.typeParameters,
|
||||
if (hasSuperClass) genericType.superClass else getSuperType(descriptor as? ClassDescriptor),
|
||||
genericType.interfaces,
|
||||
superTypes.superClass,
|
||||
superTypes.interfaces,
|
||||
enumValues + fields + methods + nestedClasses).keepKdocComments(clazz)
|
||||
}
|
||||
|
||||
private inline fun getSuperType(classDescriptor: ClassDescriptor?): JCExpression? {
|
||||
private class ClassSupertypes(val superClass: JCExpression?, val interfaces: JavacList<JCExpression>)
|
||||
|
||||
private fun calculateSuperTypes(clazz: ClassNode, genericType: SignatureParser.ClassGenericSignature): ClassSupertypes {
|
||||
val hasSuperClass = clazz.superName != "java/lang/Object" && !clazz.isEnum()
|
||||
|
||||
val defaultSuperTypes = ClassSupertypes(
|
||||
if (hasSuperClass) genericType.superClass else null,
|
||||
genericType.interfaces
|
||||
)
|
||||
|
||||
if (!correctErrorTypes) {
|
||||
return defaultSuperTypes
|
||||
}
|
||||
|
||||
val declaration = kaptContext.origins[clazz]?.element as? KtClassOrObject ?: return defaultSuperTypes
|
||||
|
||||
val (superClass, superInterfaces) = partitionSuperTypes(declaration) ?: return defaultSuperTypes
|
||||
|
||||
val sameSuperClassCount = (superClass == null) == (defaultSuperTypes.superClass == null)
|
||||
val sameSuperInterfaceCount = superInterfaces.size == defaultSuperTypes.interfaces.size
|
||||
|
||||
if (sameSuperClassCount && sameSuperInterfaceCount) {
|
||||
return defaultSuperTypes
|
||||
}
|
||||
|
||||
class SuperTypeCalculationFailure : RuntimeException()
|
||||
|
||||
fun nonErrorType(ref: () -> KtTypeReference?): JCExpression {
|
||||
assert(correctErrorTypes)
|
||||
|
||||
return getNonErrorType<JCExpression>(
|
||||
ErrorUtils.createErrorType("Error super class"),
|
||||
ErrorTypeCorrector.TypeKind.SUPER_TYPE,
|
||||
ref
|
||||
) { throw SuperTypeCalculationFailure() }
|
||||
}
|
||||
|
||||
return try {
|
||||
ClassSupertypes(
|
||||
superClass?.let { nonErrorType { it } },
|
||||
mapJList(superInterfaces) { nonErrorType { it } }
|
||||
)
|
||||
} catch (e: SuperTypeCalculationFailure) {
|
||||
defaultSuperTypes
|
||||
}
|
||||
}
|
||||
|
||||
private fun partitionSuperTypes(declaration: KtClassOrObject): Pair<KtTypeReference?, List<KtTypeReference>>? {
|
||||
val superTypeEntries = declaration.superTypeListEntries
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?: return Pair(null, emptyList())
|
||||
|
||||
val resolvedSuperTypes = superTypeEntries
|
||||
.map { it to kaptContext.bindingContext[BindingContext.TYPE, it.typeReference] }
|
||||
|
||||
val (resolvedAsClasses, otherSuperTypes) = resolvedSuperTypes
|
||||
.partition {
|
||||
it.second?.isError == false
|
||||
&& (it.second?.constructor?.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.CLASS
|
||||
}
|
||||
|
||||
if (resolvedAsClasses.size > 1) {
|
||||
// Error in user code, several entries were resolved to classes
|
||||
return null
|
||||
} else if (resolvedAsClasses.size == 1) {
|
||||
return Pair(resolvedAsClasses.single().first.typeReference, otherSuperTypes.mapNotNull { it.first.typeReference })
|
||||
}
|
||||
val ktClass = (classDescriptor?.source as? PsiSourceElement)?.psi as? KtClass
|
||||
val superTypeCallEntry =
|
||||
ktClass?.getSuperTypeList()?.entries?.mapNotNull { it as? KtSuperTypeCallEntry }?.first()
|
||||
val typeFromSource = superTypeCallEntry?.typeReference?.typeElement
|
||||
val ktFile = typeFromSource?.containingKtFile
|
||||
if (ktFile != null) {
|
||||
return ErrorTypeCorrector(this, SUPER_TYPE, ktFile).convert(typeFromSource, emptyMap())
|
||||
|
||||
val (withParenthesis, withoutParenthesis) = superTypeEntries.partition { it is KtSuperTypeCallEntry }
|
||||
|
||||
if (withParenthesis.size > 1) {
|
||||
// Error in user code, several entries with super constructor call
|
||||
return null
|
||||
} else if (withParenthesis.size == 1) {
|
||||
return Pair(withParenthesis.single().typeReference, withoutParenthesis.mapNotNull { it.typeReference })
|
||||
}
|
||||
return null
|
||||
|
||||
if (declaration is KtClass && declaration.primaryConstructor == null && declaration.secondaryConstructors.isNotEmpty()) {
|
||||
return Pair(superTypeEntries.first().typeReference, superTypeEntries.drop(1).mapNotNull { it.typeReference })
|
||||
}
|
||||
|
||||
return Pair(null, superTypeEntries.mapNotNull { it.typeReference })
|
||||
}
|
||||
|
||||
private tailrec fun checkIfValidTypeName(containingClass: ClassNode, type: Type): Boolean {
|
||||
|
||||
+10
@@ -89,6 +89,16 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/errorLocationMapping.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("errorSuperclass.kt")
|
||||
public void testErrorSuperclass() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/errorSuperclass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("errorSuperclassCorrectErrorTypes.kt")
|
||||
public void testErrorSuperclassCorrectErrorTypes() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/errorSuperclassCorrectErrorTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("fileFacadeJvmName.kt")
|
||||
public void testFileFacadeJvmName() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/fileFacadeJvmName.kt");
|
||||
|
||||
-14
@@ -50,20 +50,6 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
|
||||
assertEquals("myMethod", annotatedElements.single().simpleName.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSuperclass() = test("Superclass", "test.MyAnnotation") { set, roundEnv, env ->
|
||||
if (set.size == 1) {
|
||||
val annotatedElements = roundEnv.getElementsAnnotatedWith(set.single())
|
||||
assertEquals(1, annotatedElements.size)
|
||||
val typeElement = annotatedElements.single() as TypeElement
|
||||
assertEquals("FooBar", typeElement.superclass.toString())
|
||||
env.filer.createSourceFile("test.FooBar").openWriter().use { writer ->
|
||||
writer.write("package test;")
|
||||
writer.write("public class FooBar {}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testComments() = test("Simple", "test.MyAnnotation") { set, roundEnv, env ->
|
||||
fun commentOf(className: String) = env.elementUtils.getDocComment(env.elementUtils.getTypeElement(className))
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
// CORRECT_ERROR_TYPES
|
||||
|
||||
// EXPECTED_ERROR(kotlin:16:1) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:19:34) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:19:50) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:19:62) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:26:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:27:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:30:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:18:1) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:21:34) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:21:50) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:21:62) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:23:1) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:24:1) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:28:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:29:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:32:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:35:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:34:5) cannot find symbol
|
||||
// EXPECTED_ERROR(kotlin:37:5) cannot find symbol
|
||||
|
||||
@file:Suppress("UNRESOLVED_REFERENCE", "ANNOTATION_ARGUMENT_MUST_BE_CONST", "NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION")
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -134,7 +134,7 @@ public final class ErrorInDeclarations {
|
||||
import kotlin.reflect.KClass;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class ErrorInSupertype {
|
||||
public final class ErrorInSupertype implements ABC {
|
||||
|
||||
public ErrorInSupertype() {
|
||||
super();
|
||||
@@ -147,7 +147,7 @@ public final class ErrorInSupertype {
|
||||
import kotlin.reflect.KClass;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class ErrorInSupertype2 {
|
||||
public final class ErrorInSupertype2 extends ABC<java.lang.String> {
|
||||
|
||||
public ErrorInSupertype2() {
|
||||
super();
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
internal annotation class Anno
|
||||
|
||||
@Anno
|
||||
@Suppress("UNRESOLVED_REFERENCE")
|
||||
internal class ClassWithParent: Foo(), Bar, Baz, CharSequence
|
||||
@@ -0,0 +1,38 @@
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
public abstract @interface Anno {
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Suppress(names = {"UNRESOLVED_REFERENCE"})
|
||||
@kotlin.Metadata()
|
||||
@Anno()
|
||||
public final class ClassWithParent implements java.lang.CharSequence {
|
||||
|
||||
public ClassWithParent() {
|
||||
super();
|
||||
}
|
||||
|
||||
@java.lang.Override()
|
||||
public final int length() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract int getLength();
|
||||
|
||||
@java.lang.Override()
|
||||
public final char charAt(int p0) {
|
||||
return '\u0000';
|
||||
}
|
||||
|
||||
public abstract char get(int p0);
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// CORRECT_ERROR_TYPES
|
||||
// NO_VALIDATION
|
||||
|
||||
@file:Suppress("UNRESOLVED_REFERENCE", "DELEGATION_NOT_TO_INTERFACE", "SUPERTYPE_NOT_INITIALIZED")
|
||||
package test
|
||||
|
||||
interface Intf
|
||||
|
||||
open class Cl
|
||||
|
||||
class TFooBarBaz: Foo(), Bar, Baz
|
||||
|
||||
// Error, two ()
|
||||
class TFooBarBaz2: Foo(), Bar(), Baz, Intf
|
||||
|
||||
class TFooBarBaz3 : Foo, Bar, Baz
|
||||
|
||||
class TFooBarBaz4() : Foo, Bar, Baz
|
||||
|
||||
class TFooBarBaz5() : Foo, Bar, Baz {
|
||||
constructor(s: String) {}
|
||||
}
|
||||
|
||||
class TFooBarBaz6 : Foo, Bar, Baz {
|
||||
constructor(s: String) : super(s)
|
||||
}
|
||||
|
||||
class TClBarBaz : Cl, Bar, Baz
|
||||
|
||||
class TBarBazCl : Bar, Baz, Cl
|
||||
|
||||
class TFooBar(val a: X) : Foo(), Bar by a, Intf
|
||||
|
||||
class TFooBar2(val a: X): Foo by a, Bar by a
|
||||
|
||||
class TxFooxBarxBaz : x.Foo(), x.Bar, x.Baz, Intf
|
||||
|
||||
// Error, two ()
|
||||
class TxFooxBarxBaz2 : x.Foo(), x.Bar, x.Baz()
|
||||
|
||||
class Generics1 : Foo<String>()
|
||||
|
||||
class Generics2 : Foo<String>
|
||||
|
||||
class Generics3 : Foo<Bar, Baz, Boo<Baz, List<*>>, String>
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public class Cl {
|
||||
|
||||
public Cl() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class Generics1 extends Foo<java.lang.String> {
|
||||
|
||||
public Generics1() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class Generics2 implements Foo<java.lang.String> {
|
||||
|
||||
public Generics2() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class Generics3 implements Foo<Bar, Baz, Boo<Baz, java.util.List<?>>, java.lang.String> {
|
||||
|
||||
public Generics3() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public abstract interface Intf {
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TBarBazCl extends test.Cl implements Bar, Baz {
|
||||
|
||||
public TBarBazCl() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TClBarBaz extends test.Cl implements Bar, Baz {
|
||||
|
||||
public TClBarBaz() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBar extends Foo implements Bar, test.Intf {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final X a = null;
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final X getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public TFooBar(@org.jetbrains.annotations.NotNull()
|
||||
X a) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBar2 implements Foo, Bar {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final X a = null;
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final X getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public TFooBar2(@org.jetbrains.annotations.NotNull()
|
||||
X a) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBarBaz extends Foo implements Bar, Baz {
|
||||
|
||||
public TFooBarBaz() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBarBaz2 implements test.Intf {
|
||||
|
||||
public TFooBarBaz2() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBarBaz3 implements Foo, Bar, Baz {
|
||||
|
||||
public TFooBarBaz3() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBarBaz4 implements Foo, Bar, Baz {
|
||||
|
||||
public TFooBarBaz4() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBarBaz5 implements Foo, Bar, Baz {
|
||||
|
||||
public TFooBarBaz5() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TFooBarBaz5(@org.jetbrains.annotations.NotNull()
|
||||
java.lang.String s) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBarBaz6 extends Foo implements Bar, Baz {
|
||||
|
||||
public TFooBarBaz6(@org.jetbrains.annotations.NotNull()
|
||||
java.lang.String s) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TxFooxBarxBaz extends x.Foo implements x.Bar, x.Baz, test.Intf {
|
||||
|
||||
public TxFooxBarxBaz() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TxFooxBarxBaz2 {
|
||||
|
||||
public TxFooxBarxBaz2() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package error;
|
||||
|
||||
public final class NonExistentClass {
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
@MyAnnotation()
|
||||
public final class ClassWithParent extends FooBar {
|
||||
|
||||
public ClassWithParent() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package test;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
public abstract @interface MyAnnotation {
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package test
|
||||
|
||||
internal annotation class MyAnnotation
|
||||
|
||||
@MyAnnotation
|
||||
internal class ClassWithParent: FooBar() {
|
||||
}
|
||||
Reference in New Issue
Block a user