Kapt: Support also erroneous super interface names

This commit is contained in:
Yan Zhulanow
2018-09-04 22:30:45 +03:00
parent dfff00d55f
commit c517b85de1
11 changed files with 449 additions and 73 deletions
@@ -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 {
@@ -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");
@@ -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);
}
@@ -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>
@@ -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() {
}