mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-05-06 15:53:19 +00:00
[KAPT] Fix stub generation for anonymous delegates
Replace anonymous classes with superclass in delegate properties #KT-34838 Fixed
This commit is contained in:
@@ -5,17 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||
import org.jetbrains.kotlin.kapt3.util.replaceAnonymousTypeWithSuperType
|
||||
import org.jetbrains.kotlin.resolve.DeclarationSignatureAnonymousTypeTransformer
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isLocal
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
class KaptAnonymousTypeTransformer(
|
||||
private val analysisExtension: PartialAnalysisHandlerExtension
|
||||
@@ -29,46 +24,6 @@ class KaptAnonymousTypeTransformer(
|
||||
return type
|
||||
}
|
||||
|
||||
return convertPossiblyAnonymousType(type)
|
||||
return replaceAnonymousTypeWithSuperType(type)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun convertPossiblyAnonymousType(type: KotlinType): KotlinType {
|
||||
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
val elementTypeProjection = type.arguments.singleOrNull()
|
||||
if (elementTypeProjection != null && !elementTypeProjection.isStarProjection) {
|
||||
return type.builtIns.getArrayType(
|
||||
elementTypeProjection.projectionKind,
|
||||
convertPossiblyAnonymousType(elementTypeProjection.type)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualType = when {
|
||||
isAnonymousObject(declaration) || DescriptorUtils.isLocal(declaration) -> {
|
||||
if (type.constructor.supertypes.size == 1) {
|
||||
convertPossiblyAnonymousType(type.constructor.supertypes.iterator().next())
|
||||
} else {
|
||||
/*
|
||||
Frontend reports an error on public properties in this case,
|
||||
but we ignore errors when making stubs, so there should be a reasonable fallback.
|
||||
*/
|
||||
type.builtIns.anyType
|
||||
}
|
||||
}
|
||||
else -> type
|
||||
}
|
||||
|
||||
if (actualType.arguments.isEmpty()) return actualType
|
||||
|
||||
val arguments = actualType.arguments.map { typeArg ->
|
||||
if (typeArg.isStarProjection)
|
||||
return@map typeArg
|
||||
|
||||
TypeProjectionImpl(typeArg.projectionKind, convertPossiblyAnonymousType(typeArg.type))
|
||||
}
|
||||
|
||||
return actualType.replace(newArguments = arguments)
|
||||
}
|
||||
@@ -49,6 +49,7 @@ import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.METHOD_PARAM
|
||||
import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.RETURN_TYPE
|
||||
import org.jetbrains.kotlin.kapt3.util.*
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -62,6 +63,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -690,7 +692,8 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
val name = field.name
|
||||
if (!isValidIdentifier(name)) return null
|
||||
|
||||
val type = Type.getType(field.desc)
|
||||
val type = getFieldType(field, origin)
|
||||
|
||||
if (!checkIfValidTypeName(containingClass, type)) {
|
||||
return null
|
||||
}
|
||||
@@ -1420,6 +1423,25 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati
|
||||
lineMappings.registerSignature(this, node)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getFieldType(field: FieldNode, origin: JvmDeclarationOrigin?): Type {
|
||||
val fieldType = Type.getType(field.desc)
|
||||
return when (val declaration = origin?.element) {
|
||||
is KtProperty -> {
|
||||
//replace anonymous type in delegate (if any)
|
||||
val delegateType = kaptContext.bindingContext[BindingContext.EXPRESSION_TYPE_INFO, declaration.delegateExpression]?.type
|
||||
delegateType?.let {
|
||||
val replaced = replaceAnonymousTypeWithSuperType(it)
|
||||
//not changed => not anonymous type => use type from field
|
||||
if (replaced != it) replaced else null
|
||||
}?.let(::convertKotlinType) ?: fieldType
|
||||
}
|
||||
else -> fieldType
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertKotlinType(type: KotlinType): Type = typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT)
|
||||
|
||||
}
|
||||
|
||||
private fun Any?.isOfPrimitiveType(): Boolean = when (this) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.util
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
fun replaceAnonymousTypeWithSuperType(type: KotlinType): KotlinType {
|
||||
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
val elementTypeProjection = type.arguments.singleOrNull()
|
||||
if (elementTypeProjection != null && !elementTypeProjection.isStarProjection) {
|
||||
return type.builtIns.getArrayType(
|
||||
elementTypeProjection.projectionKind,
|
||||
replaceAnonymousTypeWithSuperType(elementTypeProjection.type)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val actualType = when {
|
||||
DescriptorUtils.isAnonymousObject(declaration) || DescriptorUtils.isLocal(declaration) -> {
|
||||
if (type.constructor.supertypes.size == 1) {
|
||||
replaceAnonymousTypeWithSuperType(type.constructor.supertypes.iterator().next())
|
||||
} else {
|
||||
/*
|
||||
Frontend reports an error on public properties in this case,
|
||||
but we ignore errors when making stubs, so there should be a reasonable fallback.
|
||||
*/
|
||||
type.builtIns.anyType
|
||||
}
|
||||
}
|
||||
else -> type
|
||||
}
|
||||
|
||||
if (actualType.arguments.isEmpty()) return actualType
|
||||
|
||||
val arguments = actualType.arguments.map { typeArg ->
|
||||
if (typeArg.isStarProjection)
|
||||
return@map typeArg
|
||||
|
||||
TypeProjectionImpl(typeArg.projectionKind, replaceAnonymousTypeWithSuperType(typeArg.type))
|
||||
}
|
||||
|
||||
return actualType.replace(newArguments = arguments)
|
||||
}
|
||||
@@ -69,6 +69,11 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousDelegate.kt")
|
||||
public void testAnonymousDelegate() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("comments.kt")
|
||||
public void testComments() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt");
|
||||
|
||||
@@ -70,6 +70,11 @@ public class IrClassFileToSourceStubConverterTestGenerated extends AbstractIrCla
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/annotationsWithTargets.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousDelegate.kt")
|
||||
public void testAnonymousDelegate() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("comments.kt")
|
||||
public void testComments() throws Exception {
|
||||
runTest("plugins/kapt3/kapt3-compiler/testData/converter/comments.kt");
|
||||
|
||||
34
plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt
vendored
Normal file
34
plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.kt
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class Test {
|
||||
|
||||
var broken by object {
|
||||
operator fun getValue(obj: Test, property: KProperty<*>) = Any()
|
||||
|
||||
operator fun setValue(obj: Test, property: KProperty<*>, any: Any) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var overridden by object : java.io.Serializable {
|
||||
operator fun getValue(obj: Test, property: KProperty<*>) = Any()
|
||||
|
||||
operator fun setValue(obj: Test, property: KProperty<*>, any: Any) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private val lazyProp by lazy {
|
||||
object : Runnable {
|
||||
override fun run() {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var delegate by object {
|
||||
operator fun getValue(nothing: Nothing?, property: KProperty<*>) = Any()
|
||||
operator fun setValue(nothing: Nothing?, property: KProperty<*>, any: Any) {
|
||||
//empty
|
||||
}
|
||||
}
|
||||
60
plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.txt
vendored
Normal file
60
plugins/kapt3/kapt3-compiler/testData/converter/anonymousDelegate.txt
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class AnonymousDelegateKt {
|
||||
|
||||
public AnonymousDelegateKt() {
|
||||
super();
|
||||
}
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private static final java.lang.Object delegate$delegate = null;
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public static final java.lang.Object getDelegate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final void setDelegate(@org.jetbrains.annotations.NotNull()
|
||||
java.lang.Object p0) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
|
||||
import java.lang.System;
|
||||
|
||||
@kotlin.Metadata()
|
||||
public final class Test {
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final java.lang.Object broken$delegate = null;
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
private final java.io.Serializable overridden$delegate = null;
|
||||
private final kotlin.Lazy lazyProp$delegate = null;
|
||||
|
||||
public Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final java.lang.Object getBroken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void setBroken(@org.jetbrains.annotations.NotNull()
|
||||
java.lang.Object p0) {
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final java.lang.Object getOverridden() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final void setOverridden(@org.jetbrains.annotations.NotNull()
|
||||
java.lang.Object p0) {
|
||||
}
|
||||
|
||||
private final java.lang.Runnable getLazyProp() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user