From b9a0a4f3db8af559cdc8e2c3e7b48ec0a13e6a69 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Tue, 29 Nov 2016 20:50:36 +0300 Subject: [PATCH] Kapt3: Ensure that field types and method return types are not anonymous (KT-14997) --- .../PartialAnalysisHandlerExtension.kt | 6 ++ .../stubs/ClassFileToSourceStubConverter.kt | 55 +++++++++++++++---- ...ileToSourceStubConverterTestGenerated.java | 6 ++ plugins/kapt3/testData/converter/kt14997.kt | 21 +++++++ plugins/kapt3/testData/converter/kt14997.txt | 30 ++++++++++ 5 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 plugins/kapt3/testData/converter/kt14997.kt create mode 100644 plugins/kapt3/testData/converter/kt14997.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/PartialAnalysisHandlerExtension.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/PartialAnalysisHandlerExtension.kt index 9aeab343150..15b52399246 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/PartialAnalysisHandlerExtension.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/extensions/PartialAnalysisHandlerExtension.kt @@ -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) + } + } } } diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index 7de43c710a3..6a949d0a7b0 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -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 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, diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java index 363ac9564ba..0ede69c1756 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -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"); diff --git a/plugins/kapt3/testData/converter/kt14997.kt b/plugins/kapt3/testData/converter/kt14997.kt new file mode 100644 index 00000000000..443d7c3dca7 --- /dev/null +++ b/plugins/kapt3/testData/converter/kt14997.kt @@ -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() {} +} \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/kt14997.txt b/plugins/kapt3/testData/converter/kt14997.txt new file mode 100644 index 00000000000..e63f81befba --- /dev/null +++ b/plugins/kapt3/testData/converter/kt14997.txt @@ -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; + } +}