Kapt: Do not write references to anonymous classes to stubs & metadata (#KT-25374)
This commit is contained in:
@@ -33,8 +33,11 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.container.ComponentProvider
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.context.ProjectContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.ANNOTATION_PROCESSORS_OPTION
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.ANNOTATION_PROCESSOR_CLASSPATH_OPTION
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.APT_MODE_OPTION
|
||||
@@ -59,7 +62,9 @@ import org.jetbrains.kotlin.kapt3.base.log
|
||||
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedKaptLogger
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
import org.jetbrains.kotlin.utils.decodePluginOptions
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
@@ -314,6 +319,19 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
)
|
||||
|
||||
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
|
||||
StorageComponentContainerContributor.registerExtension(project, KaptComponentContributor())
|
||||
}
|
||||
|
||||
class KaptComponentContributor : StorageComponentContainerContributor {
|
||||
override fun registerModuleComponents(
|
||||
container: StorageComponentContainer,
|
||||
platform: TargetPlatform,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
) {
|
||||
if (platform != JvmPlatform) return
|
||||
container.useInstance(KaptAnonymousTypeTransformer())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This extension simply disables both code analysis and code generation.
|
||||
@@ -340,6 +358,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
return AnalysisResult.Companion.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class AptMode {
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||
import org.jetbrains.kotlin.resolve.DeclarationSignatureAnonymousTypeTransformer
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isAnonymousObject
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
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
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
|
||||
class KaptAnonymousTypeTransformer : DeclarationSignatureAnonymousTypeTransformer {
|
||||
override fun transformAnonymousType(descriptor: DeclarationDescriptorWithVisibility, type: KotlinType): KotlinType? {
|
||||
if (DescriptorUtils.isLocal(descriptor))
|
||||
return type
|
||||
|
||||
return convertPossiblyAnonymousType(type)
|
||||
}
|
||||
|
||||
private 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) -> findMostSuitableParentForAnonymousType(declaration)
|
||||
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)
|
||||
}
|
||||
|
||||
private fun findMostSuitableParentForAnonymousType(descriptor: ClassDescriptor): KotlinType {
|
||||
descriptor.getSuperClassNotAny()?.let { return it.defaultType }
|
||||
|
||||
val sortedSuperTypes = descriptor.typeConstructor.supertypes
|
||||
.sortedBy { it.constructor.declarationDescriptor?.name?.asString() ?: "" }
|
||||
|
||||
for (candidate in sortedSuperTypes) {
|
||||
if (!candidate.isAnyOrNullableAny())
|
||||
return candidate
|
||||
}
|
||||
|
||||
return descriptor.builtIns.anyType
|
||||
}
|
||||
}
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.stubs
|
||||
|
||||
import com.sun.tools.javac.code.BoundKind
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.kapt3.base.mapJList
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isAnonymousObject
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
class AnonymousTypeHandler(private val converter: ClassFileToSourceStubConverter) {
|
||||
fun <T : JCTree.JCExpression?> getNonAnonymousType(descriptor: DeclarationDescriptor?, f: () -> T): T {
|
||||
val classType = when (descriptor) {
|
||||
is ClassDescriptor -> descriptor.defaultType
|
||||
is CallableDescriptor -> descriptor.returnType
|
||||
else -> null
|
||||
} ?: return f()
|
||||
|
||||
return getNonAnonymousType(classType, f)
|
||||
}
|
||||
|
||||
fun <T : JCTree.JCExpression?> getNonAnonymousType(type: KotlinType, f: () -> T): T {
|
||||
if (!checkIfAnonymousRecursively(type)) return f()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return convertKotlinType(convertPossiblyAnonymousType(type)) as T
|
||||
}
|
||||
|
||||
private fun checkIfAnonymousRecursively(type: KotlinType): Boolean {
|
||||
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
if (isAnonymousObject(declaration)) return true
|
||||
return type.arguments.any {
|
||||
if (it.isStarProjection) return@any false
|
||||
checkIfAnonymousRecursively(it.type)
|
||||
}
|
||||
}
|
||||
|
||||
private 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) -> findMostSuitableParentForAnonymousType(declaration)
|
||||
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(arguments)
|
||||
}
|
||||
|
||||
private fun findMostSuitableParentForAnonymousType(descriptor: ClassDescriptor): KotlinType {
|
||||
descriptor.getSuperClassNotAny()?.let { return it.defaultType }
|
||||
|
||||
val sortedSuperTypes = descriptor.typeConstructor.supertypes
|
||||
.sortedBy { it.constructor.declarationDescriptor?.name?.asString() ?: "" }
|
||||
|
||||
for (candidate in sortedSuperTypes) {
|
||||
if (!candidate.isAnyOrNullableAny()) return candidate
|
||||
}
|
||||
|
||||
return descriptor.builtIns.anyType
|
||||
}
|
||||
|
||||
private fun convertKotlinType(type: KotlinType): JCTree.JCExpression {
|
||||
val treeMaker = converter.treeMaker
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
val elementTypeProjection = type.arguments.single()
|
||||
|
||||
val elementType = if (elementTypeProjection.isStarProjection || elementTypeProjection.projectionKind == Variance.IN_VARIANCE) {
|
||||
type.builtIns.anyType
|
||||
} else {
|
||||
elementTypeProjection.type
|
||||
}
|
||||
|
||||
return treeMaker.TypeArray(convertKotlinType(elementType))
|
||||
}
|
||||
|
||||
val typeMapper = converter.kaptContext.generationState.typeMapper
|
||||
|
||||
// Primitive types can't be anonymous, so if we get here, we want to map a class type or its generic argument
|
||||
val selfType = treeMaker.Type(typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
if (type.arguments.isEmpty()) return selfType
|
||||
|
||||
return treeMaker.TypeApply(selfType, mapJList(type.arguments) { projection ->
|
||||
if (projection.isStarProjection) return@mapJList treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
|
||||
|
||||
val renderedArg = convertKotlinType(projection.type)
|
||||
when (projection.projectionKind) {
|
||||
Variance.INVARIANT -> renderedArg
|
||||
Variance.OUT_VARIANCE -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.EXTENDS), renderedArg)
|
||||
Variance.IN_VARIANCE -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.SUPER), renderedArg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+22
-24
@@ -107,8 +107,6 @@ class ClassFileToSourceStubConverter(
|
||||
|
||||
private val signatureParser = SignatureParser(treeMaker)
|
||||
|
||||
private val anonymousTypeHandler = AnonymousTypeHandler(this)
|
||||
|
||||
private val kdocCommentKeeper = KDocCommentKeeper(kaptContext)
|
||||
|
||||
private var done = false
|
||||
@@ -479,16 +477,16 @@ class ClassFileToSourceStubConverter(
|
||||
val typeExpression = if (isEnum(field.access))
|
||||
treeMaker.SimpleName(treeMaker.getQualifiedName(type).substringAfterLast('.'))
|
||||
else
|
||||
anonymousTypeHandler.getNonAnonymousType(descriptor) {
|
||||
getNonErrorType((descriptor as? CallableDescriptor)?.returnType, RETURN_TYPE,
|
||||
ktTypeProvider = {
|
||||
val fieldOrigin = (kaptContext.origins[field]?.element as? KtCallableDeclaration)
|
||||
?.takeIf { it !is KtFunction }
|
||||
getNonErrorType(
|
||||
(descriptor as? CallableDescriptor)?.returnType, RETURN_TYPE,
|
||||
ktTypeProvider = {
|
||||
val fieldOrigin = (kaptContext.origins[field]?.element as? KtCallableDeclaration)
|
||||
?.takeIf { it !is KtFunction }
|
||||
|
||||
fieldOrigin?.typeReference
|
||||
},
|
||||
ifNonError = { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) })
|
||||
}
|
||||
fieldOrigin?.typeReference
|
||||
},
|
||||
ifNonError = { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) }
|
||||
)
|
||||
|
||||
val value = field.value
|
||||
|
||||
@@ -646,19 +644,19 @@ class ClassFileToSourceStubConverter(
|
||||
}
|
||||
})
|
||||
|
||||
val returnType = anonymousTypeHandler.getNonAnonymousType(descriptor) {
|
||||
getNonErrorType(descriptor.returnType, RETURN_TYPE,
|
||||
ktTypeProvider = {
|
||||
val element = kaptContext.origins[method]?.element
|
||||
when (element) {
|
||||
is KtFunction -> element.typeReference
|
||||
is KtProperty -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
||||
is KtParameter -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
ifNonError = { genericSignature.returnType })
|
||||
}
|
||||
val returnType = getNonErrorType(
|
||||
descriptor.returnType, RETURN_TYPE,
|
||||
ktTypeProvider = {
|
||||
val element = kaptContext.origins[method]?.element
|
||||
when (element) {
|
||||
is KtFunction -> element.typeReference
|
||||
is KtProperty -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
||||
is KtParameter -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
ifNonError = { genericSignature.returnType }
|
||||
)
|
||||
|
||||
return Pair(genericSignature, returnType)
|
||||
}
|
||||
|
||||
+5
-1
@@ -30,7 +30,9 @@ import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3ComponentRegistrar.KaptComponentContributor
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing
|
||||
@@ -105,7 +107,9 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
addAnnotationProcessingRuntimeLibrary(myEnvironment)
|
||||
|
||||
// Use light analysis mode in tests
|
||||
AnalysisHandlerExtension.registerExtension(myEnvironment.project, PartialAnalysisHandlerExtension())
|
||||
val project = myEnvironment.project
|
||||
AnalysisHandlerExtension.registerExtension(project, PartialAnalysisHandlerExtension())
|
||||
StorageComponentContainerContributor.registerExtension(project, KaptComponentContributor())
|
||||
|
||||
loadMultiFiles(files)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user