diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt index 17941dfafd9..3ce2102b745 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt @@ -186,6 +186,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { } pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}") + pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}") pluginOptions += SubpluginOption("stubs", getKaptStubsDir(project, sourceSetName).canonicalPath) if (project.hasProperty(VERBOSE_OPTION_NAME) && project.property(VERBOSE_OPTION_NAME) == "true") { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt index c8820c410c6..86819fcfa7b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KaptExtension.kt @@ -28,6 +28,8 @@ open class KaptExtension { open var useLightAnalysis: Boolean = true + open var correctErrorTypes: Boolean = false + private var closure: Closure<*>? = null open fun arguments(closure: Closure<*>) { diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index fcfd5f71913..d971752f337 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -53,10 +53,12 @@ class ClasspathBasedKapt3Extension( options: Map, aptOnly: Boolean, val useLightAnalysis: Boolean, + correctErrorTypes: Boolean, pluginInitializedTime: Long, logger: KaptLogger ) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir, - classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, aptOnly, pluginInitializedTime, logger) { + classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, + aptOnly, pluginInitializedTime, logger, correctErrorTypes) { override val analyzePartially: Boolean get() = useLightAnalysis @@ -102,7 +104,8 @@ abstract class AbstractKapt3Extension( val options: Map, val aptOnly: Boolean, val pluginInitializedTime: Long, - val logger: KaptLogger + val logger: KaptLogger, + val correctErrorTypes: Boolean ) : PartialAnalysisHandlerExtension() { val compileClasspath = compileClasspath.distinct() val annotationProcessingClasspath = annotationProcessingClasspath.distinct() @@ -203,7 +206,8 @@ abstract class AbstractKapt3Extension( } private fun generateKotlinSourceStubs(kaptContext: KaptContext, generationState: GenerationState) { - val converter = ClassFileToSourceStubConverter(kaptContext, generationState.typeMapper, generateNonExistentClass = true) + val converter = ClassFileToSourceStubConverter(kaptContext, generationState.typeMapper, + generateNonExistentClass = true, correctErrorTypes = correctErrorTypes) val (stubGenerationTime, kotlinSourceStubs) = measureTimeMillis { converter.convert() diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt index ba332e9b3f2..24165dc1dac 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Plugin.kt @@ -74,6 +74,9 @@ object Kapt3ConfigurationKeys { val USE_LIGHT_ANALYSIS: CompilerConfigurationKey = CompilerConfigurationKey.create("do not analyze declaration bodies if can") + + val CORRECT_ERROR_TYPES: CompilerConfigurationKey = + CompilerConfigurationKey.create("replace error types with ones from the declaration sources") } class Kapt3CommandLineProcessor : CommandLineProcessor { @@ -108,13 +111,17 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { val USE_LIGHT_ANALYSIS_OPTION: CliOption = CliOption("useLightAnalysis", "true | false", "Do not analyze declaration bodies if can", required = false) + + val CORRECT_ERROR_TYPES_OPTION: CliOption = + CliOption("correctErrorTypes", "true | false", "Replace generated or error types with ones from the generated sources", required = false) } override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID override val pluginOptions: Collection = listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, - CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, USE_LIGHT_ANALYSIS_OPTION) + CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, + USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION) override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) { when (option) { @@ -127,6 +134,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor { VERBOSE_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.VERBOSE_MODE, value) APT_ONLY_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_ONLY, value) USE_LIGHT_ANALYSIS_OPTION -> configuration.put(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS, value) + CORRECT_ERROR_TYPES_OPTION -> configuration.put(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES, value) else -> throw CliOptionProcessingException("Unknown option: ${option.name}") } } @@ -177,12 +185,15 @@ class Kapt3ComponentRegistrar : ComponentRegistrar { val javaSourceRoots = contentRoots.filterIsInstance().map { it.file } val useLightAnalysis = configuration.get(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS) == "true" + val correctErrorTypes = configuration.get(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES) == "true" Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesKapt3()) if (isVerbose) { logger.info("Kapt3 is enabled.") logger.info("Do annotation processing only: $isAptOnly") + logger.info("Use light analysis: $useLightAnalysis") + logger.info("Correct error types: $correctErrorTypes") logger.info("Source output directory: $sourcesOutputDir") logger.info("Classes output directory: $classFilesOutputDir") logger.info("Stubs output directory: $stubsOutputDir") @@ -196,7 +207,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar { val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension( compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, apOptions, - isAptOnly, useLightAnalysis, System.currentTimeMillis(), logger) + isAptOnly, useLightAnalysis, correctErrorTypes, System.currentTimeMillis(), logger) AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension) } 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 264bbe7bb9a..c4c3427c6ec 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -45,7 +45,8 @@ import com.sun.tools.javac.util.List as JavacList class ClassFileToSourceStubConverter( val kaptContext: KaptContext, val typeMapper: KotlinTypeMapper, - val generateNonExistentClass: Boolean + val generateNonExistentClass: Boolean, + val correctErrorTypes: Boolean ) { private companion object { private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong() @@ -441,6 +442,10 @@ class ClassFileToSourceStubConverter( ktTypeProvider: () -> KtTypeReference?, ifNonError: () -> T ): T { + if (!correctErrorTypes) { + return ifNonError() + } + if (type?.containsErrorTypes() ?: false) { val ktType = ktTypeProvider() if (ktType != null) { diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt index 9376b6d987a..de123d68a3e 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3IntegrationTest.kt @@ -161,7 +161,8 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() { stubsOutputDir: File, incrementalDataOutputDir: File ) : AbstractKapt3Extension(PathUtil.getJdkClassesRoots(), emptyList(), javaSourceRoots, outputDir, outputDir, - stubsOutputDir, incrementalDataOutputDir, options, true, System.currentTimeMillis(), KaptLogger(true) + stubsOutputDir, incrementalDataOutputDir, options, true, System.currentTimeMillis(), + KaptLogger(true), correctErrorTypes = true ) { internal var savedStubs: String? = null internal var savedBindings: Map? = null diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index 6568fb5e39c..3ae5cdef364 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -68,8 +68,13 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() { } } - protected fun convert(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper, generateNonExistentClass: Boolean): JavacList { - val converter = ClassFileToSourceStubConverter(kaptRunner, typeMapper, generateNonExistentClass) + protected fun convert( + kaptRunner: KaptContext, + typeMapper: KotlinTypeMapper, + generateNonExistentClass: Boolean, + correctErrorTypes: Boolean + ): JavacList { + val converter = ClassFileToSourceStubConverter(kaptRunner, typeMapper, generateNonExistentClass, correctErrorTypes) return converter.convert() } @@ -85,9 +90,10 @@ abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3T fun isOptionSet(name: String) = wholeFile.useLines { lines -> lines.any { it.trim() == "// $name" } } val generateNonExistentClass = isOptionSet("NON_EXISTENT_CLASS") + val correctErrorTypes = isOptionSet("CORRECT_ERROR_TYPES") val validate = !isOptionSet("NO_VALIDATION") - val javaFiles = convert(kaptRunner, typeMapper, generateNonExistentClass) + val javaFiles = convert(kaptRunner, typeMapper, generateNonExistentClass, correctErrorTypes) if (validate) kaptRunner.compiler.enterTrees(javaFiles) @@ -104,7 +110,7 @@ abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3T abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() { override fun check(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper, txtFile: File, wholeFile: File) { - val compilationUnits = convert(kaptRunner, typeMapper, generateNonExistentClass = false) + val compilationUnits = convert(kaptRunner, typeMapper, generateNonExistentClass = false, correctErrorTypes = true) val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile() try { kaptRunner.doAnnotationProcessing(emptyList(), listOf(JavaKaptContextTest.simpleProcessor()), 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 a1d24c78ccc..21bef80c261 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/ClassFileToSourceStubConverterTestGenerated.java @@ -204,6 +204,12 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi doTest(fileName); } + @TestMetadata("nonExistentClassWIthoutCorrection.kt") + public void testNonExistentClassWIthoutCorrection() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.kt"); + doTest(fileName); + } + @TestMetadata("primitiveTypes.kt") public void testPrimitiveTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/converter/primitiveTypes.kt"); diff --git a/plugins/kapt3/testData/converter/nonExistentClass.kt b/plugins/kapt3/testData/converter/nonExistentClass.kt index c43339fae4d..ba54f7c0676 100644 --- a/plugins/kapt3/testData/converter/nonExistentClass.kt +++ b/plugins/kapt3/testData/converter/nonExistentClass.kt @@ -1,3 +1,4 @@ +// CORRECT_ERROR_TYPES // NON_EXISTENT_CLASS // NO_VALIDATION diff --git a/plugins/kapt3/testData/converter/nonExistentClassTypesConversion.kt b/plugins/kapt3/testData/converter/nonExistentClassTypesConversion.kt index 46e2a675ed6..c5f49bd0688 100644 --- a/plugins/kapt3/testData/converter/nonExistentClassTypesConversion.kt +++ b/plugins/kapt3/testData/converter/nonExistentClassTypesConversion.kt @@ -1,3 +1,4 @@ +// CORRECT_ERROR_TYPES // NON_EXISTENT_CLASS // NO_VALIDATION diff --git a/plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.kt b/plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.kt new file mode 100644 index 00000000000..c43339fae4d --- /dev/null +++ b/plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.kt @@ -0,0 +1,13 @@ +// NON_EXISTENT_CLASS +// NO_VALIDATION + +@Suppress("UNRESOLVED_REFERENCE") +object NonExistentType { + val a: ABCDEF? = null + val b: List? = null + val c: (ABCDEF) -> Unit = { f -> } + val d: ABCDEF) -> Unit>? = null + + fun a(a: ABCDEF, s: String): ABCDEF {} + fun b(s: String): ABCDEF {} +} \ No newline at end of file diff --git a/plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.txt b/plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.txt new file mode 100644 index 00000000000..ba42c7d836a --- /dev/null +++ b/plugins/kapt3/testData/converter/nonExistentClassWIthoutCorrection.txt @@ -0,0 +1,56 @@ +@kotlin.Suppress(names = {"UNRESOLVED_REFERENCE"}) +public final class NonExistentType { + @org.jetbrains.annotations.Nullable() + private static final error.NonExistentClass a = null; + @org.jetbrains.annotations.Nullable() + private static final java.util.List b = null; + @org.jetbrains.annotations.NotNull() + private static final kotlin.jvm.functions.Function1 c = null; + @org.jetbrains.annotations.Nullable() + private static final error.NonExistentClass d = null; + public static final NonExistentType INSTANCE = null; + + @org.jetbrains.annotations.Nullable() + public final error.NonExistentClass getA() { + return null; + } + + @org.jetbrains.annotations.Nullable() + public final java.util.List getB() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final kotlin.jvm.functions.Function1 getC() { + return null; + } + + @org.jetbrains.annotations.Nullable() + public final error.NonExistentClass getD() { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final error.NonExistentClass a(@org.jetbrains.annotations.NotNull() + error.NonExistentClass a, @org.jetbrains.annotations.NotNull() + java.lang.String s) { + return null; + } + + @org.jetbrains.annotations.NotNull() + public final error.NonExistentClass b(@org.jetbrains.annotations.NotNull() + java.lang.String s) { + return null; + } + + private NonExistentType() { + super(); + } +} + +//////////////////// + +package error; + +public final class NonExistentClass { +}