Kapt: Strict mode. Issue an error if the converter fails to process a class (#KT-25518, #KT-24272)

This commit is contained in:
Yan Zhulanow
2018-07-16 21:00:40 +03:00
parent ef210d7122
commit c83581e6b8
12 changed files with 152 additions and 26 deletions
@@ -341,6 +341,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}") pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}")
pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}") pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}")
pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}") pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}")
pluginOptions += SubpluginOption("strictMode", "${kaptExtension.strictMode}")
pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}") pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}")
pluginOptions += FilesSubpluginOption("stubs", listOf(getKaptStubsDir())) pluginOptions += FilesSubpluginOption("stubs", listOf(getKaptStubsDir()))
@@ -32,6 +32,8 @@ open class KaptExtension {
open var mapDiagnosticLocations: Boolean = false open var mapDiagnosticLocations: Boolean = false
open var strictMode: Boolean = false
@Deprecated("Use `annotationProcessor()` and `annotationProcessors()` instead") @Deprecated("Use `annotationProcessor()` and `annotationProcessors()` instead")
open var processors: String = "" open var processors: String = ""
@@ -224,10 +224,17 @@ class KaptJavaLog(
} }
} }
fun KaptContext.kaptError(text: String): JCDiagnostic { private val LINE_SEPARATOR: String = System.getProperty("line.separator")
fun KaptContext.kaptError(vararg line: String): JCDiagnostic {
val text = line.joinToString(LINE_SEPARATOR)
return JCDiagnostic.Factory.instance(context).errorJava9Aware(null, null, "proc.messager", text) return JCDiagnostic.Factory.instance(context).errorJava9Aware(null, null, "proc.messager", text)
} }
fun KaptContext.reportKaptError(vararg line: String) {
compiler.log.report(kaptError(*line))
}
private fun JCDiagnostic.Factory.errorJava9Aware( private fun JCDiagnostic.Factory.errorJava9Aware(
source: DiagnosticSource?, source: DiagnosticSource?,
pos: JCDiagnostic.DiagnosticPosition?, pos: JCDiagnostic.DiagnosticPosition?,
@@ -72,11 +72,15 @@ class ClasspathBasedKapt3Extension(
val useLightAnalysis: Boolean, val useLightAnalysis: Boolean,
correctErrorTypes: Boolean, correctErrorTypes: Boolean,
mapDiagnosticLocations: Boolean, mapDiagnosticLocations: Boolean,
strictMode: Boolean,
pluginInitializedTime: Long, pluginInitializedTime: Long,
logger: MessageCollectorBackedKaptLogger, logger: MessageCollectorBackedKaptLogger,
compilerConfiguration: CompilerConfiguration compilerConfiguration: CompilerConfiguration
) : AbstractKapt3Extension(paths, options, javacOptions, annotationProcessorFqNames, ) : AbstractKapt3Extension(
aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, compilerConfiguration) { paths, options, javacOptions, annotationProcessorFqNames,
aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, strictMode,
compilerConfiguration
) {
override val analyzePartially: Boolean override val analyzePartially: Boolean
get() = useLightAnalysis get() = useLightAnalysis
@@ -110,6 +114,7 @@ abstract class AbstractKapt3Extension(
val logger: MessageCollectorBackedKaptLogger, val logger: MessageCollectorBackedKaptLogger,
val correctErrorTypes: Boolean, val correctErrorTypes: Boolean,
val mapDiagnosticLocations: Boolean, val mapDiagnosticLocations: Boolean,
val strictMode: Boolean,
val compilerConfiguration: CompilerConfiguration val compilerConfiguration: CompilerConfiguration
) : PartialAnalysisHandlerExtension() { ) : PartialAnalysisHandlerExtension() {
private var annotationProcessingComplete = false private var annotationProcessingComplete = false
@@ -254,7 +259,12 @@ abstract class AbstractKapt3Extension(
} }
private fun generateKotlinSourceStubs(kaptContext: KaptContextForStubGeneration) { private fun generateKotlinSourceStubs(kaptContext: KaptContextForStubGeneration) {
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass = true, correctErrorTypes = correctErrorTypes) val converter = ClassFileToSourceStubConverter(
kaptContext,
generateNonExistentClass = true,
correctErrorTypes = correctErrorTypes,
strictMode = strictMode
)
val (stubGenerationTime, kaptStubs) = measureTimeMillis { val (stubGenerationTime, kaptStubs) = measureTimeMillis {
converter.convert() converter.convert()
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.VERBOSE_MO
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.APT_OPTIONS import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.APT_OPTIONS
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS
import org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor.Companion.STRICT_MODE_OPTION
import org.jetbrains.kotlin.kapt3.base.Kapt import org.jetbrains.kotlin.kapt3.base.Kapt
import org.jetbrains.kotlin.kapt3.base.KaptPaths import org.jetbrains.kotlin.kapt3.base.KaptPaths
import org.jetbrains.kotlin.kapt3.base.log import org.jetbrains.kotlin.kapt3.base.log
@@ -117,6 +118,9 @@ object Kapt3ConfigurationKeys {
val MAP_DIAGNOSTIC_LOCATIONS: CompilerConfigurationKey<String> = val MAP_DIAGNOSTIC_LOCATIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(MAP_DIAGNOSTIC_LOCATIONS_OPTION.description) CompilerConfigurationKey.create<String>(MAP_DIAGNOSTIC_LOCATIONS_OPTION.description)
val STRICT_MODE: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(STRICT_MODE_OPTION.description)
} }
class Kapt3CommandLineProcessor : CommandLineProcessor { class Kapt3CommandLineProcessor : CommandLineProcessor {
@@ -176,6 +180,9 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
val MAP_DIAGNOSTIC_LOCATIONS_OPTION: CliOption = val MAP_DIAGNOSTIC_LOCATIONS_OPTION: CliOption =
CliOption("mapDiagnosticLocations", "true | false", "Map diagnostic reported on kapt stubs to original locations in Kotlin sources", required = false) CliOption("mapDiagnosticLocations", "true | false", "Map diagnostic reported on kapt stubs to original locations in Kotlin sources", required = false)
val STRICT_MODE_OPTION: CliOption =
CliOption("strict", "true | false", "Show errors on incompatibilities during stub generation", required = false)
} }
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
@@ -184,7 +191,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, JAVAC_CLI_OPTIONS_OPTION, listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, JAVAC_CLI_OPTIONS_OPTION,
CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, APT_MODE_OPTION, CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, APT_MODE_OPTION,
USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION, INCREMENTAL_DATA_OUTPUT_DIR_OPTION, USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION, INCREMENTAL_DATA_OUTPUT_DIR_OPTION,
CONFIGURATION, MAP_DIAGNOSTIC_LOCATIONS_OPTION, INFO_AS_WARNINGS_OPTION) CONFIGURATION, MAP_DIAGNOSTIC_LOCATIONS_OPTION, INFO_AS_WARNINGS_OPTION, STRICT_MODE_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) { override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) { when (option) {
@@ -204,6 +211,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
CORRECT_ERROR_TYPES_OPTION -> configuration.put(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES, value) CORRECT_ERROR_TYPES_OPTION -> configuration.put(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES, value)
MAP_DIAGNOSTIC_LOCATIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.MAP_DIAGNOSTIC_LOCATIONS, value) MAP_DIAGNOSTIC_LOCATIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.MAP_DIAGNOSTIC_LOCATIONS, value)
INFO_AS_WARNINGS_OPTION -> configuration.put(Kapt3ConfigurationKeys.INFO_AS_WARNINGS, value) INFO_AS_WARNINGS_OPTION -> configuration.put(Kapt3ConfigurationKeys.INFO_AS_WARNINGS, value)
STRICT_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.STRICT_MODE, value)
CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions) CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}") else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
} }
@@ -235,6 +243,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
val isVerbose = configuration.get(Kapt3ConfigurationKeys.VERBOSE_MODE) == "true" val isVerbose = configuration.get(Kapt3ConfigurationKeys.VERBOSE_MODE) == "true"
val infoAsWarnings = configuration.get(Kapt3ConfigurationKeys.INFO_AS_WARNINGS) == "true" val infoAsWarnings = configuration.get(Kapt3ConfigurationKeys.INFO_AS_WARNINGS) == "true"
val strictMode = configuration.get(Kapt3ConfigurationKeys.STRICT_MODE) == "true"
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
?: PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose) ?: PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose)
val logger = MessageCollectorBackedKaptLogger(isVerbose, infoAsWarnings, messageCollector) val logger = MessageCollectorBackedKaptLogger(isVerbose, infoAsWarnings, messageCollector)
@@ -307,6 +316,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
logger.info("Correct error types: $correctErrorTypes") logger.info("Correct error types: $correctErrorTypes")
logger.info("Map diagnostic locations: $mapDiagnosticLocations") logger.info("Map diagnostic locations: $mapDiagnosticLocations")
logger.info("Info as warnings: $infoAsWarnings") logger.info("Info as warnings: $infoAsWarnings")
logger.info("Strict mode: $strictMode")
paths.log(logger) paths.log(logger)
logger.info("Annotation processors: " + annotationProcessors.joinToString()) logger.info("Annotation processors: " + annotationProcessors.joinToString())
logger.info("Javac options: $apOptions") logger.info("Javac options: $apOptions")
@@ -315,7 +325,8 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension( val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
paths, apOptions, javacCliOptions, annotationProcessors, paths, apOptions, javacCliOptions, annotationProcessors,
aptMode, useLightAnalysis, correctErrorTypes, mapDiagnosticLocations, System.currentTimeMillis(), logger, configuration aptMode, useLightAnalysis, correctErrorTypes, mapDiagnosticLocations, strictMode,
System.currentTimeMillis(), logger, configuration
) )
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension) AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
@@ -331,7 +342,6 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
if (platform != JvmPlatform) return if (platform != JvmPlatform) return
container.useInstance(KaptAnonymousTypeTransformer()) container.useInstance(KaptAnonymousTypeTransformer())
} }
} }
/* This extension simply disables both code analysis and code generation. /* This extension simply disables both code analysis and code generation.
@@ -358,7 +368,6 @@ 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 {
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.base.plus import org.jetbrains.kotlin.kapt3.base.plus
import org.jetbrains.kotlin.kapt3.base.javac.kaptError import org.jetbrains.kotlin.kapt3.base.javac.kaptError
import org.jetbrains.kotlin.kapt3.base.javac.reportKaptError
import org.jetbrains.kotlin.kapt3.base.mapJList import org.jetbrains.kotlin.kapt3.base.mapJList
import org.jetbrains.kotlin.kapt3.base.mapJListIndexed import org.jetbrains.kotlin.kapt3.base.mapJListIndexed
import org.jetbrains.kotlin.kapt3.base.pairedListToMap import org.jetbrains.kotlin.kapt3.base.pairedListToMap
@@ -62,7 +63,8 @@ import com.sun.tools.javac.util.List as JavacList
class ClassFileToSourceStubConverter( class ClassFileToSourceStubConverter(
val kaptContext: KaptContextForStubGeneration, val kaptContext: KaptContextForStubGeneration,
val generateNonExistentClass: Boolean, val generateNonExistentClass: Boolean,
val correctErrorTypes: Boolean val correctErrorTypes: Boolean,
val strictMode: Boolean
) { ) {
private companion object { private companion object {
private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong() private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
@@ -285,7 +287,7 @@ class ClassFileToSourceStubConverter(
isTopLevel: Boolean isTopLevel: Boolean
): JCClassDecl? { ): JCClassDecl? {
if (isSynthetic(clazz.access)) return null if (isSynthetic(clazz.access)) return null
if (checkIfShouldBeIgnored(Type.getObjectType(clazz.name))) return null if (!checkIfValidTypeName(clazz, Type.getObjectType(clazz.name))) return null
val descriptor = kaptContext.origins[clazz]?.descriptor ?: return null val descriptor = kaptContext.origins[clazz]?.descriptor ?: return null
val isNested = (descriptor as? ClassDescriptor)?.isNested ?: false val isNested = (descriptor as? ClassDescriptor)?.isNested ?: false
@@ -393,21 +395,41 @@ class ClassFileToSourceStubConverter(
enumValues + fields + methods + nestedClasses).keepKdocComments(clazz) enumValues + fields + methods + nestedClasses).keepKdocComments(clazz)
} }
private tailrec fun checkIfShouldBeIgnored(type: Type): Boolean { private tailrec fun checkIfValidTypeName(containingClass: ClassNode, type: Type): Boolean {
if (type.sort == Type.ARRAY) { if (type.sort == Type.ARRAY) {
return checkIfShouldBeIgnored(type.elementType) return checkIfValidTypeName(containingClass, type.elementType)
} }
if (type.sort != Type.OBJECT) return false if (type.sort != Type.OBJECT) return true
val internalName = type.internalName val internalName = type.internalName
// Ignore type names with Java keywords in it // Ignore type names with Java keywords in it
if (internalName.split('/', '.').any { it in JAVA_KEYWORDS }) { if (internalName.split('/', '.').any { it in JAVA_KEYWORDS }) {
return true if (strictMode) {
kaptContext.reportKaptError(
"Can't generate a stub for '${containingClass.className}'.",
"Type name '${type.className}' contains a Java keyword."
)
}
return false
} }
val clazz = kaptContext.compiledClasses.firstOrNull { it.name == internalName } ?: return false val clazz = kaptContext.compiledClasses.firstOrNull { it.name == internalName } ?: return true
return checkIfInnerClassNameConflictsWithOuter(clazz)
if (doesInnerClassNameConflictWithOuter(clazz)) {
if (strictMode) {
kaptContext.reportKaptError(
"Can't generate a stub for '${containingClass.className}'.",
"Its name '${clazz.simpleName}' is the same as one of the outer class names.",
"Java forbids it. Please change one of the class names."
)
}
return false
}
return true
} }
private fun findContainingClassNode(clazz: ClassNode): ClassNode? { private fun findContainingClassNode(clazz: ClassNode): ClassNode? {
@@ -416,7 +438,7 @@ class ClassFileToSourceStubConverter(
} }
// Java forbids outer and inner class names to be the same. Check if the names are different // Java forbids outer and inner class names to be the same. Check if the names are different
private tailrec fun checkIfInnerClassNameConflictsWithOuter( private tailrec fun doesInnerClassNameConflictWithOuter(
clazz: ClassNode, clazz: ClassNode,
outerClass: ClassNode? = findContainingClassNode(clazz) outerClass: ClassNode? = findContainingClassNode(clazz)
): Boolean { ): Boolean {
@@ -424,7 +446,7 @@ class ClassFileToSourceStubConverter(
if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true
// Try to find the containing class for outerClassNode (to check the whole tree recursively) // Try to find the containing class for outerClassNode (to check the whole tree recursively)
val containingClassForOuterClass = findContainingClassNode(outerClass) ?: return false val containingClassForOuterClass = findContainingClassNode(outerClass) ?: return false
return checkIfInnerClassNameConflictsWithOuter(clazz, containingClassForOuterClass) return doesInnerClassNameConflictWithOuter(clazz, containingClassForOuterClass)
} }
private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean) = when { private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean) = when {
@@ -469,7 +491,7 @@ class ClassFileToSourceStubConverter(
if (!isValidIdentifier(name)) return null if (!isValidIdentifier(name)) return null
val type = Type.getType(field.desc) val type = Type.getType(field.desc)
if (checkIfShouldBeIgnored(type)) { if (!checkIfValidTypeName(containingClass, type)) {
return null return null
} }
@@ -537,7 +559,9 @@ class ClassFileToSourceStubConverter(
val parametersInfo = method.getParametersInfo(containingClass) val parametersInfo = method.getParametersInfo(containingClass)
if (checkIfShouldBeIgnored(asmReturnType) || parametersInfo.any { checkIfShouldBeIgnored(it.type) }) { if (!checkIfValidTypeName(containingClass, asmReturnType)
|| parametersInfo.any { !checkIfValidTypeName(containingClass, it.type) }
) {
return null return null
} }
@@ -50,4 +50,10 @@ private val ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS: Strin
private fun AnnotationNode.isJvmOverloadsGenerated(): Boolean { private fun AnnotationNode.isJvmOverloadsGenerated(): Boolean {
return this.desc == ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS return this.desc == ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS
} }
val ClassNode.className: String
get() = Type.getObjectType(name).className
val ClassNode.simpleName: String
get() = name.substringAfterLast('/').substringAfterLast('$')
@@ -171,7 +171,8 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath, PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
emptyList(), javaSourceRoots, outputDir, outputDir, stubsOutputDir, incrementalDataOutputDir emptyList(), javaSourceRoots, outputDir, outputDir, stubsOutputDir, incrementalDataOutputDir
), options, emptyMap(), emptyList(), STUBS_AND_APT, System.currentTimeMillis(), ), options, emptyMap(), emptyList(), STUBS_AND_APT, System.currentTimeMillis(),
MessageCollectorBackedKaptLogger(true), correctErrorTypes = true, mapDiagnosticLocations = true, MessageCollectorBackedKaptLogger(true),
correctErrorTypes = true, mapDiagnosticLocations = true, strictMode = true,
compilerConfiguration = CompilerConfiguration.EMPTY compilerConfiguration = CompilerConfiguration.EMPTY
) { ) {
internal var savedStubs: String? = null internal var savedStubs: String? = null
@@ -165,9 +165,10 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
kaptContext: KaptContextForStubGeneration, kaptContext: KaptContextForStubGeneration,
javaFiles: List<File>, javaFiles: List<File>,
generateNonExistentClass: Boolean, generateNonExistentClass: Boolean,
correctErrorTypes: Boolean correctErrorTypes: Boolean,
strictMode: Boolean
): JavacList<JCCompilationUnit> { ): JavacList<JCCompilationUnit> {
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass, correctErrorTypes) val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass, correctErrorTypes, strictMode)
val kaptStubs = converter.convert() val kaptStubs = converter.convert()
val convertedFiles = kaptStubs.map { stub -> val convertedFiles = kaptStubs.map { stub ->
@@ -251,9 +252,10 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(
val generateNonExistentClass = wholeFile.isOptionSet("NON_EXISTENT_CLASS") val generateNonExistentClass = wholeFile.isOptionSet("NON_EXISTENT_CLASS")
val correctErrorTypes = wholeFile.isOptionSet("CORRECT_ERROR_TYPES") val correctErrorTypes = wholeFile.isOptionSet("CORRECT_ERROR_TYPES")
val validate = !wholeFile.isOptionSet("NO_VALIDATION") val validate = !wholeFile.isOptionSet("NO_VALIDATION")
val strictMode = wholeFile.isOptionSet("STRICT_MODE")
val expectedErrors = wholeFile.getRawOptionValues(EXPECTED_ERROR).sorted() val expectedErrors = wholeFile.getRawOptionValues(EXPECTED_ERROR).sorted()
val convertedFiles = convert(kaptContext, javaFiles, generateNonExistentClass, correctErrorTypes) val convertedFiles = convert(kaptContext, javaFiles, generateNonExistentClass, correctErrorTypes, strictMode)
kaptContext.javaLog.interceptorData.files = convertedFiles.map { it.sourceFile to it }.toMap() kaptContext.javaLog.interceptorData.files = convertedFiles.map { it.sourceFile to it }.toMap()
if (validate) kaptContext.compiler.enterTrees(convertedFiles) if (validate) kaptContext.compiler.enterTrees(convertedFiles)
@@ -307,7 +309,10 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(
abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() { abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() {
override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) { override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) {
val compilationUnits = convert(kaptContext, javaFiles, generateNonExistentClass = false, correctErrorTypes = true) val compilationUnits = convert(
kaptContext, javaFiles,
generateNonExistentClass = false, correctErrorTypes = true, strictMode = false
)
kaptContext.doAnnotationProcessing( kaptContext.doAnnotationProcessing(
emptyList(), emptyList(),
@@ -214,6 +214,11 @@ public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFi
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt19750.kt"); runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt19750.kt");
} }
@TestMetadata("kt24272.kt")
public void testKt24272() throws Exception {
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt24272.kt");
}
@TestMetadata("kt25071.kt") @TestMetadata("kt25071.kt")
public void testKt25071() throws Exception { public void testKt25071() throws Exception {
runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt25071.kt"); runTest("plugins/kapt3/kapt3-compiler/testData/converter/kt25071.kt");
@@ -0,0 +1,15 @@
// STRICT_MODE
// EXPECTED_ERROR(java:23:50) cannot find symbol
// EXPECTED_ERROR(java:28:49) cannot find symbol
// EXPECTED_ERROR(other:-1:-1) Can't generate a stub for 'Foo$Bar$Bar'.
class Foo(private val string: String) {
val bar = Bar("bar")
class Bar(val string: String) {
class Bar(val nested: String)
val bars: ArrayList<Bar> = ArrayList()
}
}
@@ -0,0 +1,41 @@
import java.lang.System;
@kotlin.Metadata()
public final class Foo {
@org.jetbrains.annotations.NotNull()
private final Foo.Bar bar = null;
private final java.lang.String string = null;
@org.jetbrains.annotations.NotNull()
public final Foo.Bar getBar() {
return null;
}
public Foo(@org.jetbrains.annotations.NotNull()
java.lang.String string) {
super();
}
@kotlin.Metadata()
public static final class Bar {
@org.jetbrains.annotations.NotNull()
private final java.util.ArrayList<Foo.Bar.Bar> bars = null;
@org.jetbrains.annotations.NotNull()
private final java.lang.String string = null;
@org.jetbrains.annotations.NotNull()
public final java.util.ArrayList<Foo.Bar.Bar> getBars() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getString() {
return null;
}
public Bar(@org.jetbrains.annotations.NotNull()
java.lang.String string) {
super();
}
}
}