Kapt3: Ensure that field types and method return types are not anonymous (KT-14997)

This commit is contained in:
Yan Zhulanow
2016-11-29 20:50:36 +03:00
committed by Yan Zhulanow
parent 01c76153c7
commit b9a0a4f3db
5 changed files with 107 additions and 11 deletions
@@ -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)
}
}
}
}
@@ -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,
@@ -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
View File
@@ -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
View File
@@ -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;
}
}