Minor: Fix inspection warnings in 'kotlin-annotation-processing'

This commit is contained in:
Yan Zhulanow
2018-10-19 20:17:27 +03:00
parent 17c02a77c7
commit f19c0c3fb9
17 changed files with 454 additions and 404 deletions
+2
View File
@@ -8,6 +8,8 @@
<w>parceler</w> <w>parceler</w>
<w>repl</w> <w>repl</w>
<w>uast</w> <w>uast</w>
<w>unboxed</w>
<w>unmute</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>
@@ -64,18 +64,18 @@ import javax.annotation.processing.Processor
import com.sun.tools.javac.util.List as JavacList import com.sun.tools.javac.util.List as JavacList
class ClasspathBasedKapt3Extension( class ClasspathBasedKapt3Extension(
paths: KaptPaths, paths: KaptPaths,
options: Map<String, String>, options: Map<String, String>,
javacOptions: Map<String, String>, javacOptions: Map<String, String>,
annotationProcessorFqNames: List<String>, annotationProcessorFqNames: List<String>,
aptMode: AptMode, aptMode: AptMode,
val useLightAnalysis: Boolean, private val useLightAnalysis: Boolean,
correctErrorTypes: Boolean, correctErrorTypes: Boolean,
mapDiagnosticLocations: Boolean, mapDiagnosticLocations: Boolean,
strictMode: Boolean, strictMode: Boolean,
pluginInitializedTime: Long, pluginInitializedTime: Long,
logger: MessageCollectorBackedKaptLogger, logger: MessageCollectorBackedKaptLogger,
compilerConfiguration: CompilerConfiguration compilerConfiguration: CompilerConfiguration
) : AbstractKapt3Extension( ) : AbstractKapt3Extension(
paths, options, javacOptions, annotationProcessorFqNames, paths, options, javacOptions, annotationProcessorFqNames,
aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, strictMode, aptMode, pluginInitializedTime, logger, correctErrorTypes, mapDiagnosticLocations, strictMode,
@@ -91,10 +91,10 @@ class ClasspathBasedKapt3Extension(
} }
override fun analysisCompleted( override fun analysisCompleted(
project: Project, project: Project,
module: ModuleDescriptor, module: ModuleDescriptor,
bindingTrace: BindingTrace, bindingTrace: BindingTrace,
files: Collection<KtFile> files: Collection<KtFile>
): AnalysisResult? { ): AnalysisResult? {
try { try {
return super.analysisCompleted(project, module, bindingTrace, files) return super.analysisCompleted(project, module, bindingTrace, files)
@@ -105,17 +105,17 @@ class ClasspathBasedKapt3Extension(
} }
abstract class AbstractKapt3Extension( abstract class AbstractKapt3Extension(
val paths: KaptPaths, val paths: KaptPaths,
val options: Map<String, String>, private val options: Map<String, String>,
val javacOptions: Map<String, String>, private val javacOptions: Map<String, String>,
val annotationProcessorFqNames: List<String>, val annotationProcessorFqNames: List<String>,
val aptMode: AptMode, private val aptMode: AptMode,
val pluginInitializedTime: Long, private val pluginInitializedTime: Long,
val logger: MessageCollectorBackedKaptLogger, val logger: MessageCollectorBackedKaptLogger,
val correctErrorTypes: Boolean, val correctErrorTypes: Boolean,
val mapDiagnosticLocations: Boolean, val mapDiagnosticLocations: Boolean,
val strictMode: Boolean, val strictMode: Boolean,
val compilerConfiguration: CompilerConfiguration val compilerConfiguration: CompilerConfiguration
) : PartialAnalysisHandlerExtension() { ) : PartialAnalysisHandlerExtension() {
private var annotationProcessingComplete = false private var annotationProcessingComplete = false
@@ -127,12 +127,12 @@ abstract class AbstractKapt3Extension(
} }
override fun doAnalysis( override fun doAnalysis(
project: Project, project: Project,
module: ModuleDescriptor, module: ModuleDescriptor,
projectContext: ProjectContext, projectContext: ProjectContext,
files: Collection<KtFile>, files: Collection<KtFile>,
bindingTrace: BindingTrace, bindingTrace: BindingTrace,
componentProvider: ComponentProvider componentProvider: ComponentProvider
): AnalysisResult? { ): AnalysisResult? {
if (aptMode == APT_ONLY) { if (aptMode == APT_ONLY) {
return AnalysisResult.EMPTY return AnalysisResult.EMPTY
@@ -142,14 +142,14 @@ abstract class AbstractKapt3Extension(
} }
override fun analysisCompleted( override fun analysisCompleted(
project: Project, project: Project,
module: ModuleDescriptor, module: ModuleDescriptor,
bindingTrace: BindingTrace, bindingTrace: BindingTrace,
files: Collection<KtFile> files: Collection<KtFile>
): AnalysisResult? { ): AnalysisResult? {
if (setAnnotationProcessingComplete()) return null if (setAnnotationProcessingComplete()) return null
fun doNotGenerateCode() = AnalysisResult.Companion.success(BindingContext.EMPTY, module, shouldGenerateCode = false) fun doNotGenerateCode() = AnalysisResult.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
logger.info { "Initial analysis took ${System.currentTimeMillis() - pluginInitializedTime} ms" } logger.info { "Initial analysis took ${System.currentTimeMillis() - pluginInitializedTime} ms" }
@@ -201,10 +201,11 @@ abstract class AbstractKapt3Extension(
doNotGenerateCode() doNotGenerateCode()
} else { } else {
AnalysisResult.RetryWithAdditionalJavaRoots( AnalysisResult.RetryWithAdditionalJavaRoots(
bindingTrace.bindingContext, bindingTrace.bindingContext,
module, module,
listOf(paths.sourcesOutputDir), listOf(paths.sourcesOutputDir),
addToEnvironment = true) addToEnvironment = true
)
} }
} }
@@ -222,24 +223,25 @@ abstract class AbstractKapt3Extension(
} }
private fun contextForStubGeneration( private fun contextForStubGeneration(
project: Project, project: Project,
module: ModuleDescriptor, module: ModuleDescriptor,
bindingContext: BindingContext, bindingContext: BindingContext,
files: List<KtFile> files: List<KtFile>
): KaptContextForStubGeneration { ): KaptContextForStubGeneration {
val builderFactory = OriginCollectingClassBuilderFactory(ClassBuilderMode.KAPT3) val builderFactory = OriginCollectingClassBuilderFactory(ClassBuilderMode.KAPT3)
val targetId = TargetId( val targetId = TargetId(
name = compilerConfiguration[CommonConfigurationKeys.MODULE_NAME] ?: module.name.asString(), name = compilerConfiguration[CommonConfigurationKeys.MODULE_NAME] ?: module.name.asString(),
type = "java-production") type = "java-production"
)
val generationState = GenerationState.Builder( val generationState = GenerationState.Builder(
project, project,
builderFactory, builderFactory,
module, module,
bindingContext, bindingContext,
files, files,
compilerConfiguration compilerConfiguration
).targetId(targetId).build() ).targetId(targetId).build()
val (classFilesCompilationTime) = measureTimeMillis { val (classFilesCompilationTime) = measureTimeMillis {
@@ -294,29 +296,30 @@ abstract class AbstractKapt3Extension(
} }
protected open fun saveIncrementalData( protected open fun saveIncrementalData(
kaptContext: KaptContextForStubGeneration, kaptContext: KaptContextForStubGeneration,
messageCollector: MessageCollector, messageCollector: MessageCollector,
converter: ClassFileToSourceStubConverter) { converter: ClassFileToSourceStubConverter
) {
val incrementalDataOutputDir = paths.incrementalDataOutputDir ?: return val incrementalDataOutputDir = paths.incrementalDataOutputDir ?: return
val reportOutputFiles = kaptContext.generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES) val reportOutputFiles = kaptContext.generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
kaptContext.generationState.factory.writeAll( kaptContext.generationState.factory.writeAll(
incrementalDataOutputDir, incrementalDataOutputDir,
if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) { if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) {
val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")] val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")]
if (stubFileObject != null) { if (stubFileObject != null) {
val stubFile = File(paths.stubsOutputDir, stubFileObject.name) val stubFile = File(paths.stubsOutputDir, stubFileObject.name)
val lineMappingsFile = File(stubFile.parentFile, stubFile.nameWithoutExtension + KAPT_METADATA_EXTENSION) val lineMappingsFile = File(stubFile.parentFile, stubFile.nameWithoutExtension + KAPT_METADATA_EXTENSION)
for (file in listOf(stubFile, lineMappingsFile)) { for (outputFile in listOf(stubFile, lineMappingsFile)) {
if (file.exists()) { if (outputFile.exists()) {
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, file)) messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, outputFile))
}
} }
} }
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
} }
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
}
) )
} }
@@ -346,7 +349,7 @@ private class PrettyWithWorkarounds(private val context: Context, val out: Write
} }
} }
private inline fun <T> measureTimeMillis(block: () -> T) : Pair<Long, T> { private inline fun <T> measureTimeMillis(block: () -> T): Pair<Long, T> {
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
val result = block() val result = block()
return Pair(System.currentTimeMillis() - start, result) return Pair(System.currentTimeMillis() - start, result)
@@ -74,47 +74,47 @@ import java.util.*
object Kapt3ConfigurationKeys { object Kapt3ConfigurationKeys {
val SOURCE_OUTPUT_DIR: CompilerConfigurationKey<String> = val SOURCE_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(SOURCE_OUTPUT_DIR_OPTION.description) CompilerConfigurationKey.create<String>(SOURCE_OUTPUT_DIR_OPTION.description)
val CLASS_OUTPUT_DIR: CompilerConfigurationKey<String> = val CLASS_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(CLASS_OUTPUT_DIR_OPTION.description) CompilerConfigurationKey.create<String>(CLASS_OUTPUT_DIR_OPTION.description)
val STUBS_OUTPUT_DIR: CompilerConfigurationKey<String> = val STUBS_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(STUBS_OUTPUT_DIR_OPTION.description) CompilerConfigurationKey.create<String>(STUBS_OUTPUT_DIR_OPTION.description)
val INCREMENTAL_DATA_OUTPUT_DIR: CompilerConfigurationKey<String> = val INCREMENTAL_DATA_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(INCREMENTAL_DATA_OUTPUT_DIR_OPTION.description) CompilerConfigurationKey.create<String>(INCREMENTAL_DATA_OUTPUT_DIR_OPTION.description)
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> = val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSOR_CLASSPATH_OPTION.description) CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSOR_CLASSPATH_OPTION.description)
val APT_OPTIONS: CompilerConfigurationKey<String> = val APT_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(APT_OPTIONS_OPTION.description) CompilerConfigurationKey.create<String>(APT_OPTIONS_OPTION.description)
val JAVAC_CLI_OPTIONS: CompilerConfigurationKey<String> = val JAVAC_CLI_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(JAVAC_CLI_OPTIONS_OPTION.description) CompilerConfigurationKey.create<String>(JAVAC_CLI_OPTIONS_OPTION.description)
val ANNOTATION_PROCESSORS: CompilerConfigurationKey<List<String>> = val ANNOTATION_PROCESSORS: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSORS_OPTION.description) CompilerConfigurationKey.create<List<String>>(ANNOTATION_PROCESSORS_OPTION.description)
val VERBOSE_MODE: CompilerConfigurationKey<String> = val VERBOSE_MODE: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(VERBOSE_MODE_OPTION.description) CompilerConfigurationKey.create<String>(VERBOSE_MODE_OPTION.description)
val INFO_AS_WARNINGS: CompilerConfigurationKey<String> = val INFO_AS_WARNINGS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(INFO_AS_WARNINGS_OPTION.description) CompilerConfigurationKey.create<String>(INFO_AS_WARNINGS_OPTION.description)
@Deprecated("Use APT_MODE instead.") @Deprecated("Use APT_MODE instead.")
val APT_ONLY: CompilerConfigurationKey<String> = val APT_ONLY: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(APT_ONLY_OPTION.description) CompilerConfigurationKey.create<String>(APT_ONLY_OPTION.description)
val APT_MODE: CompilerConfigurationKey<String> = val APT_MODE: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(APT_MODE_OPTION.description) CompilerConfigurationKey.create<String>(APT_MODE_OPTION.description)
val USE_LIGHT_ANALYSIS: CompilerConfigurationKey<String> = val USE_LIGHT_ANALYSIS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(USE_LIGHT_ANALYSIS_OPTION.description) CompilerConfigurationKey.create<String>(USE_LIGHT_ANALYSIS_OPTION.description)
val CORRECT_ERROR_TYPES: CompilerConfigurationKey<String> = val CORRECT_ERROR_TYPES: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>(CORRECT_ERROR_TYPES_OPTION.description) CompilerConfigurationKey.create<String>(CORRECT_ERROR_TYPES_OPTION.description)
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)
@@ -125,61 +125,81 @@ object Kapt3ConfigurationKeys {
class Kapt3CommandLineProcessor : CommandLineProcessor { class Kapt3CommandLineProcessor : CommandLineProcessor {
companion object { companion object {
val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3" const val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3"
val CONFIGURATION = CliOption("configuration", "<encoded>", "Encoded configuration", required = false) val CONFIGURATION = CliOption("configuration", "<encoded>", "Encoded configuration", required = false)
val SOURCE_OUTPUT_DIR_OPTION: CliOption = val SOURCE_OUTPUT_DIR_OPTION: CliOption =
CliOption("sources", "<path>", "Output path for the generated files", required = false) CliOption("sources", "<path>", "Output path for the generated files", required = false)
val CLASS_OUTPUT_DIR_OPTION: CliOption = val CLASS_OUTPUT_DIR_OPTION: CliOption =
CliOption("classes", "<path>", "Output path for the class files", required = false) CliOption("classes", "<path>", "Output path for the class files", required = false)
val STUBS_OUTPUT_DIR_OPTION: CliOption = val STUBS_OUTPUT_DIR_OPTION: CliOption =
CliOption("stubs", "<path>", "Output path for the Java stubs", required = false) CliOption("stubs", "<path>", "Output path for the Java stubs", required = false)
val INCREMENTAL_DATA_OUTPUT_DIR_OPTION: CliOption = val INCREMENTAL_DATA_OUTPUT_DIR_OPTION: CliOption =
CliOption("incrementalData", "<path>", "Output path for the incremental data", required = false) CliOption("incrementalData", "<path>", "Output path for the incremental data", required = false)
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption = val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
CliOption("apclasspath", "<classpath>", "Annotation processor classpath", CliOption(
required = false, allowMultipleOccurrences = true) "apclasspath", "<classpath>", "Annotation processor classpath",
required = false, allowMultipleOccurrences = true
)
val APT_OPTIONS_OPTION: CliOption = val APT_OPTIONS_OPTION: CliOption =
CliOption("apoptions", "options map", "Encoded annotation processor options", CliOption(
required = false, allowMultipleOccurrences = false) "apoptions", "options map", "Encoded annotation processor options",
required = false, allowMultipleOccurrences = false
)
val JAVAC_CLI_OPTIONS_OPTION: CliOption = val JAVAC_CLI_OPTIONS_OPTION: CliOption =
CliOption("javacArguments", "javac CLI options map", "Encoded javac CLI options", CliOption(
required = false, allowMultipleOccurrences = false) "javacArguments", "javac CLI options map", "Encoded javac CLI options",
required = false, allowMultipleOccurrences = false
)
val ANNOTATION_PROCESSORS_OPTION: CliOption = val ANNOTATION_PROCESSORS_OPTION: CliOption =
CliOption("processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names", CliOption(
required = false, allowMultipleOccurrences = true) "processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names",
required = false, allowMultipleOccurrences = true
)
val VERBOSE_MODE_OPTION: CliOption = val VERBOSE_MODE_OPTION: CliOption =
CliOption("verbose", "true | false", "Enable verbose output", required = false) CliOption("verbose", "true | false", "Enable verbose output", required = false)
val INFO_AS_WARNINGS_OPTION: CliOption = val INFO_AS_WARNINGS_OPTION: CliOption =
CliOption("infoAsWarnings", "true | false", "Show information messages as warnings", required = false) CliOption("infoAsWarnings", "true | false", "Show information messages as warnings", required = false)
@Deprecated("Use APT_MODE_OPTION instead.") @Deprecated("Use APT_MODE_OPTION instead.")
val APT_ONLY_OPTION: CliOption = val APT_ONLY_OPTION: CliOption =
CliOption("aptOnly", "true | false", "Run only annotation processing, do not compile Kotlin files", required = false) CliOption("aptOnly", "true | false", "Run only annotation processing, do not compile Kotlin files", required = false)
val APT_MODE_OPTION: CliOption = val APT_MODE_OPTION: CliOption =
CliOption("aptMode", "apt | stubs | stubsAndApt | compile", CliOption(
"Annotation processing mode: only apt, only stub generation, both, or with the subsequent compilation", "aptMode", "apt | stubs | stubsAndApt | compile",
required = false) "Annotation processing mode: only apt, only stub generation, both, or with the subsequent compilation",
required = false
)
val USE_LIGHT_ANALYSIS_OPTION: CliOption = val USE_LIGHT_ANALYSIS_OPTION: CliOption =
CliOption("useLightAnalysis", "true | false", "Do not analyze declaration bodies if can", required = false) CliOption("useLightAnalysis", "true | false", "Do not analyze declaration bodies if can", required = false)
val CORRECT_ERROR_TYPES_OPTION: CliOption = val CORRECT_ERROR_TYPES_OPTION: CliOption =
CliOption("correctErrorTypes", "true | false", "Replace generated or error types with ones from the generated sources", required = false) CliOption(
"correctErrorTypes",
"true | false",
"Replace generated or error types with ones from the generated sources",
required = false
)
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 = val STRICT_MODE_OPTION: CliOption =
CliOption("strict", "true | false", "Show errors on incompatibilities during stub generation", required = false) CliOption("strict", "true | false", "Show errors on incompatibilities during stub generation", required = false)
@@ -188,10 +208,12 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> = override val pluginOptions: Collection<CliOption> =
listOf(SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, JAVAC_CLI_OPTIONS_OPTION, listOf(
CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, APT_MODE_OPTION, SOURCE_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION, APT_OPTIONS_OPTION, JAVAC_CLI_OPTIONS_OPTION,
USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION, INCREMENTAL_DATA_OUTPUT_DIR_OPTION, CLASS_OUTPUT_DIR_OPTION, VERBOSE_MODE_OPTION, STUBS_OUTPUT_DIR_OPTION, APT_ONLY_OPTION, APT_MODE_OPTION,
CONFIGURATION, MAP_DIAGNOSTIC_LOCATIONS_OPTION, INFO_AS_WARNINGS_OPTION, STRICT_MODE_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, 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) {
@@ -238,14 +260,13 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
} }
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) { override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val aptMode = AptMode.parse(configuration.get(Kapt3ConfigurationKeys.APT_MODE) ?: val aptMode = AptMode.parse(configuration.get(Kapt3ConfigurationKeys.APT_MODE) ?: configuration.get(Kapt3ConfigurationKeys.APT_ONLY))
configuration.get(Kapt3ConfigurationKeys.APT_ONLY))
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 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)
fun abortAnalysis() = AnalysisHandlerExtension.registerExtension(project, AbortAnalysisHandlerExtension()) fun abortAnalysis() = AnalysisHandlerExtension.registerExtension(project, AbortAnalysisHandlerExtension())
@@ -365,7 +386,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
bindingTrace: BindingTrace, bindingTrace: BindingTrace,
files: Collection<KtFile> files: Collection<KtFile>
): AnalysisResult? { ): AnalysisResult? {
return AnalysisResult.Companion.success(bindingTrace.bindingContext, module, shouldGenerateCode = false) return AnalysisResult.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
} }
} }
} }
@@ -25,10 +25,10 @@ import javax.lang.model.element.NestingKind
import javax.tools.JavaFileObject import javax.tools.JavaFileObject
class KaptJavaFileObject( class KaptJavaFileObject(
val compilationUnit: JCTree.JCCompilationUnit, val compilationUnit: JCTree.JCCompilationUnit,
val clazz: JCTree.JCClassDecl, val clazz: JCTree.JCClassDecl,
val file: File? = null, val file: File? = null,
val timestamp: Long = System.currentTimeMillis() val timestamp: Long = System.currentTimeMillis()
) : JavaFileObject { ) : JavaFileObject {
override fun toString() = "${javaClass.simpleName}[$name]" override fun toString() = "${javaClass.simpleName}[$name]"
@@ -38,6 +38,7 @@ class KaptTreeMaker(context: Context, kaptContext: KaptContextForStubGeneration)
val nameTable: Name.Table = Names.instance(context).table val nameTable: Name.Table = Names.instance(context).table
@Suppress("FunctionName")
fun Type(type: Type): JCTree.JCExpression { fun Type(type: Type): JCTree.JCExpression {
convertBuiltinType(type)?.let { return it } convertBuiltinType(type)?.let { return it }
if (type.sort == ARRAY) { if (type.sort == ARRAY) {
@@ -46,14 +47,17 @@ class KaptTreeMaker(context: Context, kaptContext: KaptContextForStubGeneration)
return FqName(type.internalName) return FqName(type.internalName)
} }
@Suppress("FunctionName")
fun FqName(internalOrFqName: String): JCTree.JCExpression { fun FqName(internalOrFqName: String): JCTree.JCExpression {
val path = getQualifiedName(internalOrFqName).convertSpecialFqName().split('.') val path = getQualifiedName(internalOrFqName).convertSpecialFqName().split('.')
assert(path.isNotEmpty()) assert(path.isNotEmpty())
return FqName(path) return FqName(path)
} }
@Suppress("FunctionName")
fun FqName(fqName: FqName) = FqName(fqName.pathSegments().map { it.asString() }) fun FqName(fqName: FqName) = FqName(fqName.pathSegments().map { it.asString() })
@Suppress("FunctionName")
private fun FqName(path: List<String>): JCTree.JCExpression { private fun FqName(path: List<String>): JCTree.JCExpression {
if (path.size == 1) return SimpleName(path.single()) if (path.size == 1) return SimpleName(path.single())
@@ -162,6 +166,7 @@ class KaptTreeMaker(context: Context, kaptContext: KaptContextForStubGeneration)
return TypeIdent(typeTag) return TypeIdent(typeTag)
} }
@Suppress("FunctionName")
fun SimpleName(name: String): JCTree.JCExpression = Ident(name(name)) fun SimpleName(name: String): JCTree.JCExpression = Ident(name(name))
fun name(name: String): Name = nameTable.fromString(name) fun name(name: String): Name = nameTable.fromString(name)
@@ -63,31 +63,31 @@ import javax.lang.model.element.ElementKind
import com.sun.tools.javac.util.List as JavacList 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 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 const val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
private val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).toLong() private const val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).toLong()
private val CLASS_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or private const val CLASS_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_INTERFACE or Opcodes.ACC_ANNOTATION or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong() (Opcodes.ACC_DEPRECATED or Opcodes.ACC_INTERFACE or Opcodes.ACC_ANNOTATION or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
private val METHOD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or private const val METHOD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_DEPRECATED or Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_NATIVE or Opcodes.ACC_STATIC or Opcodes.ACC_STRICT).toLong() (Opcodes.ACC_DEPRECATED or Opcodes.ACC_SYNCHRONIZED or Opcodes.ACC_NATIVE or Opcodes.ACC_STATIC or Opcodes.ACC_STRICT).toLong()
private val FIELD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or private const val FIELD_MODIFIERS = VISIBILITY_MODIFIERS or MODALITY_MODIFIERS or
(Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong() (Opcodes.ACC_VOLATILE or Opcodes.ACC_TRANSIENT or Opcodes.ACC_ENUM or Opcodes.ACC_STATIC).toLong()
private val PARAMETER_MODIFIERS = FIELD_MODIFIERS or Flags.PARAMETER or Flags.VARARGS or Opcodes.ACC_FINAL.toLong() private const val PARAMETER_MODIFIERS = FIELD_MODIFIERS or Flags.PARAMETER or Flags.VARARGS or Opcodes.ACC_FINAL.toLong()
private val BLACKLISTED_ANNOTATIONS = listOf( private val BLACKLISTED_ANNOTATIONS = listOf(
"java.lang.Deprecated", "kotlin.Deprecated", // Deprecated annotations "java.lang.Deprecated", "kotlin.Deprecated", // Deprecated annotations
"java.lang.Synthetic", "java.lang.Synthetic",
"synthetic.kotlin.jvm.GeneratedByJvmOverloads", // kapt3-related annotation for marking JvmOverloads-generated methods "synthetic.kotlin.jvm.GeneratedByJvmOverloads", // kapt3-related annotation for marking JvmOverloads-generated methods
"kotlin.jvm." // Kotlin annotations from runtime "kotlin.jvm." // Kotlin annotations from runtime
) )
private val NON_EXISTENT_CLASS_NAME = FqName("error.NonExistentClass") private val NON_EXISTENT_CLASS_NAME = FqName("error.NonExistentClass")
@@ -95,8 +95,8 @@ class ClassFileToSourceStubConverter(
private val JAVA_KEYWORD_FILTER_REGEX = "[a-z]+".toRegex() private val JAVA_KEYWORD_FILTER_REGEX = "[a-z]+".toRegex()
private val JAVA_KEYWORDS = Tokens.TokenKind.values() private val JAVA_KEYWORDS = Tokens.TokenKind.values()
.filter { JAVA_KEYWORD_FILTER_REGEX.matches(it.toString().orEmpty()) } .filter { JAVA_KEYWORD_FILTER_REGEX.matches(it.toString().orEmpty()) }
.mapTo(hashSetOf(), Any::toString) .mapTo(hashSetOf(), Any::toString)
} }
private val _bindings = mutableMapOf<String, KaptJavaFileObject>() private val _bindings = mutableMapOf<String, KaptJavaFileObject>()
@@ -130,12 +130,13 @@ class ClassFileToSourceStubConverter(
private fun generateNonExistentClass(): JCCompilationUnit { private fun generateNonExistentClass(): JCCompilationUnit {
val nonExistentClass = treeMaker.ClassDef( val nonExistentClass = treeMaker.ClassDef(
treeMaker.Modifiers((Flags.PUBLIC or Flags.FINAL).toLong()), treeMaker.Modifiers((Flags.PUBLIC or Flags.FINAL).toLong()),
treeMaker.name(NON_EXISTENT_CLASS_NAME.shortName().asString()), treeMaker.name(NON_EXISTENT_CLASS_NAME.shortName().asString()),
JavacList.nil(), JavacList.nil(),
null, null,
JavacList.nil(), JavacList.nil(),
JavacList.nil()) JavacList.nil()
)
val topLevel = treeMaker.TopLevelJava9Aware(treeMaker.FqName(NON_EXISTENT_CLASS_NAME.parent()), JavacList.of(nonExistentClass)) val topLevel = treeMaker.TopLevelJava9Aware(treeMaker.FqName(NON_EXISTENT_CLASS_NAME.parent()), JavacList.of(nonExistentClass))
@@ -145,7 +146,7 @@ class ClassFileToSourceStubConverter(
return topLevel return topLevel
} }
class KaptStub(val file: JCCompilationUnit, val kaptMetadata: ByteArray? = null) { class KaptStub(val file: JCCompilationUnit, private val kaptMetadata: ByteArray? = null) {
fun writeMetadataIfNeeded(forSource: File) { fun writeMetadataIfNeeded(forSource: File) {
if (kaptMetadata == null) { if (kaptMetadata == null) {
return return
@@ -166,7 +167,7 @@ class ClassFileToSourceStubConverter(
val descriptor = origin.descriptor ?: return null val descriptor = origin.descriptor ?: return null
// Nested classes will be processed during the outer classes conversion // Nested classes will be processed during the outer classes conversion
if ((descriptor as? ClassDescriptor)?.isNested ?: false) return null if ((descriptor as? ClassDescriptor)?.isNested == true) return null
val lineMappings = KaptLineMappingCollector(kaptContext) val lineMappings = KaptLineMappingCollector(kaptContext)
@@ -245,7 +246,7 @@ class ClassFileToSourceStubConverter(
val shortName = importedFqName.shortName() val shortName = importedFqName.shortName()
if (shortName.asString() == classDeclaration.simpleName.toString()) continue if (shortName.asString() == classDeclaration.simpleName.toString()) continue
val importedReference = resolveImportReference@ run { val importedReference = /* resolveImportReference */ run {
val referenceExpression = getReferenceExpression(importDirective.importedReference) ?: return@run null val referenceExpression = getReferenceExpression(importDirective.importedReference) ?: return@run null
val bindingContext = kaptContext.bindingContext val bindingContext = kaptContext.bindingContext
@@ -283,10 +284,10 @@ class ClassFileToSourceStubConverter(
* Returns false for the inner classes or if the origin for the class was not found. * Returns false for the inner classes or if the origin for the class was not found.
*/ */
private fun convertClass( private fun convertClass(
clazz: ClassNode, clazz: ClassNode,
lineMappings: KaptLineMappingCollector, lineMappings: KaptLineMappingCollector,
packageFqName: String, packageFqName: String,
isTopLevel: Boolean isTopLevel: Boolean
): JCClassDecl? { ): JCClassDecl? {
if (isSynthetic(clazz.access)) return null if (isSynthetic(clazz.access)) return null
if (!checkIfValidTypeName(clazz, Type.getObjectType(clazz.name))) return null if (!checkIfValidTypeName(clazz, Type.getObjectType(clazz.name))) return null
@@ -300,14 +301,16 @@ class ClassFileToSourceStubConverter(
val isEnum = clazz.isEnum() val isEnum = clazz.isEnum()
val isAnnotation = clazz.isAnnotation() val isAnnotation = clazz.isAnnotation()
val modifiers = convertModifiers(flags, val modifiers = convertModifiers(
if (isEnum) ElementKind.ENUM else ElementKind.CLASS, flags,
packageFqName, clazz.visibleAnnotations, clazz.invisibleAnnotations, descriptor.annotations) if (isEnum) ElementKind.ENUM else ElementKind.CLASS,
packageFqName, clazz.visibleAnnotations, clazz.invisibleAnnotations, descriptor.annotations
)
val isDefaultImpls = clazz.name.endsWith("${descriptor.name.asString()}\$DefaultImpls") val isDefaultImpls = clazz.name.endsWith("${descriptor.name.asString()}\$DefaultImpls")
&& isPublic(clazz.access) && isFinal(clazz.access) && isPublic(clazz.access) && isFinal(clazz.access)
&& descriptor is ClassDescriptor && descriptor is ClassDescriptor
&& descriptor.kind == ClassKind.INTERFACE && descriptor.kind == ClassKind.INTERFACE
// DefaultImpls without any contents don't have INNERCLASS'es inside it (and inside the parent interface) // DefaultImpls without any contents don't have INNERCLASS'es inside it (and inside the parent interface)
if (isDefaultImpls && (isTopLevel || (clazz.fields.isNullOrEmpty() && clazz.methods.isNullOrEmpty()))) { if (isDefaultImpls && (isTopLevel || (clazz.fields.isNullOrEmpty() && clazz.methods.isNullOrEmpty()))) {
@@ -357,12 +360,15 @@ class ClassFileToSourceStubConverter(
val def = data.correspondingClass?.let { convertClass(it, lineMappings, packageFqName, false) } val def = data.correspondingClass?.let { convertClass(it, lineMappings, packageFqName, false) }
convertField(data.field, clazz, lineMappings, packageFqName, treeMaker.NewClass( convertField(
data.field, clazz, lineMappings, packageFqName, treeMaker.NewClass(
/* enclosing = */ null, /* enclosing = */ null,
/* typeArgs = */ JavacList.nil(), /* typeArgs = */ JavacList.nil(),
/* clazz = */ treeMaker.Ident(treeMaker.name(data.field.name)), /* clazz = */ treeMaker.Ident(treeMaker.name(data.field.name)),
/* args = */ args, /* args = */ args,
/* def = */ def)) /* def = */ def
)
)
} }
val fields = mapJList<FieldNode, JCTree>(clazz.fields) { val fields = mapJList<FieldNode, JCTree>(clazz.fields) {
@@ -390,12 +396,13 @@ class ClassFileToSourceStubConverter(
val superTypes = calculateSuperTypes(clazz, genericType) val superTypes = calculateSuperTypes(clazz, genericType)
return treeMaker.ClassDef( return treeMaker.ClassDef(
modifiers, modifiers,
treeMaker.name(simpleName), treeMaker.name(simpleName),
genericType.typeParameters, genericType.typeParameters,
superTypes.superClass, superTypes.superClass,
superTypes.interfaces, superTypes.interfaces,
enumValues + fields + methods + nestedClasses).keepKdocComments(clazz) enumValues + fields + methods + nestedClasses
).keepKdocComments(clazz)
} }
private class ClassSupertypes(val superClass: JCExpression?, val interfaces: JavacList<JCExpression>) private class ClassSupertypes(val superClass: JCExpression?, val interfaces: JavacList<JCExpression>)
@@ -456,7 +463,7 @@ class ClassFileToSourceStubConverter(
val (resolvedAsClasses, otherSuperTypes) = resolvedSuperTypes val (resolvedAsClasses, otherSuperTypes) = resolvedSuperTypes
.partition { .partition {
it.second?.isError == false it.second?.isError == false
&& (it.second?.constructor?.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.CLASS && (it.second?.constructor?.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.CLASS
} }
if (resolvedAsClasses.size > 1) { if (resolvedAsClasses.size > 1) {
@@ -526,8 +533,8 @@ 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 doesInnerClassNameConflictWithOuter( private tailrec fun doesInnerClassNameConflictWithOuter(
clazz: ClassNode, clazz: ClassNode,
outerClass: ClassNode? = findContainingClassNode(clazz) outerClass: ClassNode? = findContainingClassNode(clazz)
): Boolean { ): Boolean {
if (outerClass == null) return false if (outerClass == null) return false
if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true
@@ -559,11 +566,11 @@ class ClassFileToSourceStubConverter(
} }
private fun convertField( private fun convertField(
field: FieldNode, field: FieldNode,
containingClass: ClassNode, containingClass: ClassNode,
lineMappings: KaptLineMappingCollector, lineMappings: KaptLineMappingCollector,
packageFqName: String, packageFqName: String,
explicitInitializer: JCExpression? = null explicitInitializer: JCExpression? = null
): JCVariableDecl? { ): JCVariableDecl? {
if (isSynthetic(field.access) || isIgnored(field.invisibleAnnotations)) return null if (isSynthetic(field.access) || isIgnored(field.invisibleAnnotations)) return null
// not needed anymore // not needed anymore
@@ -606,8 +613,8 @@ class ClassFileToSourceStubConverter(
val value = field.value val value = field.value
val initializer = explicitInitializer val initializer = explicitInitializer
?: convertValueOfPrimitiveTypeOrString(value) ?: convertValueOfPrimitiveTypeOrString(value)
?: if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null ?: if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null
lineMappings.registerField(containingClass, field) lineMappings.registerField(containingClass, field)
@@ -615,16 +622,16 @@ class ClassFileToSourceStubConverter(
} }
private fun convertMethod( private fun convertMethod(
method: MethodNode, method: MethodNode,
containingClass: ClassNode, containingClass: ClassNode,
lineMappings: KaptLineMappingCollector, lineMappings: KaptLineMappingCollector,
packageFqName: String packageFqName: String
): JCMethodDecl? { ): JCMethodDecl? {
if (isIgnored(method.invisibleAnnotations)) return null if (isIgnored(method.invisibleAnnotations)) return null
val descriptor = kaptContext.origins[method]?.descriptor as? CallableDescriptor ?: return null val descriptor = kaptContext.origins[method]?.descriptor as? CallableDescriptor ?: return null
val isAnnotationHolderForProperty = descriptor is PropertyDescriptor && isSynthetic(method.access) val isAnnotationHolderForProperty = descriptor is PropertyDescriptor && isSynthetic(method.access)
&& isStatic(method.access) && method.name.endsWith("\$annotations") && isStatic(method.access) && method.name.endsWith("\$annotations")
if (isSynthetic(method.access) && !isAnnotationHolderForProperty) return null if (isSynthetic(method.access) && !isAnnotationHolderForProperty) return null
@@ -641,11 +648,12 @@ class ClassFileToSourceStubConverter(
if (!isValidIdentifier(name, canBeConstructor = isConstructor)) return null if (!isValidIdentifier(name, canBeConstructor = isConstructor)) return null
val modifiers = convertModifiers( val modifiers = convertModifiers(
if (containingClass.isEnum() && isConstructor) if (containingClass.isEnum() && isConstructor)
(method.access.toLong() and VISIBILITY_MODIFIERS.inv()) (method.access.toLong() and VISIBILITY_MODIFIERS.inv())
else else
method.access.toLong(), method.access.toLong(),
ElementKind.METHOD, packageFqName, visibleAnnotations, method.invisibleAnnotations, descriptor.annotations) ElementKind.METHOD, packageFqName, visibleAnnotations, method.invisibleAnnotations, descriptor.annotations
)
val asmReturnType = Type.getReturnType(method.desc) val asmReturnType = Type.getReturnType(method.desc)
val jcReturnType = if (isConstructor) null else treeMaker.Type(asmReturnType) val jcReturnType = if (isConstructor) null else treeMaker.Type(asmReturnType)
@@ -665,14 +673,15 @@ class ClassFileToSourceStubConverter(
val varargs = if (lastParameter && isArrayType && method.isVarargs()) Flags.VARARGS else 0L val varargs = if (lastParameter && isArrayType && method.isVarargs()) Flags.VARARGS else 0L
val modifiers = convertModifiers( val modifiers = convertModifiers(
info.flags or varargs or Flags.PARAMETER, info.flags or varargs or Flags.PARAMETER,
ElementKind.PARAMETER, ElementKind.PARAMETER,
packageFqName, packageFqName,
info.visibleAnnotations, info.visibleAnnotations,
info.invisibleAnnotations, info.invisibleAnnotations,
Annotations.EMPTY /* TODO */) Annotations.EMPTY /* TODO */
)
val name = info.name.takeIf { isValidIdentifier(it) } ?: "p${index}_" + info.name.hashCode().ushr(1) val name = info.name.takeIf { isValidIdentifier(it) } ?: ("p" + index + "_" + info.name.hashCode().ushr(1))
val type = treeMaker.Type(info.type) val type = treeMaker.Type(info.type)
treeMaker.VarDef(modifiers, treeMaker.name(name), type, null) treeMaker.VarDef(modifiers, treeMaker.name(name), type, null)
} }
@@ -680,8 +689,8 @@ class ClassFileToSourceStubConverter(
val exceptionTypes = mapJList(method.exceptions) { treeMaker.FqName(it) } val exceptionTypes = mapJList(method.exceptions) { treeMaker.FqName(it) }
val valueParametersFromDescriptor = descriptor.valueParameters val valueParametersFromDescriptor = descriptor.valueParameters
val (genericSignature, returnType) = extractMethodSignatureTypes( val (genericSignature, returnType) =
descriptor, exceptionTypes, jcReturnType, method, parameters, valueParametersFromDescriptor) extractMethodSignatureTypes(descriptor, exceptionTypes, jcReturnType, method, parameters, valueParametersFromDescriptor)
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) } val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
@@ -718,9 +727,9 @@ class ClassFileToSourceStubConverter(
lineMappings.registerMethod(containingClass, method) lineMappings.registerMethod(containingClass, method)
return treeMaker.MethodDef( return treeMaker.MethodDef(
modifiers, treeMaker.name(name), returnType, genericSignature.typeParameters, modifiers, treeMaker.name(name), returnType, genericSignature.typeParameters,
genericSignature.parameterTypes, genericSignature.exceptionTypes, genericSignature.parameterTypes, genericSignature.exceptionTypes,
body, defaultValue body, defaultValue
).keepKdocComments(method).keepSignature(lineMappings, method) ).keepKdocComments(method).keepSignature(lineMappings, method)
} }
@@ -730,36 +739,34 @@ class ClassFileToSourceStubConverter(
} }
private fun extractMethodSignatureTypes( private fun extractMethodSignatureTypes(
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
exceptionTypes: JavacList<JCExpression>, exceptionTypes: JavacList<JCExpression>,
jcReturnType: JCExpression?, method: MethodNode, jcReturnType: JCExpression?, method: MethodNode,
parameters: JavacList<JCVariableDecl>, parameters: JavacList<JCVariableDecl>,
valueParametersFromDescriptor: List<ValueParameterDescriptor> valueParametersFromDescriptor: List<ValueParameterDescriptor>
): Pair<SignatureParser.MethodGenericSignature, JCExpression?> { ): Pair<SignatureParser.MethodGenericSignature, JCExpression?> {
val genericSignature = signatureParser.parseMethodSignature( val genericSignature = signatureParser.parseMethodSignature(
method.signature, parameters, exceptionTypes, jcReturnType, method.signature, parameters, exceptionTypes, jcReturnType,
nonErrorParameterTypeProvider = { index, lazyType -> nonErrorParameterTypeProvider = { index, lazyType ->
if (descriptor is PropertySetterDescriptor && valueParametersFromDescriptor.size == 1 && index == 0) { if (descriptor is PropertySetterDescriptor && valueParametersFromDescriptor.size == 1 && index == 0) {
getNonErrorType(descriptor.correspondingProperty.returnType, METHOD_PARAMETER_TYPE, getNonErrorType(descriptor.correspondingProperty.returnType, METHOD_PARAMETER_TYPE,
ktTypeProvider = { ktTypeProvider = {
val setterOrigin = (kaptContext.origins[method]?.element as? KtCallableDeclaration) val setterOrigin = (kaptContext.origins[method]?.element as? KtCallableDeclaration)
?.takeIf { it !is KtFunction } ?.takeIf { it !is KtFunction }
setterOrigin?.typeReference setterOrigin?.typeReference
}, },
ifNonError = { lazyType() }) ifNonError = { lazyType() })
} } else if (descriptor is FunctionDescriptor && valueParametersFromDescriptor.size == parameters.size) {
else if (descriptor is FunctionDescriptor && valueParametersFromDescriptor.size == parameters.size) { getNonErrorType(valueParametersFromDescriptor[index].type, METHOD_PARAMETER_TYPE,
getNonErrorType(valueParametersFromDescriptor[index].type, METHOD_PARAMETER_TYPE, ktTypeProvider = {
ktTypeProvider = { (kaptContext.origins[method]?.element as? KtFunction)?.valueParameters?.get(index)?.typeReference
(kaptContext.origins[method]?.element as? KtFunction)?.valueParameters?.get(index)?.typeReference },
}, ifNonError = { lazyType() })
ifNonError = { lazyType() }) } else {
} lazyType()
else { }
lazyType() })
}
})
val returnType = getNonErrorType( val returnType = getNonErrorType(
descriptor.returnType, RETURN_TYPE, descriptor.returnType, RETURN_TYPE,
@@ -779,10 +786,10 @@ class ClassFileToSourceStubConverter(
} }
private inline fun <T : JCExpression?> getNonErrorType( private inline fun <T : JCExpression?> getNonErrorType(
type: KotlinType?, type: KotlinType?,
kind: ErrorTypeCorrector.TypeKind, kind: ErrorTypeCorrector.TypeKind,
ktTypeProvider: () -> KtTypeReference?, ktTypeProvider: () -> KtTypeReference?,
ifNonError: () -> T ifNonError: () -> T
): T { ): T {
if (!correctErrorTypes) { if (!correctErrorTypes) {
return ifNonError() return ifNonError()
@@ -802,8 +809,8 @@ class ClassFileToSourceStubConverter(
if (nonErrorType is JCFieldAccess) { if (nonErrorType is JCFieldAccess) {
val qualifier = nonErrorType.selected val qualifier = nonErrorType.selected
if (nonErrorType.name.toString() == NON_EXISTENT_CLASS_NAME.shortName().asString() if (nonErrorType.name.toString() == NON_EXISTENT_CLASS_NAME.shortName().asString()
&& qualifier is JCIdent && qualifier is JCIdent
&& qualifier.name.toString() == NON_EXISTENT_CLASS_NAME.parent().asString() && qualifier.name.toString() == NON_EXISTENT_CLASS_NAME.parent().asString()
) { ) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return treeMaker.FqName("java.lang.Object") as T return treeMaker.FqName("java.lang.Object") as T
@@ -834,25 +841,25 @@ class ClassFileToSourceStubConverter(
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
private inline fun convertModifiers( private inline fun convertModifiers(
access: Int, access: Int,
kind: ElementKind, kind: ElementKind,
packageFqName: String, packageFqName: String,
visibleAnnotations: List<AnnotationNode>?, visibleAnnotations: List<AnnotationNode>?,
invisibleAnnotations: List<AnnotationNode>?, invisibleAnnotations: List<AnnotationNode>?,
descriptorAnnotations: Annotations descriptorAnnotations: Annotations
): JCModifiers = convertModifiers(access.toLong(), kind, packageFqName, visibleAnnotations, invisibleAnnotations, descriptorAnnotations) ): JCModifiers = convertModifiers(access.toLong(), kind, packageFqName, visibleAnnotations, invisibleAnnotations, descriptorAnnotations)
private fun convertModifiers( private fun convertModifiers(
access: Long, access: Long,
kind: ElementKind, kind: ElementKind,
packageFqName: String, packageFqName: String,
visibleAnnotations: List<AnnotationNode>?, visibleAnnotations: List<AnnotationNode>?,
invisibleAnnotations: List<AnnotationNode>?, invisibleAnnotations: List<AnnotationNode>?,
descriptorAnnotations: Annotations descriptorAnnotations: Annotations
): JCModifiers { ): JCModifiers {
fun convertAndAdd(list: JavacList<JCAnnotation>, anno: AnnotationNode): JavacList<JCAnnotation> { fun convertAndAdd(list: JavacList<JCAnnotation>, annotation: AnnotationNode): JavacList<JCAnnotation> {
val annotationDescriptor = descriptorAnnotations.singleOrNull { checkIfAnnotationValueMatches(anno, AnnotationValue(it)) } val annotationDescriptor = descriptorAnnotations.singleOrNull { checkIfAnnotationValueMatches(annotation, AnnotationValue(it)) }
val annotationTree = convertAnnotation(anno, packageFqName, annotationDescriptor) ?: return list val annotationTree = convertAnnotation(annotation, packageFqName, annotationDescriptor) ?: return list
return list.prepend(annotationTree) return list.prepend(annotationTree)
} }
@@ -871,10 +878,10 @@ class ClassFileToSourceStubConverter(
} }
private fun convertAnnotation( private fun convertAnnotation(
annotation: AnnotationNode, annotation: AnnotationNode,
packageFqName: String? = "", packageFqName: String? = "",
annotationDescriptor: AnnotationDescriptor? = null, annotationDescriptor: AnnotationDescriptor? = null,
filtered: Boolean = true filtered: Boolean = true
): JCAnnotation? { ): JCAnnotation? {
val annotationType = Type.getType(annotation.desc) val annotationType = Type.getType(annotation.desc)
val fqName = treeMaker.getQualifiedName(annotationType) val fqName = treeMaker.getQualifiedName(annotationType)
@@ -885,9 +892,9 @@ class ClassFileToSourceStubConverter(
val ktAnnotation = (annotationDescriptor?.source as? PsiSourceElement)?.psi as? KtAnnotationEntry val ktAnnotation = (annotationDescriptor?.source as? PsiSourceElement)?.psi as? KtAnnotationEntry
val argMapping = ktAnnotation?.calleeExpression val argMapping = ktAnnotation?.calleeExpression
?.getResolvedCall(kaptContext.bindingContext)?.valueArguments ?.getResolvedCall(kaptContext.bindingContext)?.valueArguments
?.mapKeys { it.key.name.asString() } ?.mapKeys { it.key.name.asString() }
?: emptyMap() ?: emptyMap()
val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName
@@ -922,7 +929,7 @@ class ClassFileToSourceStubConverter(
val args = value?.arguments?.mapNotNull { it.getArgumentExpression() } ?: emptyList() val args = value?.arguments?.mapNotNull { it.getArgumentExpression() } ?: emptyList()
val singleArg = args.singleOrNull() val singleArg = args.singleOrNull()
if (constantValue.isOfPrimiviteType()) { if (constantValue.isOfPrimitiveType()) {
// Do not inline primitive constants // Do not inline primitive constants
tryParseReferenceToIntConstant(singleArg)?.let { return it } tryParseReferenceToIntConstant(singleArg)?.let { return it }
} }
@@ -1115,7 +1122,7 @@ class ClassFileToSourceStubConverter(
} }
} }
private fun Any?.isOfPrimiviteType(): Boolean = when(this) { private fun Any?.isOfPrimitiveType(): Boolean = when (this) {
is Boolean, is Byte, is Int, is Long, is Short, is Char, is Float, is Double -> true is Boolean, is Byte, is Int, is Long, is Short, is Char, is Float, is Double -> true
else -> false else -> false
} }
@@ -37,9 +37,9 @@ import org.jetbrains.kotlin.types.*
private typealias SubstitutionMap = Map<String, Pair<KtTypeParameter, KtTypeProjection>> private typealias SubstitutionMap = Map<String, Pair<KtTypeParameter, KtTypeProjection>>
class ErrorTypeCorrector( class ErrorTypeCorrector(
private val converter: ClassFileToSourceStubConverter, private val converter: ClassFileToSourceStubConverter,
private val typeKind: TypeKind, private val typeKind: TypeKind,
file: KtFile file: KtFile
) { ) {
private val defaultType = converter.treeMaker.FqName(Object::class.java.name) private val defaultType = converter.treeMaker.FqName(Object::class.java.name)
@@ -54,7 +54,7 @@ class ErrorTypeCorrector(
val importedFqName = importDirective.importedFqName ?: continue val importedFqName = importDirective.importedFqName ?: continue
val importedReference = getReferenceExpression(importDirective.importedReference) val importedReference = getReferenceExpression(importDirective.importedReference)
?.let { bindingContext[BindingContext.REFERENCE_TARGET, it] } ?.let { bindingContext[BindingContext.REFERENCE_TARGET, it] }
if (importedReference is CallableDescriptor) continue if (importedReference is CallableDescriptor) continue
@@ -90,40 +90,47 @@ class ErrorTypeCorrector(
val baseExpression: JCTree.JCExpression val baseExpression: JCTree.JCExpression
if (target is TypeAliasDescriptor) { when (target) {
val typeAlias = target.source.getPsi() as? KtTypeAlias is TypeAliasDescriptor -> {
val actualType = typeAlias?.getTypeReference() ?: return convert(target.expandedType) val typeAlias = target.source.getPsi() as? KtTypeAlias
return convert(actualType, typeAlias.getSubstitutions(type)) val actualType = typeAlias?.getTypeReference() ?: return convert(target.expandedType)
} else if (target is ClassConstructorDescriptor) { return convert(actualType, typeAlias.getSubstitutions(type))
val asmType = converter.kaptContext.generationState.typeMapper
.mapType(target.constructedClass.defaultType, null, TypeMappingMode.GENERIC_ARGUMENT)
baseExpression = converter.treeMaker.Type(asmType)
} else if (target is ClassDescriptor) {
// We only get here if some type were an error type. In other words, 'type' is either an error type or its argument,
// so it's impossible it to be unboxed primitive.
val asmType = converter.kaptContext.generationState.typeMapper.mapType(target.defaultType, null, TypeMappingMode.GENERIC_ARGUMENT)
baseExpression = converter.treeMaker.Type(asmType)
} else {
val referencedName = type.referencedName ?: return defaultType
val qualifier = type.qualifier
if (qualifier == null) {
if (referencedName in substitutions) {
val (typeParameter, projection) = substitutions.getValue(referencedName)
return convertTypeProjection(projection, typeParameter.variance, emptyMap())
}
aliasedImports[referencedName]?.let { return it }
} }
is ClassConstructorDescriptor -> {
val asmType = converter.kaptContext.generationState.typeMapper
.mapType(target.constructedClass.defaultType, null, TypeMappingMode.GENERIC_ARGUMENT)
baseExpression = when { baseExpression = converter.treeMaker.Type(asmType)
qualifier != null -> { }
val qualifierType = convertUserType(qualifier, substitutions) is ClassDescriptor -> {
if (qualifierType === defaultType) return defaultType // Do not allow to use 'defaultType' as a qualifier // We only get here if some type were an error type. In other words, 'type' is either an error type or its argument,
treeMaker.Select(qualifierType, treeMaker.name(referencedName)) // so it's impossible it to be unboxed primitive.
val asmType = converter.kaptContext.generationState.typeMapper
.mapType(target.defaultType, null, TypeMappingMode.GENERIC_ARGUMENT)
baseExpression = converter.treeMaker.Type(asmType)
}
else -> {
val referencedName = type.referencedName ?: return defaultType
val qualifier = type.qualifier
if (qualifier == null) {
if (referencedName in substitutions) {
val (typeParameter, projection) = substitutions.getValue(referencedName)
return convertTypeProjection(projection, typeParameter.variance, emptyMap())
}
aliasedImports[referencedName]?.let { return it }
}
baseExpression = when {
qualifier != null -> {
val qualifierType = convertUserType(qualifier, substitutions)
if (qualifierType === defaultType) return defaultType // Do not allow to use 'defaultType' as a qualifier
treeMaker.Select(qualifierType, treeMaker.name(referencedName))
}
else -> treeMaker.SimpleName(referencedName)
} }
else -> treeMaker.SimpleName(referencedName)
} }
} }
@@ -147,8 +154,7 @@ class ErrorTypeCorrector(
val variance = if (typeArgument != null && typeParameter != null) { val variance = if (typeArgument != null && typeParameter != null) {
KotlinTypeMapper.getVarianceForWildcard(typeParameter, typeArgument, typeMappingMode) KotlinTypeMapper.getVarianceForWildcard(typeParameter, typeArgument, typeMappingMode)
} } else {
else {
null null
} }
@@ -157,9 +163,9 @@ class ErrorTypeCorrector(
} }
private fun convertTypeProjection( private fun convertTypeProjection(
projection: KtTypeProjection, projection: KtTypeProjection,
variance: Variance?, variance: Variance?,
substitutions: SubstitutionMap substitutions: SubstitutionMap
): JCTree.JCExpression { ): JCTree.JCExpression {
fun unbounded() = treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null) fun unbounded() = treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
@@ -183,10 +189,6 @@ class ErrorTypeCorrector(
} }
} }
private fun convertTypeProjection() {
}
private fun convertFunctionType(type: KtFunctionType, substitutions: SubstitutionMap): JCTree.JCExpression { private fun convertFunctionType(type: KtFunctionType, substitutions: SubstitutionMap): JCTree.JCExpression {
val receiverType = type.receiverTypeReference val receiverType = type.receiverTypeReference
var parameterTypes = mapJList(type.parameters) { convert(it.typeReference, substitutions) } var parameterTypes = mapJList(type.parameters) { convert(it.typeReference, substitutions) }
@@ -207,8 +209,8 @@ class ErrorTypeCorrector(
if (typeParameters.size != arguments.size) { if (typeParameters.size != arguments.size) {
val kaptContext = converter.kaptContext val kaptContext = converter.kaptContext
kaptContext.compiler.log.report( val error = kaptContext.kaptError("${typeParameters.size} parameters are expected but ${arguments.size} passed")
kaptContext.kaptError("${typeParameters.size} parameters are expected but ${arguments.size} passed")) kaptContext.compiler.log.report(error)
return emptyMap() return emptyMap()
} }
@@ -87,7 +87,7 @@ class KDocCommentKeeper(private val kaptContext: KaptContextForStubGeneration) {
&& descriptor is PropertyAccessorDescriptor && descriptor is PropertyAccessorDescriptor
&& kaptContext.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, descriptor.correspondingProperty] == true && kaptContext.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, descriptor.correspondingProperty] == true
) { ) {
// Do not place the smae documentation on backing field and property accessors // Do not place documentation on backing field and property accessors
return return
} }
@@ -47,8 +47,8 @@ class KaptLineMappingCollector(private val kaptContext: KaptContextForStubGenera
register(field, clazz.name + "#" + field.name) register(field, clazz.name + "#" + field.name)
} }
fun registerSignature(decl: JCTree.JCMethodDecl, method: MethodNode) { fun registerSignature(declaration: JCTree.JCMethodDecl, method: MethodNode) {
signatureInfo[decl.getJavacSignature()] = method.name + method.desc signatureInfo[declaration.getJavacSignature()] = method.name + method.desc
} }
private fun register(asmNode: Any, fqName: String) { private fun register(asmNode: Any, fqName: String) {
@@ -92,24 +92,24 @@ private class SignatureNode(val kind: ElementKind, val name: String? = null) {
val children: MutableList<SignatureNode> = SmartList<SignatureNode>() val children: MutableList<SignatureNode> = SmartList<SignatureNode>()
} }
class SignatureParser(val treeMaker: KaptTreeMaker) { class SignatureParser(private val treeMaker: KaptTreeMaker) {
class ClassGenericSignature( class ClassGenericSignature(
val typeParameters: JavacList<JCTypeParameter>, val typeParameters: JavacList<JCTypeParameter>,
val superClass: JCExpression, val superClass: JCExpression,
val interfaces: JavacList<JCExpression> val interfaces: JavacList<JCExpression>
) )
class MethodGenericSignature( class MethodGenericSignature(
val typeParameters: JavacList<JCTypeParameter>, val typeParameters: JavacList<JCTypeParameter>,
val parameterTypes: JavacList<JCVariableDecl>, val parameterTypes: JavacList<JCVariableDecl>,
val exceptionTypes: JavacList<JCExpression>, val exceptionTypes: JavacList<JCExpression>,
val returnType: JCExpression? val returnType: JCExpression?
) )
fun parseClassSignature( fun parseClassSignature(
signature: String?, signature: String?,
rawSuperClass: JCExpression, rawSuperClass: JCExpression,
rawInterfaces: JavacList<JCExpression> rawInterfaces: JavacList<JCExpression>
): ClassGenericSignature { ): ClassGenericSignature {
if (signature == null) { if (signature == null) {
return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces) return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces)
@@ -128,11 +128,11 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
} }
fun parseMethodSignature( fun parseMethodSignature(
signature: String?, signature: String?,
rawParameters: JavacList<JCVariableDecl>, rawParameters: JavacList<JCVariableDecl>,
rawExceptionTypes: JavacList<JCExpression>, rawExceptionTypes: JavacList<JCExpression>,
rawReturnType: JCExpression?, rawReturnType: JCExpression?,
nonErrorParameterTypeProvider: (Int, () -> JCExpression) -> JCExpression nonErrorParameterTypeProvider: (Int, () -> JCExpression) -> JCExpression
): MethodGenericSignature { ): MethodGenericSignature {
if (signature == null) { if (signature == null) {
val parameters = mapJListIndexed(rawParameters) { index, it -> val parameters = mapJListIndexed(rawParameters) { index, it ->
@@ -164,8 +164,8 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
} }
fun parseFieldSignature( fun parseFieldSignature(
signature: String?, signature: String?,
rawType: JCExpression rawType: JCExpression
): JCExpression { ): JCExpression {
if (signature == null) return rawType if (signature == null) return rawType
@@ -208,8 +208,9 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
for (innerClass in innerClasses) { for (innerClass in innerClasses) {
expression = makeExpressionForClassTypeWithArguments( expression = makeExpressionForClassTypeWithArguments(
treeMaker.Select(expression, treeMaker.name(innerClass.name!!)), treeMaker.Select(expression, treeMaker.name(innerClass.name!!)),
innerClass.children) innerClass.children
)
} }
expression expression
@@ -273,12 +274,12 @@ private fun SignatureNode.split(l1: MutableList<SignatureNode>, e1: ElementKind,
} }
private fun SignatureNode.split( private fun SignatureNode.split(
l1: MutableList<SignatureNode>, l1: MutableList<SignatureNode>,
e1: ElementKind, e1: ElementKind,
l2: MutableList<SignatureNode>, l2: MutableList<SignatureNode>,
e2: ElementKind, e2: ElementKind,
l3: MutableList<SignatureNode>, l3: MutableList<SignatureNode>,
e3: ElementKind e3: ElementKind
) { ) {
for (child in children) { for (child in children) {
val kind = child.kind val kind = child.kind
@@ -292,14 +293,14 @@ private fun SignatureNode.split(
} }
private fun SignatureNode.split( private fun SignatureNode.split(
l1: MutableList<SignatureNode>, l1: MutableList<SignatureNode>,
e1: ElementKind, e1: ElementKind,
l2: MutableList<SignatureNode>, l2: MutableList<SignatureNode>,
e2: ElementKind, e2: ElementKind,
l3: MutableList<SignatureNode>, l3: MutableList<SignatureNode>,
e3: ElementKind, e3: ElementKind,
l4: MutableList<SignatureNode>, l4: MutableList<SignatureNode>,
e4: ElementKind e4: ElementKind
) { ) {
for (child in children) { for (child in children) {
val kind = child.kind val kind = child.kind
@@ -27,11 +27,12 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.* import java.util.*
internal class ParameterInfo( internal class ParameterInfo(
val flags: Long, val flags: Long,
val name: String, val name: String,
val type: Type, val type: Type,
val visibleAnnotations: List<AnnotationNode>?, val visibleAnnotations: List<AnnotationNode>?,
val invisibleAnnotations: List<AnnotationNode>?) val invisibleAnnotations: List<AnnotationNode>?
)
internal fun MethodNode.getParametersInfo(containingClass: ClassNode): List<ParameterInfo> { internal fun MethodNode.getParametersInfo(containingClass: ClassNode): List<ParameterInfo> {
val localVariables = this.localVariables ?: emptyList() val localVariables = this.localVariables ?: emptyList()
@@ -63,7 +64,7 @@ internal fun MethodNode.getParametersInfo(containingClass: ClassNode): List<Para
// @JvmOverloads constructors and ordinary methods don't have "this" local variable // @JvmOverloads constructors and ordinary methods don't have "this" local variable
name = name ?: localVariables.getOrNull(index + localVariableIndexOffset)?.name name = name ?: localVariables.getOrNull(index + localVariableIndexOffset)?.name
?: "p${index - startParameterIndex}" ?: "p${index - startParameterIndex}"
// Property setters has bad parameter names // Property setters has bad parameter names
if (name.startsWith("<") && name.endsWith(">")) { if (name.startsWith("<") && name.endsWith(">")) {
@@ -20,7 +20,7 @@ class MessageCollectorBackedKaptLogger(
val messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose) val messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose)
) : KaptLogger { ) : KaptLogger {
private companion object { private companion object {
val PREFIX = "[kapt] " const val PREFIX = "[kapt] "
} }
override val errorWriter = makeWriter(ERROR) override val errorWriter = makeWriter(ERROR)
@@ -21,7 +21,10 @@ import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import java.io.Writer import java.io.Writer
class MessageCollectorBackedWriter(val messageCollector: MessageCollector, val severity: CompilerMessageSeverity) : Writer() { class MessageCollectorBackedWriter(
private val messageCollector: MessageCollector,
private val severity: CompilerMessageSeverity
) : Writer() {
override fun write(buffer: CharArray, offset: Int, length: Int) { override fun write(buffer: CharArray, offset: Int, length: Int) {
val message = String(buffer, offset, length).trim().trim('\n', '\r') val message = String(buffer, offset, length).trim().trim('\n', '\r')
if (message.isNotEmpty()) { if (message.isNotEmpty()) {
@@ -26,7 +26,6 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
internal fun isEnum(access: Int) = (access and Opcodes.ACC_ENUM) != 0 internal fun isEnum(access: Int) = (access and Opcodes.ACC_ENUM) != 0
internal fun isPublic(access: Int) = (access and Opcodes.ACC_PUBLIC) != 0 internal fun isPublic(access: Int) = (access and Opcodes.ACC_PUBLIC) != 0
internal fun isSynthetic(access: Int) = (access and Opcodes.ACC_SYNTHETIC) != 0 internal fun isSynthetic(access: Int) = (access and Opcodes.ACC_SYNTHETIC) != 0
internal fun isPrivate(access: Int) = (access and Opcodes.ACC_PRIVATE) != 0
internal fun isFinal(access: Int) = (access and Opcodes.ACC_FINAL) != 0 internal fun isFinal(access: Int) = (access and Opcodes.ACC_FINAL) != 0
internal fun isStatic(access: Int) = (access and Opcodes.ACC_STATIC) != 0 internal fun isStatic(access: Int) = (access and Opcodes.ACC_STATIC) != 0
internal fun isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) != 0 internal fun isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) != 0
@@ -40,13 +39,13 @@ internal fun <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
internal fun MethodNode.isJvmOverloadsGenerated(): Boolean { internal fun MethodNode.isJvmOverloadsGenerated(): Boolean {
return (invisibleAnnotations?.any { it.isJvmOverloadsGenerated() } ?: false) return (invisibleAnnotations?.any { it.isJvmOverloadsGenerated() } ?: false)
|| (visibleAnnotations?.any { it.isJvmOverloadsGenerated() } ?: false) || (visibleAnnotations?.any { it.isJvmOverloadsGenerated() } ?: false)
} }
// Constant from DefaultParameterValueSubstitutor can't be used in Maven build because of ProGuard // Constant from DefaultParameterValueSubstitutor can't be used in Maven build because of ProGuard
// rename this as well // rename this as well
private val ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS: String = private val ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS: String =
Type.getObjectType("synthetic/kotlin/jvm/GeneratedByJvmOverloads").descriptor Type.getObjectType("synthetic/kotlin/jvm/GeneratedByJvmOverloads").descriptor
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
@@ -68,22 +68,22 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
} }
protected open fun test( protected open fun test(
name: String, name: String,
vararg supportedAnnotations: String, vararg supportedAnnotations: String,
options: Map<String, String> = emptyMap(), options: Map<String, String> = emptyMap(),
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit
) = testAP(true, name, options, process, *supportedAnnotations) ) = testAP(true, name, options, process, *supportedAnnotations)
protected fun testAP( private fun testAP(
shouldRun: Boolean, shouldRun: Boolean,
name: String, name: String,
options: Map<String, String>, options: Map<String, String>,
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit, process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit,
vararg supportedAnnotations: String vararg supportedAnnotations: String
) { ) {
this._options = options this._options = options
val ktFileName = File(TEST_DATA_DIR, name + ".kt") val ktFileName = File(TEST_DATA_DIR, "$name.kt")
var started = false var started = false
val processor = object : Processor { val processor = object : Processor {
lateinit var processingEnv: ProcessingEnvironment lateinit var processingEnv: ProcessingEnvironment
@@ -103,10 +103,10 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
} }
override fun getCompletions( override fun getCompletions(
element: Element?, element: Element?,
annotation: AnnotationMirror?, annotation: AnnotationMirror?,
member: ExecutableElement?, member: ExecutableElement?,
userText: String? userText: String?
): Iterable<Completion>? { ): Iterable<Completion>? {
return emptyList() return emptyList()
} }
@@ -134,8 +134,10 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources) createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
val project = myEnvironment.project val project = myEnvironment.project
val kapt3Extension = Kapt3ExtensionForTests(project, processors, javaSources.toList(), sourceOutputDir, this.options, val kapt3Extension = Kapt3ExtensionForTests(
stubsOutputDir = stubsDir, incrementalDataOutputDir = incrementalDataDir) project, processors, javaSources.toList(), sourceOutputDir, this.options,
stubsOutputDir = stubsDir, incrementalDataOutputDir = incrementalDataDir
)
AnalysisHandlerExtension.registerExtension(project, kapt3Extension) AnalysisHandlerExtension.registerExtension(project, kapt3Extension)
@@ -146,9 +148,9 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, classBuilderFactory).factory GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, classBuilderFactory).factory
val actualRaw = kapt3Extension.savedStubs ?: error("Stubs were not saved") val actualRaw = kapt3Extension.savedStubs ?: error("Stubs were not saved")
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })) val actual = StringUtil.convertLineSeparators(actualRaw.trim { it <= ' ' })
.trimTrailingWhitespacesAndAddNewlineAtEOF() .trimTrailingWhitespacesAndAddNewlineAtEOF()
.let { AbstractClassFileToSourceStubConverterTest.removeMetadataAnnotationContents(it) } .let { AbstractClassFileToSourceStubConverterTest.removeMetadataAnnotationContents(it) }
KotlinTestUtils.assertEqualsToFile(txtFile, actual) KotlinTestUtils.assertEqualsToFile(txtFile, actual)
} finally { } finally {
@@ -158,13 +160,13 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
} }
protected class Kapt3ExtensionForTests( protected class Kapt3ExtensionForTests(
project: Project, project: Project,
private val processors: List<Processor>, private val processors: List<Processor>,
javaSourceRoots: List<File>, javaSourceRoots: List<File>,
outputDir: File, outputDir: File,
options: Map<String, String>, options: Map<String, String>,
stubsOutputDir: File, stubsOutputDir: File,
incrementalDataOutputDir: File incrementalDataOutputDir: File
) : AbstractKapt3Extension( ) : AbstractKapt3Extension(
KaptPaths( KaptPaths(
project.basePath?.let(::File), project.basePath?.let(::File),
@@ -186,17 +188,17 @@ abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
} }
this.savedStubs = stubs this.savedStubs = stubs
.map { it.file.prettyPrint(kaptContext.context) } .map { it.file.prettyPrint(kaptContext.context) }
.sorted() .sorted()
.joinToString(AbstractKotlinKapt3Test.FILE_SEPARATOR) .joinToString(AbstractKotlinKapt3Test.FILE_SEPARATOR)
super.saveStubs(kaptContext, stubs) super.saveStubs(kaptContext, stubs)
} }
override fun saveIncrementalData( override fun saveIncrementalData(
kaptContext: KaptContextForStubGeneration, kaptContext: KaptContextForStubGeneration,
messageCollector: MessageCollector, messageCollector: MessageCollector,
converter: ClassFileToSourceStubConverter converter: ClassFileToSourceStubConverter
) { ) {
if (this.savedBindings != null) { if (this.savedBindings != null) {
error("Bindings are already saved") error("Bindings are already saved")
@@ -208,7 +208,7 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
lines.filter { it.startsWith("// $name") }.toList() lines.filter { it.startsWith("// $name") }.toList()
} }
protected fun File.getOptionValues(name: String) = getRawOptionValues(name).map { it.drop("// ".length + name.length).trim() } private fun File.getOptionValues(name: String) = getRawOptionValues(name).map { it.drop("// ".length + name.length).trim() }
protected abstract fun check( protected abstract fun check(
kaptContext: KaptContextForStubGeneration, kaptContext: KaptContextForStubGeneration,
@@ -31,15 +31,17 @@ import javax.lang.model.element.TypeElement
class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9TestLauncher { class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9TestLauncher {
override fun test( override fun test(
name: String, name: String,
vararg supportedAnnotations: String, vararg supportedAnnotations: String,
options: Map<String, String>, options: Map<String, String>,
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit
) { ) {
super.test(name, *supportedAnnotations, options = options, process = process) super.test(name, *supportedAnnotations, options = options, process = process)
doTestWithJdk9(SingleJUnitTestRunner::class.java, doTestWithJdk9(
KotlinKapt3IntegrationTests::class.java.name + "#test" + getTestName(false)) SingleJUnitTestRunner::class.java,
KotlinKapt3IntegrationTests::class.java.name + "#test" + getTestName(false)
)
} }
@Test @Test
@@ -51,7 +53,7 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
} }
@Test @Test
fun testComments() = test("Simple", "test.MyAnnotation") { set, roundEnv, env -> fun testComments() = test("Simple", "test.MyAnnotation") { _, _, env ->
fun commentOf(className: String) = env.elementUtils.getDocComment(env.elementUtils.getTypeElement(className)) fun commentOf(className: String) = env.elementUtils.getDocComment(env.elementUtils.getTypeElement(className))
assert(commentOf("test.Simple") == " * KDoc comment.\n") assert(commentOf("test.Simple") == " * KDoc comment.\n")
@@ -73,19 +75,21 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
} }
@Test @Test
fun testStubsAndIncrementalDataForNestedClasses() = bindingsTest("NestedClasses") { stubsOutputDir, incrementalDataOutputDir, bindings -> fun testStubsAndIncrementalDataForNestedClasses() {
assert(File(stubsOutputDir, "test/Simple.java").exists()) bindingsTest("NestedClasses") { stubsOutputDir, incrementalDataOutputDir, bindings ->
assert(!File(stubsOutputDir, "test/Simple/InnerClass.java").exists()) assert(File(stubsOutputDir, "test/Simple.java").exists())
assert(!File(stubsOutputDir, "test/Simple/InnerClass.java").exists())
assert(File(incrementalDataOutputDir, "test/Simple.class").exists()) assert(File(incrementalDataOutputDir, "test/Simple.class").exists())
assert(File(incrementalDataOutputDir, "test/Simple\$Companion.class").exists()) assert(File(incrementalDataOutputDir, "test/Simple\$Companion.class").exists())
assert(File(incrementalDataOutputDir, "test/Simple\$InnerClass.class").exists()) assert(File(incrementalDataOutputDir, "test/Simple\$InnerClass.class").exists())
assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass.class").exists()) assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass.class").exists())
assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass\$NestedNestedClass.class").exists()) assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass\$NestedNestedClass.class").exists())
assert(bindings.any { it.key == "test/Simple" && it.value.name == "test/Simple.java" }) assert(bindings.any { it.key == "test/Simple" && it.value.name == "test/Simple.java" })
assert(bindings.none { it.key.contains("Companion") }) assert(bindings.none { it.key.contains("Companion") })
assert(bindings.none { it.key.contains("InnerClass") }) assert(bindings.none { it.key.contains("InnerClass") })
}
} }
private fun bindingsTest(name: String, test: (File, File, Map<String, KaptJavaFileObject>) -> Unit) { private fun bindingsTest(name: String, test: (File, File, Map<String, KaptJavaFileObject>) -> Unit) {
@@ -103,8 +107,8 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
@Test @Test
fun testOptions() = test( fun testOptions() = test(
"Simple", "test.MyAnnotation", "Simple", "test.MyAnnotation",
options = mapOf("firstKey" to "firstValue", "secondKey" to "") options = mapOf("firstKey" to "firstValue", "secondKey" to "")
) { _, _, env -> ) { _, _, env ->
val options = env.options val options = env.options
assertEquals("firstValue", options["firstKey"]) assertEquals("firstValue", options["firstKey"])
@@ -117,11 +121,11 @@ class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9T
val annotatedElements = roundEnv.getElementsAnnotatedWith(set.single()) val annotatedElements = roundEnv.getElementsAnnotatedWith(set.single())
assertEquals(1, annotatedElements.size) assertEquals(1, annotatedElements.size)
val constructors = annotatedElements val constructors = annotatedElements
.first() .first()
.enclosedElements .enclosedElements
.filter { it.kind == ElementKind.CONSTRUCTOR } .filter { it.kind == ElementKind.CONSTRUCTOR }
.map { it as ExecutableElement } .map { it as ExecutableElement }
.sortedBy { it.parameters.size } .sortedBy { it.parameters.size }
assertEquals(2, constructors.size) assertEquals(2, constructors.size)
assertEquals(2, constructors[0].parameters.size) assertEquals(2, constructors[0].parameters.size)
assertEquals(3, constructors[1].parameters.size) assertEquals(3, constructors[1].parameters.size)