Kapt: Do not write references to anonymous classes to stubs & metadata (#KT-25374)
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
interface DeclarationSignatureAnonymousTypeTransformer {
|
||||||
|
fun transformAnonymousType(descriptor: DeclarationDescriptorWithVisibility, type: KotlinType): KotlinType?
|
||||||
|
}
|
||||||
@@ -88,6 +88,7 @@ public class DescriptorResolver {
|
|||||||
private final TypeApproximator typeApproximator;
|
private final TypeApproximator typeApproximator;
|
||||||
private final DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer;
|
private final DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer;
|
||||||
private final DataFlowValueFactory dataFlowValueFactory;
|
private final DataFlowValueFactory dataFlowValueFactory;
|
||||||
|
private final Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers;
|
||||||
|
|
||||||
public DescriptorResolver(
|
public DescriptorResolver(
|
||||||
@NotNull AnnotationResolver annotationResolver,
|
@NotNull AnnotationResolver annotationResolver,
|
||||||
@@ -106,7 +107,8 @@ public class DescriptorResolver {
|
|||||||
@NotNull Project project,
|
@NotNull Project project,
|
||||||
@NotNull TypeApproximator approximator,
|
@NotNull TypeApproximator approximator,
|
||||||
@NotNull DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer,
|
@NotNull DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer,
|
||||||
@NotNull DataFlowValueFactory dataFlowValueFactory
|
@NotNull DataFlowValueFactory dataFlowValueFactory,
|
||||||
|
@NotNull Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers
|
||||||
) {
|
) {
|
||||||
this.annotationResolver = annotationResolver;
|
this.annotationResolver = annotationResolver;
|
||||||
this.builtIns = builtIns;
|
this.builtIns = builtIns;
|
||||||
@@ -125,6 +127,7 @@ public class DescriptorResolver {
|
|||||||
typeApproximator = approximator;
|
typeApproximator = approximator;
|
||||||
this.declarationReturnTypeSanitizer = declarationReturnTypeSanitizer;
|
this.declarationReturnTypeSanitizer = declarationReturnTypeSanitizer;
|
||||||
this.dataFlowValueFactory = dataFlowValueFactory;
|
this.dataFlowValueFactory = dataFlowValueFactory;
|
||||||
|
this.anonymousTypeTransformers = anonymousTypeTransformers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<KotlinType> resolveSupertypes(
|
public List<KotlinType> resolveSupertypes(
|
||||||
@@ -977,8 +980,16 @@ public class DescriptorResolver {
|
|||||||
@NotNull DeclarationDescriptorWithVisibility descriptor,
|
@NotNull DeclarationDescriptorWithVisibility descriptor,
|
||||||
@NotNull KtDeclaration declaration,
|
@NotNull KtDeclaration declaration,
|
||||||
@NotNull KotlinType type,
|
@NotNull KotlinType type,
|
||||||
@NotNull BindingTrace trace
|
@NotNull BindingTrace trace,
|
||||||
|
@NotNull Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers
|
||||||
) {
|
) {
|
||||||
|
for (DeclarationSignatureAnonymousTypeTransformer transformer : anonymousTypeTransformers) {
|
||||||
|
KotlinType transformedType = transformer.transformAnonymousType(descriptor, type);
|
||||||
|
if (transformedType != null) {
|
||||||
|
return transformedType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
|
ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
|
||||||
if (classifier == null || !DescriptorUtils.isAnonymousObject(classifier) || DescriptorUtils.isLocal(descriptor)) {
|
if (classifier == null || !DescriptorUtils.isAnonymousObject(classifier) || DescriptorUtils.isLocal(descriptor)) {
|
||||||
return type;
|
return type;
|
||||||
@@ -996,7 +1007,6 @@ public class DescriptorResolver {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PropertySetterDescriptor resolvePropertySetterDescriptor(
|
private PropertySetterDescriptor resolvePropertySetterDescriptor(
|
||||||
@NotNull LexicalScope scopeWithTypeParameters,
|
@NotNull LexicalScope scopeWithTypeParameters,
|
||||||
@@ -1159,7 +1169,7 @@ public class DescriptorResolver {
|
|||||||
return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> {
|
return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> {
|
||||||
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
|
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
|
||||||
KotlinType type = expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor);
|
KotlinType type = expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor);
|
||||||
KotlinType publicType = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace);
|
KotlinType publicType = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace, anonymousTypeTransformers);
|
||||||
UnwrappedType approximatedType = typeApproximator.approximateDeclarationType(publicType, false, languageVersionSettings);
|
UnwrappedType approximatedType = typeApproximator.approximateDeclarationType(publicType, false, languageVersionSettings);
|
||||||
KotlinType sanitizedType = declarationReturnTypeSanitizer.sanitizeReturnType(approximatedType, wrappedTypeFactory, trace, languageVersionSettings);
|
KotlinType sanitizedType = declarationReturnTypeSanitizer.sanitizeReturnType(approximatedType, wrappedTypeFactory, trace, languageVersionSettings);
|
||||||
functionsTypingVisitor.checkTypesForReturnStatements(function, trace, sanitizedType);
|
functionsTypingVisitor.checkTypesForReturnStatements(function, trace, sanitizedType);
|
||||||
|
|||||||
+3
-2
@@ -31,7 +31,8 @@ class VariableTypeAndInitializerResolver(
|
|||||||
private val wrappedTypeFactory: WrappedTypeFactory,
|
private val wrappedTypeFactory: WrappedTypeFactory,
|
||||||
private val typeApproximator: TypeApproximator,
|
private val typeApproximator: TypeApproximator,
|
||||||
private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer,
|
private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
|
private val anonymousTypeTransformers: Iterable<DeclarationSignatureAnonymousTypeTransformer>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -82,7 +83,7 @@ class VariableTypeAndInitializerResolver(
|
|||||||
)
|
)
|
||||||
val initializerType =
|
val initializerType =
|
||||||
resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
|
resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
|
||||||
transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace)
|
transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace, anonymousTypeTransformers)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
|
else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
|
||||||
|
|||||||
+46
-20
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.util.isLegacyAndroidGradleVersion
|
import org.jetbrains.kotlin.gradle.util.isLegacyAndroidGradleVersion
|
||||||
|
import org.jetbrains.kotlin.gradle.util.getFileByName
|
||||||
import org.jetbrains.kotlin.gradle.util.modify
|
import org.jetbrains.kotlin.gradle.util.modify
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -126,29 +127,32 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testICWithAnonymousClasses() {
|
||||||
|
val project = Project("icAnonymousTypes", directoryPrefix = "kapt2")
|
||||||
|
setupDataBinding(project, null)
|
||||||
|
|
||||||
|
project.build("assembleDebug") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertKaptSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
val aKt = project.projectDir.getFileByName("a.kt").also { assert(it.exists()) }
|
||||||
|
aKt.modify {
|
||||||
|
assert(it.contains("CrashMe2(1000)"))
|
||||||
|
it.replace("CrashMe2(1000)", "CrashMe2(2000)")
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build("assembleDebug") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertKaptSuccessful()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
open fun testDatabinding() {
|
open fun testDatabinding() {
|
||||||
val project = Project("android-databinding", directoryPrefix = "kapt2")
|
val project = Project("android-databinding", directoryPrefix = "kapt2")
|
||||||
|
setupDataBinding(project, "app")
|
||||||
if (!isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
|
|
||||||
project.setupWorkingDir()
|
|
||||||
|
|
||||||
// With new AGP, there's no need in the Databinding kapt dependency:
|
|
||||||
project.gradleBuildScript("app").modify {
|
|
||||||
it.lines().filterNot {
|
|
||||||
it.contains("kapt \"com.android.databinding:compiler")
|
|
||||||
}.joinToString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for KT-24915
|
|
||||||
project.gradleBuildScript("app").appendText(
|
|
||||||
"\n" + """
|
|
||||||
afterEvaluate {
|
|
||||||
kaptDebugKotlin.dependsOn dataBindingExportFeaturePackageIdsDebug
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
project.build("assembleDebug") {
|
project.build("assembleDebug") {
|
||||||
assertSuccessful()
|
assertSuccessful()
|
||||||
@@ -165,4 +169,26 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
|
|||||||
assertNotContains("The following options were not recognized by any processor")
|
assertNotContains("The following options were not recognized by any processor")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupDataBinding(project: Project, projectName: String?) {
|
||||||
|
if (!isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
|
||||||
|
project.setupWorkingDir()
|
||||||
|
|
||||||
|
// With new AGP, there's no need in the Databinding kapt dependency:
|
||||||
|
project.gradleBuildScript(projectName).modify {
|
||||||
|
it.lines().filterNot {
|
||||||
|
it.contains("kapt \"com.android.databinding:compiler")
|
||||||
|
}.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for KT-24915
|
||||||
|
project.gradleBuildScript(projectName).appendText(
|
||||||
|
"\n" + """
|
||||||
|
afterEvaluate {
|
||||||
|
kaptDebugKotlin.dependsOn dataBindingExportFeaturePackageIdsDebug
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
maven { url 'https://maven.google.com' }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath "com.android.tools.build:gradle:$android_tools_version"
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 27
|
||||||
|
buildToolsVersion "27.0.3"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "org.kotlinlang.test"
|
||||||
|
|
||||||
|
minSdkVersion 16
|
||||||
|
targetSdkVersion 27
|
||||||
|
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBinding {
|
||||||
|
enabled true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
maven { url 'https://maven.google.com' }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
kapt "com.android.databinding:compiler:$android_tools_version"
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.databinding">
|
||||||
|
|
||||||
|
<application android:label="test">
|
||||||
|
<activity android:name=".MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class CrashMe {
|
||||||
|
private val crashMe = object : CrashMe2(1000) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
abstract class CrashMe2(value: Long) {
|
||||||
|
val crashMe2 = object : Any() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent" android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"/>
|
||||||
|
</layout>
|
||||||
@@ -33,8 +33,11 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
|||||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
import org.jetbrains.kotlin.container.ComponentProvider
|
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.context.ProjectContext
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
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_PROCESSORS_OPTION
|
||||||
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.ANNOTATION_PROCESSOR_CLASSPATH_OPTION
|
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.ANNOTATION_PROCESSOR_CLASSPATH_OPTION
|
||||||
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.APT_MODE_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.kapt3.util.MessageCollectorBackedKaptLogger
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
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.extensions.AnalysisHandlerExtension
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||||
import org.jetbrains.kotlin.utils.decodePluginOptions
|
import org.jetbrains.kotlin.utils.decodePluginOptions
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -314,6 +319,19 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
|||||||
)
|
)
|
||||||
|
|
||||||
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
|
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.
|
/* 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)
|
return AnalysisResult.Companion.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AptMode {
|
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 signatureParser = SignatureParser(treeMaker)
|
||||||
|
|
||||||
private val anonymousTypeHandler = AnonymousTypeHandler(this)
|
|
||||||
|
|
||||||
private val kdocCommentKeeper = KDocCommentKeeper(kaptContext)
|
private val kdocCommentKeeper = KDocCommentKeeper(kaptContext)
|
||||||
|
|
||||||
private var done = false
|
private var done = false
|
||||||
@@ -479,16 +477,16 @@ class ClassFileToSourceStubConverter(
|
|||||||
val typeExpression = if (isEnum(field.access))
|
val typeExpression = if (isEnum(field.access))
|
||||||
treeMaker.SimpleName(treeMaker.getQualifiedName(type).substringAfterLast('.'))
|
treeMaker.SimpleName(treeMaker.getQualifiedName(type).substringAfterLast('.'))
|
||||||
else
|
else
|
||||||
anonymousTypeHandler.getNonAnonymousType(descriptor) {
|
getNonErrorType(
|
||||||
getNonErrorType((descriptor as? CallableDescriptor)?.returnType, RETURN_TYPE,
|
(descriptor as? CallableDescriptor)?.returnType, RETURN_TYPE,
|
||||||
ktTypeProvider = {
|
ktTypeProvider = {
|
||||||
val fieldOrigin = (kaptContext.origins[field]?.element as? KtCallableDeclaration)
|
val fieldOrigin = (kaptContext.origins[field]?.element as? KtCallableDeclaration)
|
||||||
?.takeIf { it !is KtFunction }
|
?.takeIf { it !is KtFunction }
|
||||||
|
|
||||||
fieldOrigin?.typeReference
|
fieldOrigin?.typeReference
|
||||||
},
|
},
|
||||||
ifNonError = { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) })
|
ifNonError = { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) }
|
||||||
}
|
)
|
||||||
|
|
||||||
val value = field.value
|
val value = field.value
|
||||||
|
|
||||||
@@ -646,19 +644,19 @@ class ClassFileToSourceStubConverter(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
val returnType = anonymousTypeHandler.getNonAnonymousType(descriptor) {
|
val returnType = getNonErrorType(
|
||||||
getNonErrorType(descriptor.returnType, RETURN_TYPE,
|
descriptor.returnType, RETURN_TYPE,
|
||||||
ktTypeProvider = {
|
ktTypeProvider = {
|
||||||
val element = kaptContext.origins[method]?.element
|
val element = kaptContext.origins[method]?.element
|
||||||
when (element) {
|
when (element) {
|
||||||
is KtFunction -> element.typeReference
|
is KtFunction -> element.typeReference
|
||||||
is KtProperty -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
is KtProperty -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
||||||
is KtParameter -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
is KtParameter -> if (descriptor is PropertyGetterDescriptor) element.typeReference else null
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ifNonError = { genericSignature.returnType })
|
ifNonError = { genericSignature.returnType }
|
||||||
}
|
)
|
||||||
|
|
||||||
return Pair(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.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
|
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||||
import org.jetbrains.kotlin.kapt3.*
|
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.KaptContext
|
||||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||||
import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing
|
import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing
|
||||||
@@ -105,7 +107,9 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
|||||||
addAnnotationProcessingRuntimeLibrary(myEnvironment)
|
addAnnotationProcessingRuntimeLibrary(myEnvironment)
|
||||||
|
|
||||||
// Use light analysis mode in tests
|
// 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)
|
loadMultiFiles(files)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user