Kapt: Fix "no interface expected here" in class implementing interface with secondary constructor (KT-27506)
This commit is contained in:
+35
-22
@@ -467,36 +467,49 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?: return Pair(null, emptyList())
|
||||
|
||||
val resolvedSuperTypes = superTypeEntries
|
||||
.map { it to kaptContext.bindingContext[BindingContext.TYPE, it.typeReference] }
|
||||
val classEntries = mutableListOf<KtSuperTypeListEntry>()
|
||||
val interfaceEntries = mutableListOf<KtSuperTypeListEntry>()
|
||||
val otherEntries = mutableListOf<KtSuperTypeListEntry>()
|
||||
|
||||
val (resolvedAsClasses, otherSuperTypes) = resolvedSuperTypes
|
||||
.partition {
|
||||
it.second?.isError == false
|
||||
&& (it.second?.constructor?.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.CLASS
|
||||
for (entry in superTypeEntries) {
|
||||
val type = kaptContext.bindingContext[BindingContext.TYPE, entry.typeReference]
|
||||
val classDescriptor = type?.constructor?.declarationDescriptor as? ClassDescriptor
|
||||
|
||||
if (type != null && !type.isError && classDescriptor != null) {
|
||||
val container = if (classDescriptor.kind == ClassKind.INTERFACE) interfaceEntries else classEntries
|
||||
container += entry
|
||||
continue
|
||||
}
|
||||
|
||||
if (resolvedAsClasses.size > 1) {
|
||||
if (entry is KtSuperTypeCallEntry) {
|
||||
classEntries += entry
|
||||
continue
|
||||
}
|
||||
|
||||
otherEntries += entry
|
||||
}
|
||||
|
||||
for (entry in otherEntries) {
|
||||
if (classEntries.isEmpty()) {
|
||||
if (declaration is KtClass && !declaration.isInterface() && declaration.hasOnlySecondaryConstructors()) {
|
||||
classEntries += entry
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
interfaceEntries += entry
|
||||
}
|
||||
|
||||
if (classEntries.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 (withParenthesis, withoutParenthesis) = superTypeEntries.partition { it is KtSuperTypeCallEntry }
|
||||
return Pair(classEntries.firstOrNull()?.typeReference, interfaceEntries.mapNotNull { it.typeReference })
|
||||
}
|
||||
|
||||
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 })
|
||||
}
|
||||
|
||||
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 fun KtClass.hasOnlySecondaryConstructors(): Boolean {
|
||||
return primaryConstructor == null && secondaryConstructors.isNotEmpty()
|
||||
}
|
||||
|
||||
private tailrec fun checkIfValidTypeName(containingClass: ClassNode, type: Type): Boolean {
|
||||
|
||||
+5
@@ -369,6 +369,11 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/repeatableAnnotations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("secondaryConstructor.kt")
|
||||
public void testSecondaryConstructor() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/secondaryConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("severalPackageParts.kt")
|
||||
public void testSeveralPackageParts() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/severalPackageParts.kt");
|
||||
|
||||
+2
-2
@@ -176,7 +176,7 @@ package test;
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TFooBar extends Foo implements Bar, test.Intf {
|
||||
public final class TFooBar extends Foo implements test.Intf, Bar {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final X a = null;
|
||||
|
||||
@@ -310,7 +310,7 @@ package test;
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class TxFooxBarxBaz extends x.Foo implements x.Bar, x.Baz, test.Intf {
|
||||
public final class TxFooxBarxBaz extends x.Foo implements test.Intf, x.Bar, x.Baz {
|
||||
|
||||
public TxFooxBarxBaz() {
|
||||
super();
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// CORRECT_ERROR_TYPES
|
||||
|
||||
package secondary
|
||||
|
||||
interface Named {
|
||||
val name: String?
|
||||
}
|
||||
|
||||
class Product2 : Named {
|
||||
override var name: String? = null
|
||||
|
||||
constructor(otherName: String) {
|
||||
this.name = otherName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package secondary;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public abstract interface Named {
|
||||
|
||||
@org.jetbrains.annotations.Nullable()
|
||||
public abstract java.lang.String getName();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
package secondary;
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class Product2 implements secondary.Named {
|
||||
@org.jetbrains.annotations.Nullable()
|
||||
private java.lang.String name;
|
||||
|
||||
@org.jetbrains.annotations.Nullable()
|
||||
@java.lang.Override()
|
||||
public java.lang.String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setName(@org.jetbrains.annotations.Nullable()
|
||||
java.lang.String p0) {
|
||||
}
|
||||
|
||||
public Product2(@org.jetbrains.annotations.NotNull()
|
||||
java.lang.String otherName) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user