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.javac.KaptJavaFileObject
|
||||||
import org.jetbrains.kotlin.kapt3.util.*
|
import org.jetbrains.kotlin.kapt3.util.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
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.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
@@ -193,17 +196,17 @@ class ClassFileToSourceStubConverter(
|
|||||||
|
|
||||||
private fun convertField(field: FieldNode, packageFqName: String): JCVariableDecl? {
|
private fun convertField(field: FieldNode, packageFqName: String): JCVariableDecl? {
|
||||||
if (isSynthetic(field.access)) return null
|
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 modifiers = convertModifiers(field.access, ElementKind.FIELD, packageFqName, field.visibleAnnotations, field.invisibleAnnotations)
|
||||||
val name = treeMaker.name(field.name)
|
val name = treeMaker.name(field.name)
|
||||||
val type = Type.getType(field.desc)
|
val type = Type.getType(field.desc)
|
||||||
|
|
||||||
// Enum type must be an identifier (Javac requirement)
|
// 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('.'))
|
treeMaker.SimpleName(type.className.substringAfterLast('.'))
|
||||||
} else {
|
else
|
||||||
signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type))
|
getNotAnonymousType(descriptor) { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) }
|
||||||
}
|
|
||||||
|
|
||||||
val value = field.value
|
val value = field.value
|
||||||
|
|
||||||
@@ -234,8 +237,8 @@ class ClassFileToSourceStubConverter(
|
|||||||
method.access.toLong(),
|
method.access.toLong(),
|
||||||
ElementKind.METHOD, packageFqName, visibleAnnotations, method.invisibleAnnotations)
|
ElementKind.METHOD, packageFqName, visibleAnnotations, method.invisibleAnnotations)
|
||||||
|
|
||||||
val returnType = Type.getReturnType(method.desc)
|
val asmReturnType = Type.getReturnType(method.desc)
|
||||||
val jcReturnType = if (isConstructor) null else treeMaker.Type(returnType)
|
val jcReturnType = if (isConstructor) null else treeMaker.Type(asmReturnType)
|
||||||
|
|
||||||
val parametersInfo = method.getParametersInfo(containingClass)
|
val parametersInfo = method.getParametersInfo(containingClass)
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
@@ -258,7 +261,8 @@ class ClassFileToSourceStubConverter(
|
|||||||
|
|
||||||
val exceptionTypes = mapJList(method.exceptions) { treeMaker.FqName(it) }
|
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) }
|
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
|
||||||
|
|
||||||
@@ -285,19 +289,48 @@ class ClassFileToSourceStubConverter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
treeMaker.Block(0, superClassConstructorCall)
|
treeMaker.Block(0, superClassConstructorCall)
|
||||||
} else if (returnType == Type.VOID_TYPE) {
|
} else if (asmReturnType == Type.VOID_TYPE) {
|
||||||
treeMaker.Block(0, JavacList.nil())
|
treeMaker.Block(0, JavacList.nil())
|
||||||
} else {
|
} else {
|
||||||
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(returnType)))
|
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(asmReturnType)))
|
||||||
treeMaker.Block(0, JavacList.of(returnStatement))
|
treeMaker.Block(0, JavacList.of(returnStatement))
|
||||||
}
|
}
|
||||||
|
|
||||||
return treeMaker.MethodDef(
|
return treeMaker.MethodDef(
|
||||||
modifiers, name, genericType.returnType, genericType.typeParameters,
|
modifiers, name, returnType, genericSignature.typeParameters,
|
||||||
genericType.parameterTypes, genericType.exceptionTypes,
|
genericSignature.parameterTypes, genericSignature.exceptionTypes,
|
||||||
body, defaultValue)
|
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")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline fun convertModifiers(
|
private inline fun convertModifiers(
|
||||||
access: Int,
|
access: Int,
|
||||||
|
|||||||
+6
@@ -120,6 +120,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("modifiers.kt")
|
||||||
public void testModifiers() throws Exception {
|
public void testModifiers() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/modifiers.kt");
|
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