Kapt3: Ensure that field types and method return types are not anonymous (KT-14997)
This commit is contained in:
committed by
Yan Zhulanow
parent
01c76153c7
commit
b9a0a4f3db
+6
@@ -92,6 +92,12 @@ open class PartialAnalysisHandlerExtension : AnalysisHandlerExtension {
|
||||
}
|
||||
}
|
||||
}
|
||||
is FunctionDescriptor -> {
|
||||
// is body expression (not unit)
|
||||
if (declaration is KtFunction && !declaration.hasDeclaredReturnType() && !declaration.hasBlockBody()) {
|
||||
ForceResolveUtil.forceResolveAllContents(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+44
-11
@@ -29,7 +29,10 @@ import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
|
||||
import org.jetbrains.kotlin.kapt3.util.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -193,17 +196,17 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
private fun convertField(field: FieldNode, packageFqName: String): JCVariableDecl? {
|
||||
if (isSynthetic(field.access)) return null
|
||||
val descriptor = kaptContext.origins[field]?.descriptor
|
||||
|
||||
val modifiers = convertModifiers(field.access, ElementKind.FIELD, packageFqName, field.visibleAnnotations, field.invisibleAnnotations)
|
||||
val name = treeMaker.name(field.name)
|
||||
val type = Type.getType(field.desc)
|
||||
|
||||
// Enum type must be an identifier (Javac requirement)
|
||||
val typeExpression = if (isEnum(field.access)) {
|
||||
val typeExpression = if (isEnum(field.access))
|
||||
treeMaker.SimpleName(type.className.substringAfterLast('.'))
|
||||
} else {
|
||||
signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type))
|
||||
}
|
||||
else
|
||||
getNotAnonymousType(descriptor) { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) }
|
||||
|
||||
val value = field.value
|
||||
|
||||
@@ -234,8 +237,8 @@ class ClassFileToSourceStubConverter(
|
||||
method.access.toLong(),
|
||||
ElementKind.METHOD, packageFqName, visibleAnnotations, method.invisibleAnnotations)
|
||||
|
||||
val returnType = Type.getReturnType(method.desc)
|
||||
val jcReturnType = if (isConstructor) null else treeMaker.Type(returnType)
|
||||
val asmReturnType = Type.getReturnType(method.desc)
|
||||
val jcReturnType = if (isConstructor) null else treeMaker.Type(asmReturnType)
|
||||
|
||||
val parametersInfo = method.getParametersInfo(containingClass)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
@@ -258,7 +261,8 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
val exceptionTypes = mapJList(method.exceptions) { treeMaker.FqName(it) }
|
||||
|
||||
val genericType = signatureParser.parseMethodSignature(method.signature, parameters, exceptionTypes, jcReturnType)
|
||||
val genericSignature = signatureParser.parseMethodSignature(method.signature, parameters, exceptionTypes, jcReturnType)
|
||||
val returnType = getNotAnonymousType(descriptor) { genericSignature.returnType }
|
||||
|
||||
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
|
||||
|
||||
@@ -285,19 +289,48 @@ class ClassFileToSourceStubConverter(
|
||||
}
|
||||
|
||||
treeMaker.Block(0, superClassConstructorCall)
|
||||
} else if (returnType == Type.VOID_TYPE) {
|
||||
} else if (asmReturnType == Type.VOID_TYPE) {
|
||||
treeMaker.Block(0, JavacList.nil())
|
||||
} else {
|
||||
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(returnType)))
|
||||
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(asmReturnType)))
|
||||
treeMaker.Block(0, JavacList.of(returnStatement))
|
||||
}
|
||||
|
||||
return treeMaker.MethodDef(
|
||||
modifiers, name, genericType.returnType, genericType.typeParameters,
|
||||
genericType.parameterTypes, genericType.exceptionTypes,
|
||||
modifiers, name, returnType, genericSignature.typeParameters,
|
||||
genericSignature.parameterTypes, genericSignature.exceptionTypes,
|
||||
body, defaultValue)
|
||||
}
|
||||
|
||||
private inline fun <T : JCExpression?> getNotAnonymousType(descriptor: DeclarationDescriptor?, f: () -> T): T {
|
||||
if (descriptor is CallableDescriptor) {
|
||||
val returnTypeDescriptor = descriptor.returnType?.constructor?.declarationDescriptor
|
||||
if (returnTypeDescriptor is ClassDescriptor && DescriptorUtils.isAnonymousObject(returnTypeDescriptor)) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return getMostSuitableSuperTypeForAnonymousType(returnTypeDescriptor) as T
|
||||
}
|
||||
}
|
||||
|
||||
return f()
|
||||
}
|
||||
|
||||
private fun getMostSuitableSuperTypeForAnonymousType(typeDescriptor: ClassDescriptor): JCExpression {
|
||||
val superClass = typeDescriptor.getSuperClassNotAny()
|
||||
if (superClass != null) {
|
||||
return treeMaker.Type(typeMapper.mapType(superClass))
|
||||
} else {
|
||||
val sortedSuperTypes = typeDescriptor.typeConstructor.supertypes
|
||||
.sortedBy { it.constructor.declarationDescriptor?.name?.asString() ?: "" }
|
||||
|
||||
for (superType in sortedSuperTypes) {
|
||||
if (superType.isAnyOrNullableAny()) continue
|
||||
return treeMaker.Type(typeMapper.mapType(superType))
|
||||
}
|
||||
}
|
||||
|
||||
return treeMaker.FqName("java.lang.Object")
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun convertModifiers(
|
||||
access: Int,
|
||||
|
||||
+6
@@ -120,6 +120,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt14997.kt")
|
||||
public void testKt14997() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/kt14997.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("modifiers.kt")
|
||||
public void testModifiers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/modifiers.kt");
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
@file:Suppress("AMBIGUOUS_ANONYMOUS_TYPE_INFERRED")
|
||||
|
||||
open class CrashMe {
|
||||
private val notReally = object : Runnable {
|
||||
override fun run() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun a() = object : Runnable {
|
||||
override fun run() {}
|
||||
}
|
||||
|
||||
fun b() = object : java.io.Serializable, Runnable {
|
||||
override fun run() {}
|
||||
}
|
||||
|
||||
fun c() = object : CrashMe(), Runnable {
|
||||
override fun run() {}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
public class CrashMe {
|
||||
private final java.lang.Runnable notReally = null;
|
||||
|
||||
public CrashMe() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
@kotlin.Suppress(names = {"AMBIGUOUS_ANONYMOUS_TYPE_INFERRED"})
|
||||
public final class Kt14997Kt {
|
||||
|
||||
public Kt14997Kt() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static final java.lang.Runnable a() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final java.lang.Runnable b() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final CrashMe c() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user