Kapt: Add runtime library, move all modules inside the 'kapt3' directory

This commit is contained in:
Yan Zhulanow
2017-11-02 11:15:15 +09:00
parent b74ef72af7
commit fd84ecda54
140 changed files with 110 additions and 58 deletions
@@ -0,0 +1,44 @@
description = "Annotation Processor for Kotlin"
apply { plugin("kotlin") }
dependencies {
compile(project(":compiler:util"))
compile(project(":compiler:cli"))
compile(project(":compiler:backend"))
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:plugin-api"))
testCompile(project(":compiler:tests-common"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(ideaSdkDeps("idea", "idea_rt", "openapi"))
testCompile(commonDep("junit:junit"))
compileOnly(project(":kotlin-annotation-processing-runtime"))
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
runtimeJar {
from(getSourceSetsFrom(":kotlin-annotation-processing-runtime")["main"].output.classesDirs)
}
testsJar {}
projectTest {
workingDir = rootDir
dependsOnTaskIfExistsRec("dist", project = rootProject)
}
runtimeJar()
sourcesJar()
javadocJar()
dist()
publish()
@@ -0,0 +1 @@
org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor
@@ -0,0 +1 @@
org.jetbrains.kotlin.kapt3.Kapt3ComponentRegistrar
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.tree.*
internal class Kapt3BuilderFactory : ClassBuilderFactory {
internal val compiledClasses = mutableListOf<ClassNode>()
internal val origins = mutableMapOf<Any, JvmDeclarationOrigin>()
override fun getClassBuilderMode(): ClassBuilderMode = ClassBuilderMode.KAPT3
override fun newClassBuilder(origin: JvmDeclarationOrigin): AbstractClassBuilder.Concrete {
val classNode = ClassNode()
compiledClasses += classNode
origins.put(classNode, origin)
return Kapt3ClassBuilder(classNode)
}
private inner class Kapt3ClassBuilder(val classNode: ClassNode) : AbstractClassBuilder.Concrete(classNode) {
override fun newField(
origin: JvmDeclarationOrigin,
access: Int,
name: String,
desc: String,
signature: String?,
value: Any?
): FieldVisitor {
val fieldNode = super.newField(origin, access, name, desc, signature, value) as FieldNode
origins.put(fieldNode, origin)
return fieldNode
}
override fun newMethod(
origin: JvmDeclarationOrigin,
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
val methodNode = super.newMethod(origin, access, name, desc, signature, exceptions) as MethodNode
origins.put(methodNode, origin)
// ASM doesn't read information about local variables for the `abstract` methods so we need to get it manually
if ((access and Opcodes.ACC_ABSTRACT) != 0 && methodNode.localVariables == null) {
methodNode.localVariables = mutableListOf<LocalVariableNode>()
}
return methodNode
}
}
override fun asBytes(builder: ClassBuilder): ByteArray {
val classWriter = ClassWriter(0)
(builder as Kapt3ClassBuilder).classNode.accept(classWriter)
return classWriter.toByteArray()
}
override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException()
override fun close() {}
}
@@ -0,0 +1,312 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3
import com.intellij.openapi.project.Project
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.kapt3.AptMode.*
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
import java.io.File
import java.net.URLClassLoader
import java.util.*
import javax.annotation.processing.Processor
import com.sun.tools.javac.util.List as JavacList
class ClasspathBasedKapt3Extension(
compileClasspath: List<File>,
annotationProcessingClasspath: List<File>,
javaSourceRoots: List<File>,
sourcesOutputDir: File,
classFilesOutputDir: File,
stubsOutputDir: File,
incrementalDataOutputDir: File?,
options: Map<String, String>,
javacOptions: Map<String, String>,
annotationProcessors: String,
aptMode: AptMode,
val useLightAnalysis: Boolean,
correctErrorTypes: Boolean,
pluginInitializedTime: Long,
logger: KaptLogger,
compilerConfiguration: CompilerConfiguration
) : AbstractKapt3Extension(compileClasspath, annotationProcessingClasspath, javaSourceRoots, sourcesOutputDir,
classFilesOutputDir, stubsOutputDir, incrementalDataOutputDir, options, javacOptions, annotationProcessors,
aptMode, pluginInitializedTime, logger, correctErrorTypes, compilerConfiguration) {
override val analyzePartially: Boolean
get() = useLightAnalysis
private var annotationProcessingClassLoader: URLClassLoader? = null
override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
bindingTrace: BindingTrace,
files: Collection<KtFile>
): AnalysisResult? {
try {
return super.analysisCompleted(project, module, bindingTrace, files)
} finally {
annotationProcessingClassLoader?.close()
}
}
override fun loadProcessors(): List<Processor> {
val classpath = annotationProcessingClasspath + compileClasspath
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray())
this.annotationProcessingClassLoader = classLoader
val processors = ServiceLoader.load(Processor::class.java, classLoader).toList()
if (processors.isEmpty()) {
logger.info("No annotation processors available, aborting")
} else {
logger.info { "Annotation processors: " + processors.joinToString { it::class.java.canonicalName } }
}
return processors
}
}
abstract class AbstractKapt3Extension(
compileClasspath: List<File>,
annotationProcessingClasspath: List<File>,
val javaSourceRoots: List<File>,
val sourcesOutputDir: File,
val classFilesOutputDir: File,
val stubsOutputDir: File,
val incrementalDataOutputDir: File?,
val options: Map<String, String>,
val javacOptions: Map<String, String>,
val annotationProcessors: String,
val aptMode: AptMode,
val pluginInitializedTime: Long,
val logger: KaptLogger,
val correctErrorTypes: Boolean,
val compilerConfiguration: CompilerConfiguration
) : PartialAnalysisHandlerExtension() {
val compileClasspath = compileClasspath.distinct()
val annotationProcessingClasspath = annotationProcessingClasspath.distinct()
private var annotationProcessingComplete = false
private fun setAnnotationProcessingComplete(): Boolean {
if (annotationProcessingComplete) return true
annotationProcessingComplete = true
return false
}
override fun doAnalysis(
project: Project,
module: ModuleDescriptor,
projectContext: ProjectContext,
files: Collection<KtFile>,
bindingTrace: BindingTrace,
componentProvider: ComponentProvider
): AnalysisResult? {
if (aptMode == APT_ONLY) {
return AnalysisResult.EMPTY
}
return super.doAnalysis(project, module, projectContext, files, bindingTrace, componentProvider)
}
override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
bindingTrace: BindingTrace,
files: Collection<KtFile>
): AnalysisResult? {
if (setAnnotationProcessingComplete()) return null
fun doNotGenerateCode() = AnalysisResult.Companion.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
logger.info { "Initial analysis took ${System.currentTimeMillis() - pluginInitializedTime} ms" }
val processors = loadProcessors()
if (processors.isEmpty()) return if (aptMode != WITH_COMPILATION) doNotGenerateCode() else null
val kaptContext = generateStubs(project, module, bindingTrace.bindingContext, files)
try {
runAnnotationProcessing(kaptContext, processors)
} catch (error: KaptError) {
val originalException = error.cause ?: error
return AnalysisResult.error(bindingTrace.bindingContext, originalException)
} catch (thr: Throwable) {
return AnalysisResult.error(bindingTrace.bindingContext, thr)
} finally {
kaptContext.close()
}
return if (aptMode != WITH_COMPILATION) {
doNotGenerateCode()
} else {
AnalysisResult.RetryWithAdditionalJavaRoots(
bindingTrace.bindingContext,
module,
listOf(sourcesOutputDir),
addToEnvironment = true)
}
}
private fun generateStubs(project: Project, module: ModuleDescriptor, context: BindingContext, files: Collection<KtFile>): KaptContext<*> {
if (!aptMode.generateStubs) {
return KaptContext(logger, project, BindingContext.EMPTY, emptyList(), emptyMap(), null, options, javacOptions)
}
logger.info { "Kotlin files to compile: " + files.map { it.virtualFile?.name ?: "<in memory ${it.hashCode()}>" } }
return compileStubs(project, module, context, files.toList()).apply {
generateKotlinSourceStubs(this)
}
}
private fun runAnnotationProcessing(kaptContext: KaptContext<*>, processors: List<Processor>) {
if (!aptMode.runAnnotationProcessing) return
val javaSourceFiles = collectJavaSourceFiles()
val (annotationProcessingTime) = measureTimeMillis {
kaptContext.doAnnotationProcessing(
javaSourceFiles, processors, compileClasspath, annotationProcessingClasspath,
annotationProcessors, sourcesOutputDir, classFilesOutputDir)
}
logger.info { "Annotation processing took $annotationProcessingTime ms" }
}
private fun compileStubs(
project: Project,
module: ModuleDescriptor,
bindingContext: BindingContext,
files: List<KtFile>
): KaptContext<GenerationState> {
val builderFactory = Kapt3BuilderFactory()
val targetId = TargetId(
name = compilerConfiguration[CommonConfigurationKeys.MODULE_NAME] ?: module.name.asString(),
type = "java-production")
val generationState = GenerationState.Builder(
project,
builderFactory,
module,
bindingContext,
files,
compilerConfiguration
).targetId(targetId).build()
val (classFilesCompilationTime) = measureTimeMillis {
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
}
val compiledClasses = builderFactory.compiledClasses
val origins = builderFactory.origins
logger.info { "Stubs compilation took $classFilesCompilationTime ms" }
logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } }
return KaptContext(logger, project, bindingContext, compiledClasses, origins, generationState, options, javacOptions)
}
private fun generateKotlinSourceStubs(kaptContext: KaptContext<GenerationState>) {
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass = true, correctErrorTypes = correctErrorTypes)
val (stubGenerationTime, kotlinSourceStubs) = measureTimeMillis {
converter.convert()
}
logger.info { "Java stub generation took $stubGenerationTime ms" }
logger.info { "Stubs for Kotlin classes: " + kotlinSourceStubs.joinToString { it.sourcefile.name } }
saveStubs(kotlinSourceStubs)
saveIncrementalData(kaptContext, logger.messageCollector, converter)
}
private fun collectJavaSourceFiles(): List<File> {
val javaFilesFromJavaSourceRoots = (javaSourceRoots + stubsOutputDir).flatMap {
root -> root.walk().filter { it.isFile && it.extension == "java" }.toList()
}
logger.info { "Java source files: " + javaFilesFromJavaSourceRoots.joinToString { it.canonicalPath } }
return javaFilesFromJavaSourceRoots
}
protected open fun saveStubs(stubs: JavacList<JCTree.JCCompilationUnit>) {
for (stub in stubs) {
val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString()
val packageName = stub.getPackageNameJava9Aware()?.toString() ?: ""
val packageDir = if (packageName.isEmpty()) stubsOutputDir else File(stubsOutputDir, packageName.replace('.', '/'))
packageDir.mkdirs()
File(packageDir, className + ".java").writeText(stub.toString())
}
}
protected open fun saveIncrementalData(
kaptContext: KaptContext<GenerationState>,
messageCollector: MessageCollector,
converter: ClassFileToSourceStubConverter) {
val incrementalDataOutputDir = this.incrementalDataOutputDir ?: return
val reportOutputFiles = kaptContext.generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
kaptContext.generationState.factory.writeAll(
incrementalDataOutputDir,
if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) {
val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")]
if (stubFileObject != null) {
val stubFile = File(stubsOutputDir, stubFileObject.name)
if (stubFile.exists()) {
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, stubFile))
}
}
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
}
)
}
protected abstract fun loadProcessors(): List<Processor>
}
private inline fun <T> measureTimeMillis(block: () -> T) : Pair<Long, T> {
val start = System.currentTimeMillis()
val result = block()
return Pair(System.currentTimeMillis() - start, result)
}
@@ -0,0 +1,322 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3
import com.intellij.mock.MockProject
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.APT_OPTIONS
import org.jetbrains.kotlin.kapt3.Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.compiler.plugin.CliOption
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.utils.decodePluginOptions
import java.io.ByteArrayInputStream
import java.io.File
import java.io.ObjectInputStream
import java.util.*
object Kapt3ConfigurationKeys {
val SOURCE_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("source files output directory")
val CLASS_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("class files output directory")
val STUBS_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("stubs output directory")
val INCREMENTAL_DATA_OUTPUT_DIR: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("incremental data output directory")
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
val APT_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processing options")
val JAVAC_CLI_OPTIONS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("javac CLI options")
val ANNOTATION_PROCESSORS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processor qualified names")
val VERBOSE_MODE: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("verbose mode")
@Deprecated("Use APT_MODE instead.")
val APT_ONLY: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("do only annotation processing")
val APT_MODE: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("annotation processing mode")
val USE_LIGHT_ANALYSIS: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("do not analyze declaration bodies if can")
val CORRECT_ERROR_TYPES: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("replace error types with ones from the declaration sources")
}
class Kapt3CommandLineProcessor : CommandLineProcessor {
companion object {
val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt3"
val CONFIGURATION = CliOption("configuration", "<encoded>", "Encoded configuration", required = false)
val SOURCE_OUTPUT_DIR_OPTION: CliOption =
CliOption("sources", "<path>", "Output path for the generated files", required = false)
val CLASS_OUTPUT_DIR_OPTION: CliOption =
CliOption("classes", "<path>", "Output path for the class files", required = false)
val STUBS_OUTPUT_DIR_OPTION: CliOption =
CliOption("stubs", "<path>", "Output path for the Java stubs", required = false)
val INCREMENTAL_DATA_OUTPUT_DIR_OPTION: CliOption =
CliOption("incrementalData", "<path>", "Output path for the incremental data", required = false)
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
required = false, allowMultipleOccurrences = true)
val APT_OPTIONS_OPTION: CliOption =
CliOption("apoptions", "options map", "Encoded annotation processor options",
required = false, allowMultipleOccurrences = false)
val JAVAC_CLI_OPTIONS_OPTION: CliOption =
CliOption("javacArguments", "javac CLI options map", "Encoded javac CLI options",
required = false, allowMultipleOccurrences = false)
val ANNOTATION_PROCESSORS_OPTION: CliOption =
CliOption("processors", "<fqname,[fqname2,...]>", "Annotation processor qualified names",
required = false, allowMultipleOccurrences = true)
val VERBOSE_MODE_OPTION: CliOption =
CliOption("verbose", "true | false", "Enable verbose output", required = false)
@Deprecated("Use APT_MODE_OPTION instead.")
val APT_ONLY_OPTION: CliOption =
CliOption("aptOnly", "true | false", "Run only annotation processing, do not compile Kotlin files", required = false)
val APT_MODE_OPTION: CliOption =
CliOption("aptMode", "apt | stubs | stubsAndApt | compile",
"Annotation processing mode: only apt, only stub generation, both, or with the subsequent compilation",
required = false)
val USE_LIGHT_ANALYSIS_OPTION: CliOption =
CliOption("useLightAnalysis", "true | false", "Do not analyze declaration bodies if can", required = false)
val CORRECT_ERROR_TYPES_OPTION: CliOption =
CliOption("correctErrorTypes", "true | false", "Replace generated or error types with ones from the generated sources", required = false)
}
override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> =
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,
USE_LIGHT_ANALYSIS_OPTION, CORRECT_ERROR_TYPES_OPTION, ANNOTATION_PROCESSORS_OPTION, INCREMENTAL_DATA_OUTPUT_DIR_OPTION,
CONFIGURATION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> configuration.appendList(ANNOTATION_PROCESSOR_CLASSPATH, value)
ANNOTATION_PROCESSORS_OPTION -> configuration.put(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS, value)
APT_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_OPTIONS, value)
JAVAC_CLI_OPTIONS_OPTION -> configuration.put(Kapt3ConfigurationKeys.JAVAC_CLI_OPTIONS, value)
SOURCE_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR, value)
CLASS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR, value)
STUBS_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR, value)
INCREMENTAL_DATA_OUTPUT_DIR_OPTION -> configuration.put(Kapt3ConfigurationKeys.INCREMENTAL_DATA_OUTPUT_DIR, value)
VERBOSE_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.VERBOSE_MODE, value)
APT_ONLY_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_ONLY, value)
APT_MODE_OPTION -> configuration.put(Kapt3ConfigurationKeys.APT_MODE, value)
USE_LIGHT_ANALYSIS_OPTION -> configuration.put(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS, value)
CORRECT_ERROR_TYPES_OPTION -> configuration.put(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES, value)
CONFIGURATION -> configuration.applyOptionsFrom(decodePluginOptions(value), pluginOptions)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
}
class Kapt3ComponentRegistrar : ComponentRegistrar {
private companion object {
private const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context"
}
private fun decodeList(options: String): Map<String, String> {
val map = LinkedHashMap<String, String>()
val decodedBytes = Base64.getDecoder().decode(options)
val bis = ByteArrayInputStream(decodedBytes)
val ois = ObjectInputStream(bis)
val n = ois.readInt()
repeat(n) {
val k = ois.readUTF()
val v = ois.readUTF()
map[k] = v
}
return map
}
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val aptMode = AptMode.parse(configuration.get(Kapt3ConfigurationKeys.APT_MODE) ?:
configuration.get(Kapt3ConfigurationKeys.APT_ONLY))
val isVerbose = configuration.get(Kapt3ConfigurationKeys.VERBOSE_MODE) == "true"
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
?: PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose)
val logger = KaptLogger(isVerbose, messageCollector)
try {
Class.forName(JAVAC_CONTEXT_CLASS)
} catch (e: ClassNotFoundException) {
logger.warn("'$JAVAC_CONTEXT_CLASS' class can't be found ('tools.jar' is absent in the plugin classpath). Kapt won't work.")
return
}
val sourcesOutputDir = configuration.get(Kapt3ConfigurationKeys.SOURCE_OUTPUT_DIR)?.let(::File)
val classFilesOutputDir = configuration.get(Kapt3ConfigurationKeys.CLASS_OUTPUT_DIR)?.let(::File)
val stubsOutputDir = configuration.get(Kapt3ConfigurationKeys.STUBS_OUTPUT_DIR)?.let(::File)
val incrementalDataOutputDir = configuration.get(Kapt3ConfigurationKeys.INCREMENTAL_DATA_OUTPUT_DIR)?.let(::File)
val annotationProcessors = configuration.get(Kapt3ConfigurationKeys.ANNOTATION_PROCESSORS) ?: ""
val apClasspath = configuration.get(ANNOTATION_PROCESSOR_CLASSPATH)?.map(::File)
if (sourcesOutputDir == null || classFilesOutputDir == null || apClasspath == null || stubsOutputDir == null) {
if (aptMode != AptMode.WITH_COMPILATION) {
val nonExistentOptionName = when {
sourcesOutputDir == null -> "Sources output directory"
classFilesOutputDir == null -> "Classes output directory"
apClasspath == null -> "Annotation processing classpath"
stubsOutputDir == null -> "Stubs output directory"
else -> throw IllegalStateException()
}
val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME)
?: configuration.get(JVMConfigurationKeys.MODULES).orEmpty().joinToString()
logger.warn("$nonExistentOptionName is not specified for $moduleName, skipping annotation processing")
AnalysisHandlerExtension.registerExtension(project, AbortAnalysisHandlerExtension())
}
return
}
val apOptions = configuration.get(APT_OPTIONS)?.let { decodeList(it) } ?: emptyMap()
val javacCliOptions = configuration.get(JAVAC_CLI_OPTIONS)?.let { decodeList(it) } ?: emptyMap()
sourcesOutputDir.mkdirs()
val contentRoots = configuration[JVMConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
val compileClasspath = contentRoots.filterIsInstance<JvmClasspathRoot>().map { it.file }
val javaSourceRoots = contentRoots.filterIsInstance<JavaSourceRoot>().map { it.file }
val useLightAnalysis = configuration.get(Kapt3ConfigurationKeys.USE_LIGHT_ANALYSIS) == "true"
val correctErrorTypes = configuration.get(Kapt3ConfigurationKeys.CORRECT_ERROR_TYPES) == "true"
if (isVerbose) {
logger.info("Kapt3 is enabled.")
logger.info("Annotation processing mode: $aptMode")
logger.info("Use light analysis: $useLightAnalysis")
logger.info("Correct error types: $correctErrorTypes")
logger.info("Source output directory: $sourcesOutputDir")
logger.info("Classes output directory: $classFilesOutputDir")
logger.info("Stubs output directory: $stubsOutputDir")
logger.info("Incremental data output directory: $incrementalDataOutputDir")
logger.info("Compile classpath: " + compileClasspath.joinToString())
logger.info("Annotation processing classpath: " + apClasspath.joinToString())
logger.info("Annotation processors: " + annotationProcessors)
logger.info("Java source roots: " + javaSourceRoots.joinToString())
logger.info("Options: $apOptions")
}
val kapt3AnalysisCompletedHandlerExtension = ClasspathBasedKapt3Extension(
compileClasspath, apClasspath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir,
stubsOutputDir, incrementalDataOutputDir, apOptions, javacCliOptions, annotationProcessors,
aptMode, useLightAnalysis, correctErrorTypes, System.currentTimeMillis(), logger, configuration)
AnalysisHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
}
/* This extension simply disables both code analysis and code generation.
* When aptOnly is true, and any of required kapt options was not passed, we just abort compilation by providing this extension.
* */
private class AbortAnalysisHandlerExtension : AnalysisHandlerExtension {
override fun doAnalysis(
project: Project,
module: ModuleDescriptor,
projectContext: ProjectContext,
files: Collection<KtFile>,
bindingTrace: BindingTrace,
componentProvider: ComponentProvider
): AnalysisResult? {
return AnalysisResult.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
}
override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
bindingTrace: BindingTrace,
files: Collection<KtFile>
): AnalysisResult? {
return AnalysisResult.Companion.success(bindingTrace.bindingContext, module, shouldGenerateCode = false)
}
}
}
enum class AptMode {
WITH_COMPILATION, STUBS_AND_APT, STUBS_ONLY, APT_ONLY;
val runAnnotationProcessing
get() = this != STUBS_ONLY
val generateStubs
get() = this != APT_ONLY
companion object {
// Supports both deprecated APT_ONLY and new APT_MODE options
fun parse(mode: String?): AptMode = when (mode) {
"true", "stubsAndApt" -> STUBS_AND_APT
"false", "compile" -> WITH_COMPILATION
"apt" -> APT_ONLY
"stubs" -> STUBS_ONLY
else -> WITH_COMPILATION
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3
import com.intellij.openapi.project.Project
import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.jvm.ClassReader
import com.sun.tools.javac.main.JavaCompiler
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Options
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.kapt3.javac.KaptJavaCompiler
import org.jetbrains.kotlin.kapt3.javac.KaptJavaLog
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import javax.tools.JavaFileManager
class KaptContext<out GState : GenerationState?>(
val logger: KaptLogger,
val project: Project,
val bindingContext: BindingContext,
val compiledClasses: List<ClassNode>,
val origins: Map<Any, JvmDeclarationOrigin>,
val generationState: GState,
processorOptions: Map<String, String>,
javacOptions: Map<String, String> = emptyMap()
) : AutoCloseable {
val context = Context()
val compiler: KaptJavaCompiler
val fileManager: JavacFileManager
val options: Options
val javaLog: KaptJavaLog
init {
KaptJavaLog.preRegister(context, logger.messageCollector)
JavacFileManager.preRegister(context)
KaptTreeMaker.preRegister(context, this)
KaptJavaCompiler.preRegister(context)
fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
compiler = JavaCompiler.instance(context) as KaptJavaCompiler
ClassReader.instance(context).saveParameterNames = true
javaLog = compiler.log as KaptJavaLog
options = Options.instance(context)
for ((key, value) in processorOptions) {
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
options.put(option, option) // key == value: it's intentional
}
for ((key, value) in javacOptions) {
if (value.isNotEmpty()) {
options.put(key, value)
} else {
options.put(key, key)
}
}
if (logger.isVerbose) {
logger.info("Javac options: " + options.keySet().keysToMap { key -> options[key] ?: "" })
}
}
override fun close() {
compiler.close()
fileManager.close()
generationState?.destroy()
}
}
@@ -0,0 +1,122 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3
import com.sun.tools.javac.comp.CompileStates
import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.main.JavaCompiler
import com.sun.tools.javac.main.Option
import com.sun.tools.javac.processing.AnnotationProcessingError
import com.sun.tools.javac.processing.JavacFiler
import com.sun.tools.javac.processing.JavacProcessingEnvironment
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
import org.jetbrains.kotlin.kapt3.util.isJava9OrLater
import org.jetbrains.kotlin.kapt3.util.putJavacOption
import java.io.File
import javax.annotation.processing.Processor
import javax.tools.JavaFileManager
import javax.tools.JavaFileObject
import com.sun.tools.javac.util.List as JavacList
fun KaptContext<*>.doAnnotationProcessing(
javaSourceFiles: List<File>,
processors: List<Processor>,
compileClasspath: List<File>,
annotationProcessingClasspath: List<File>,
annotationProcessors: String,
sourcesOutputDir: File,
classesOutputDir: File,
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil(),
withJdk: Boolean = false
) {
with (options) {
put(Option.PROC, "only") // Only process annotations
if (!withJdk) {
putJavacOption("BOOTCLASSPATH", "BOOT_CLASS_PATH", "") // No boot classpath
}
putJavacOption("CLASSPATH", "CLASS_PATH", compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH", annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
put(Option.PROCESSOR, annotationProcessors)
put(Option.S, sourcesOutputDir.canonicalPath)
put(Option.D, classesOutputDir.canonicalPath)
put(Option.ENCODING, "UTF-8")
}
val processingEnvironment = JavacProcessingEnvironment.instance(context)
val compilerAfterAP: JavaCompiler
try {
if (isJava9OrLater) {
val initProcessAnnotationsMethod = JavaCompiler::class.java.declaredMethods.single { it.name == "initProcessAnnotations" }
initProcessAnnotationsMethod.invoke(compiler, processors, emptyList<JavaFileObject>(), emptyList<String>())
}
else {
compiler.initProcessAnnotations(processors)
}
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
var parsedJavaFiles = compiler.stopIfErrorOccurred(
CompileStates.CompileState.PARSE, compiler.parseFiles(javaFileObjects))
if (isJava9OrLater) {
val initModulesMethod = compiler.javaClass.getMethod("initModules", JavacList::class.java)
@Suppress("UNCHECKED_CAST")
parsedJavaFiles = compiler.stopIfErrorOccurred(
CompileStates.CompileState.PARSE,
initModulesMethod.invoke(compiler, parsedJavaFiles) as JavacList<JCTree.JCCompilationUnit>)
}
compilerAfterAP = try {
javaLog.interceptorData.files = parsedJavaFiles.map { it.sourceFile to it }.toMap()
val analyzedFiles = compiler.stopIfErrorOccurred(
CompileStates.CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources))
if (isJava9OrLater) {
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
processAnnotationsMethod.invoke(compiler, analyzedFiles)
compiler
}
else {
compiler.processAnnotations(analyzedFiles)
}
} catch (e: AnnotationProcessingError) {
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
}
val log = compilerAfterAP.log
val filer = processingEnvironment.filer as JavacFiler
val errorCount = log.nerrors
val warningCount = log.nwarnings
logger.info { "Annotation processing complete, errors: $errorCount, warnings: $warningCount" }
if (logger.isVerbose) {
filer.displayState()
}
if (log.nerrors > 0) {
throw KaptError(KaptError.Kind.ERROR_RAISED)
}
} finally {
processingEnvironment.close()
this@doAnnotationProcessing.close()
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.javac
import com.sun.tools.javac.comp.CompileStates
import com.sun.tools.javac.main.JavaCompiler
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.List as JavacList
class KaptJavaCompiler(context: Context) : JavaCompiler(context) {
public override fun shouldStop(cs: CompileStates.CompileState) = super.shouldStop(cs)
fun <T> stopIfErrorOccurred(cs: CompileStates.CompileState, list: JavacList<T>): JavacList<T> {
return if (shouldStop(cs)) JavacList.nil<T>() else list
}
companion object {
internal fun preRegister(context: Context) {
context.put(compilerKey, Context.Factory<JavaCompiler>(::KaptJavaCompiler))
}
}
}
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.javac
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware
import java.net.URI
import java.net.URL
import javax.lang.model.element.Modifier
import javax.lang.model.element.NestingKind
import javax.tools.JavaFileObject
class KaptJavaFileObject(
val compilationUnit: JCTree.JCCompilationUnit,
val clazz: JCTree.JCClassDecl,
val timestamp: Long = System.currentTimeMillis()
) : JavaFileObject {
override fun toString() = "${javaClass.simpleName}[$name]"
override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?): Boolean {
if (simpleName == null || kind == null) return false
return this.kind == kind && simpleName == clazz.simpleName.toString()
}
override fun getKind() = JavaFileObject.Kind.SOURCE
override fun getName(): String {
val packageName = compilationUnit.getPackageNameJava9Aware()
if (packageName == null || packageName.toString() == "") {
return clazz.name.toString() + ".java"
}
return packageName.toString().replace('.', '/') + '/' + clazz.simpleName.toString() + ".java"
}
override fun getAccessLevel(): Modifier? {
val flags = clazz.modifiers.getFlags()
if (Modifier.PUBLIC in flags) return Modifier.PUBLIC
if (Modifier.PROTECTED in flags) return Modifier.PROTECTED
if (Modifier.PRIVATE in flags) return Modifier.PRIVATE
return null
}
override fun openInputStream() = getCharContent(false).byteInputStream()
override fun getCharContent(ignoreEncodingErrors: Boolean) = compilationUnit.toString()
override fun getNestingKind() = NestingKind.TOP_LEVEL
override fun toUri(): URI? = URL(name).toURI()
override fun openReader(ignoreEncodingErrors: Boolean) = getCharContent(ignoreEncodingErrors).reader()
override fun openWriter() = throw UnsupportedOperationException()
override fun getLastModified() = timestamp
override fun openOutputStream() = throw UnsupportedOperationException()
override fun delete() = throw UnsupportedOperationException()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other::class.java != this::class.java) return false
other as KaptJavaFileObject
if (compilationUnit != other.compilationUnit) return false
if (clazz != other.clazz) return false
if (timestamp != other.timestamp) return false
return true
}
override fun hashCode(): Int {
var result = 0
result = 31 * result + compilationUnit.hashCode()
result = 31 * result + clazz.hashCode()
result = 31 * result + timestamp.hashCode()
return result
}
}
@@ -0,0 +1,144 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.javac
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.util.*
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedWriter
import java.io.PrintWriter
import javax.tools.JavaFileObject
class KaptJavaLog(
context: Context,
errWriter: PrintWriter,
warnWriter: PrintWriter,
noticeWriter: PrintWriter,
val interceptorData: DiagnosticInterceptorData
) : Log(context, errWriter, warnWriter, noticeWriter) {
init {
context.put(Log.outKey, noticeWriter)
}
val reportedDiagnostics: List<JCDiagnostic>
get() = _reportedDiagnostics
private val _reportedDiagnostics = mutableListOf<JCDiagnostic>()
override fun flush(kind: WriterKind?) {
super.flush(kind)
val diagnosticKind = when (kind) {
WriterKind.ERROR -> JCDiagnostic.DiagnosticType.ERROR
WriterKind.WARNING -> JCDiagnostic.DiagnosticType.WARNING
WriterKind.NOTICE -> JCDiagnostic.DiagnosticType.NOTE
else -> return
}
_reportedDiagnostics.removeAll { it.type == diagnosticKind }
}
override fun flush() {
super.flush()
_reportedDiagnostics.clear()
}
override fun report(diagnostic: JCDiagnostic) {
if (diagnostic.type == JCDiagnostic.DiagnosticType.ERROR && diagnostic.code in IGNORED_DIAGNOSTICS) {
return
}
if (diagnostic.type == JCDiagnostic.DiagnosticType.WARNING
&& diagnostic.code == "compiler.warn.proc.unmatched.processor.options"
&& diagnostic.args.singleOrNull() == "[kapt.kotlin.generated]"
) {
// Do not report the warning about "kapt.kotlin.generated" option being ignored if it's the only ignored option
return
}
val targetElement = diagnostic.diagnosticPosition
if (diagnostic.code.contains("err.cant.resolve") && targetElement != null) {
val sourceFile = interceptorData.files[diagnostic.source]
if (sourceFile != null) {
val insideImports = targetElement.tree in sourceFile.imports
// Ignore resolve errors in import statements
if (insideImports) return
}
}
_reportedDiagnostics += diagnostic
super.report(diagnostic)
}
private operator fun <T : JCTree> Iterable<T>.contains(element: JCTree?): Boolean {
if (element == null) {
return false
}
var found = false
val visitor = object : JCTree.Visitor() {
override fun visitImport(that: JCTree.JCImport) {
super.visitImport(that)
if (!found) that.qualid.accept(this)
}
override fun visitSelect(that: JCTree.JCFieldAccess) {
super.visitSelect(that)
if (!found) that.selected.accept(this)
}
override fun visitTree(that: JCTree) {
if (!found && element == that) found = true
}
}
this.forEach { if (!found) it.accept(visitor) }
return found
}
companion object {
private val IGNORED_DIAGNOSTICS = setOf(
"compiler.err.name.clash.same.erasure",
"compiler.err.name.clash.same.erasure.no.override",
"compiler.err.name.clash.same.erasure.no.override.1",
"compiler.err.name.clash.same.erasure.no.hide",
"compiler.err.already.defined",
"compiler.err.annotation.type.not.applicable",
"compiler.err.doesnt.exist")
internal fun preRegister(context: Context, messageCollector: MessageCollector) {
val interceptorData = DiagnosticInterceptorData()
context.put(Log.logKey, Context.Factory<Log> {
fun makeWriter(severity: CompilerMessageSeverity) = PrintWriter(MessageCollectorBackedWriter(messageCollector, severity))
val errWriter = makeWriter(ERROR)
val warnWriter = makeWriter(STRONG_WARNING)
val noticeWriter = makeWriter(WARNING)
KaptJavaLog(it, errWriter, warnWriter, noticeWriter, interceptorData)
})
}
}
class DiagnosticInterceptorData {
var files: Map<JavaFileObject, JCTree.JCCompilationUnit> = emptyMap()
}
}
fun KaptContext<*>.kaptError(text: String): JCDiagnostic {
return JCDiagnostic.Factory.instance(context).error(null, null, "proc.messager", text)
}
@@ -0,0 +1,166 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.javac
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import com.sun.tools.javac.code.TypeTag
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Name
import com.sun.tools.javac.util.Names
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.Type.*
import org.jetbrains.org.objectweb.asm.tree.ClassNode
class KaptTreeMaker(context: Context, private val kaptContext: KaptContext<*>) : TreeMaker(context) {
val nameTable: Name.Table = Names.instance(context).table
fun Type(type: Type): JCTree.JCExpression {
convertBuiltinType(type)?.let { return it }
if (type.sort == ARRAY) {
return TypeArray(Type(AsmUtil.correctElementType(type)))
}
return FqName(type.internalName)
}
fun FqName(internalOrFqName: String): JCTree.JCExpression {
val path = getQualifiedName(internalOrFqName).convertSpecialFqName().split('.')
assert(path.isNotEmpty())
return FqName(path)
}
fun FqName(fqName: FqName) = FqName(fqName.pathSegments().map { it.asString() })
private fun FqName(path: List<String>): JCTree.JCExpression {
if (path.size == 1) return SimpleName(path.single())
var expr = Select(SimpleName(path[0]), name(path[1]))
for (index in 2..path.lastIndex) {
expr = Select(expr, name(path[index]))
}
return expr
}
fun getQualifiedName(type: Type) = getQualifiedName(type.internalName)
fun getSimpleName(clazz: ClassNode) = getQualifiedName(clazz.name).substringAfterLast('.')
fun getQualifiedName(internalName: String): String {
val nameWithDots = internalName.replace('/', '.')
// This is a top-level class
if ('$' !in nameWithDots) return nameWithDots
// Maybe it's in our sources?
val classFromSources = kaptContext.compiledClasses.firstOrNull { it.name == internalName }
if (classFromSources != null) {
// Get inner class node pointing to the outer class
val innerClassNode = classFromSources.innerClasses.firstOrNull { it.name == classFromSources.name }
return innerClassNode?.let { getQualifiedName(it.outerName) + "." + it.innerName } ?: nameWithDots
}
// Search in the classpath
val javaPsiFacade = JavaPsiFacade.getInstance(kaptContext.project)
val scope = GlobalSearchScope.allScope(javaPsiFacade.project)
val fqNameFromClassWithPreciseName = javaPsiFacade.findClass(nameWithDots, scope)?.qualifiedName
if (fqNameFromClassWithPreciseName != null) {
return fqNameFromClassWithPreciseName
}
nameWithDots.iterateDollars { outerName, innerName ->
if (innerName.isEmpty()) return@iterateDollars // We already checked an exact match
val outerClass = javaPsiFacade.findClass(outerName, scope) ?: return@iterateDollars
return tryToFindNestedClass(outerClass, innerName)?.qualifiedName ?: return@iterateDollars
}
return nameWithDots
}
private fun tryToFindNestedClass(outerClass: PsiClass, innerClassName: String): PsiClass? {
outerClass.findInnerClassByName(innerClassName, false)?.let { return it }
innerClassName.iterateDollars { name1, name2 ->
if (name2.isEmpty()) return outerClass.findInnerClassByName(name1, false)
val nestedClass = outerClass.findInnerClassByName(name1, false)
if (nestedClass != null) {
tryToFindNestedClass(nestedClass, name2)?.let { return it }
}
}
return null
}
private inline fun String.iterateDollars(variantHandler: (outerName: String, innerName: String) -> Unit) {
var dollarIndex = this.indexOf('$')
if (dollarIndex < 0) {
variantHandler(this, "")
return
}
while (dollarIndex > 0 && dollarIndex < this.lastIndex) {
val outerName = this.take(dollarIndex)
val innerName = this.drop(dollarIndex + 1)
variantHandler(outerName, innerName)
dollarIndex = this.indexOf('$', startIndex = dollarIndex + 1)
}
}
private fun String.convertSpecialFqName(): String {
// Hard-coded in ImplementationBodyCodegen, KOTLIN_MARKER_INTERFACES
if (this == "kotlin.jvm.internal.markers.KMutableMap\$Entry") {
return replace('$', '.')
}
return this
}
private fun convertBuiltinType(type: Type): JCTree.JCExpression? {
val typeTag = when (type) {
BYTE_TYPE -> TypeTag.BYTE
BOOLEAN_TYPE -> TypeTag.BOOLEAN
CHAR_TYPE -> TypeTag.CHAR
SHORT_TYPE -> TypeTag.SHORT
INT_TYPE -> TypeTag.INT
LONG_TYPE -> TypeTag.LONG
FLOAT_TYPE -> TypeTag.FLOAT
DOUBLE_TYPE -> TypeTag.DOUBLE
VOID_TYPE -> TypeTag.VOID
else -> null
} ?: return null
return TypeIdent(typeTag)
}
fun SimpleName(name: String): JCTree.JCExpression = Ident(name(name))
fun name(name: String): Name = nameTable.fromString(name)
companion object {
internal fun preRegister(context: Context, kaptContext: KaptContext<*>) {
context.put(treeMakerKey, Context.Factory<TreeMaker> { KaptTreeMaker(it, kaptContext) })
}
}
}
@@ -0,0 +1,112 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.stubs
import com.sun.tools.javac.code.BoundKind
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.kapt3.mapJList
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.resolve.DescriptorUtils.isAnonymousObject
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.replace
class AnonymousTypeHandler(private val converter: ClassFileToSourceStubConverter) {
fun <T : JCTree.JCExpression?> getNonAnonymousType(descriptor: DeclarationDescriptor?, f: () -> T): T {
val classType = when (descriptor) {
is ClassDescriptor -> descriptor.defaultType
is CallableDescriptor -> descriptor.returnType
else -> null
} ?: return f()
return getNonAnonymousType(classType, f)
}
fun <T : JCTree.JCExpression?> getNonAnonymousType(type: KotlinType, f: () -> T): T {
if (!checkIfAnonymousRecursively(type)) return f()
@Suppress("UNCHECKED_CAST")
return convertKotlinType(convertPossiblyAnonymousType(type)) as T
}
private fun checkIfAnonymousRecursively(type: KotlinType): Boolean {
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return false
if (isAnonymousObject(declaration)) return true
return type.arguments.any {
if (it.isStarProjection) return@any false
checkIfAnonymousRecursively(it.type)
}
}
private fun convertPossiblyAnonymousType(type: KotlinType): KotlinType {
val declaration = type.constructor.declarationDescriptor as? ClassDescriptor ?: return type
val actualType = when {
isAnonymousObject(declaration) -> findMostSuitableParentForAnonymousType(declaration)
else -> type
}
if (actualType.arguments.isEmpty()) return actualType
val arguments = actualType.arguments.map { typeArg ->
if (typeArg.isStarProjection) return@map typeArg
TypeProjectionImpl(typeArg.projectionKind, convertPossiblyAnonymousType(typeArg.type))
}
return actualType.replace(arguments)
}
private fun findMostSuitableParentForAnonymousType(descriptor: ClassDescriptor): KotlinType {
descriptor.getSuperClassNotAny()?.let { return it.defaultType }
val sortedSuperTypes = descriptor.typeConstructor.supertypes
.sortedBy { it.constructor.declarationDescriptor?.name?.asString() ?: "" }
for (candidate in sortedSuperTypes) {
if (!candidate.isAnyOrNullableAny()) return candidate
}
return descriptor.builtIns.anyType
}
private fun convertKotlinType(type: KotlinType): JCTree.JCExpression {
val typeMapper = converter.kaptContext.generationState.typeMapper
val treeMaker = converter.treeMaker
// Primitive types can't be anonymous, so if we get here, we want to map a class type or its generic argument
val selfType = treeMaker.Type(typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
if (type.arguments.isEmpty()) return selfType
return treeMaker.TypeApply(selfType, mapJList(type.arguments) { projection ->
if (projection.isStarProjection) return@mapJList treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
val renderedArg = convertKotlinType(projection.type)
when (projection.projectionKind) {
Variance.INVARIANT -> renderedArg
Variance.OUT_VARIANCE -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.EXTENDS), renderedArg)
Variance.IN_VARIANCE -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.SUPER), renderedArg)
}
})
}
}
@@ -0,0 +1,820 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.stubs
import com.sun.tools.javac.code.Flags
import com.sun.tools.javac.code.TypeTag
import com.sun.tools.javac.parser.Tokens
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.JCTree.*
import com.sun.tools.javac.tree.TreeMaker
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.kapt3.*
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.javac.kaptError
import org.jetbrains.kotlin.kapt3.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import javax.lang.model.element.ElementKind
import com.sun.tools.javac.util.List as JavacList
class ClassFileToSourceStubConverter(
val kaptContext: KaptContext<GenerationState>,
val generateNonExistentClass: Boolean,
val correctErrorTypes: Boolean
) {
private companion object {
private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
private val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).toLong()
private 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()
private 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()
private 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()
private val PARAMETER_MODIFIERS = FIELD_MODIFIERS or Flags.PARAMETER or Flags.VARARGS or Opcodes.ACC_FINAL.toLong()
private val BLACKLISTED_ANNOTATIONS = listOf(
"java.lang.Deprecated", "kotlin.Deprecated", // Deprecated annotations
"java.lang.Synthetic",
"synthetic.kotlin.jvm.GeneratedByJvmOverloads", // kapt3-related annotation for marking JvmOverloads-generated methods
"kotlin.jvm." // Kotlin annotations from runtime
)
private val JAVA_KEYWORD_FILTER_REGEX = "[a-z]+".toRegex()
private val JAVA_KEYWORDS = Tokens.TokenKind.values()
.filter { JAVA_KEYWORD_FILTER_REGEX.matches(it.toString().orEmpty()) }
.mapTo(hashSetOf(), Any::toString)
}
private val _bindings = mutableMapOf<String, KaptJavaFileObject>()
val bindings: Map<String, KaptJavaFileObject>
get() = _bindings
val treeMaker = TreeMaker.instance(kaptContext.context) as KaptTreeMaker
private val signatureParser = SignatureParser(treeMaker)
private val anonymousTypeHandler = AnonymousTypeHandler(this)
private var done = false
fun convert(): JavacList<JCCompilationUnit> {
if (done) error(ClassFileToSourceStubConverter::class.java.simpleName + " can convert classes only once")
done = true
var stubs = mapJList(kaptContext.compiledClasses) { convertTopLevelClass(it) }
if (generateNonExistentClass) {
stubs = stubs.append(generateNonExistentClass())
}
return stubs
}
private fun generateNonExistentClass(): JCCompilationUnit {
val nonExistentClass = treeMaker.ClassDef(
treeMaker.Modifiers((Flags.PUBLIC or Flags.FINAL).toLong()),
treeMaker.name("NonExistentClass"),
JavacList.nil(),
null,
JavacList.nil(),
JavacList.nil())
val topLevel = treeMaker.TopLevelJava9Aware(treeMaker.SimpleName("error"), JavacList.of(nonExistentClass))
topLevel.sourcefile = KaptJavaFileObject(topLevel, nonExistentClass)
// We basically don't need to add binding for NonExistentClass
return topLevel
}
private fun convertTopLevelClass(clazz: ClassNode): JCCompilationUnit? {
val origin = kaptContext.origins[clazz] ?: return null
val ktFile = origin.element?.containingFile as? KtFile ?: return null
val descriptor = origin.descriptor ?: return null
// Nested classes will be processed during the outer classes conversion
if ((descriptor as? ClassDescriptor)?.isNested ?: false) return null
val packageName = ktFile.packageFqName.asString()
val packageClause = if (packageName.isEmpty()) null else treeMaker.FqName(packageName)
val classDeclaration = convertClass(clazz, packageName, true) ?: return null
val imports = if (correctErrorTypes) convertImports(ktFile, classDeclaration) else JavacList.nil()
val classes = JavacList.of<JCTree>(classDeclaration)
val topLevel = treeMaker.TopLevelJava9Aware(packageClause, imports + classes)
KaptJavaFileObject(topLevel, classDeclaration).apply {
topLevel.sourcefile = this
_bindings[clazz.name] = this
}
return topLevel
}
private fun convertImports(file: KtFile, classDeclaration: JCClassDecl): JavacList<JCTree> {
val imports = mutableListOf<JCTree>()
for (importDirective in file.importDirectives) {
// Qualified name should be valid Java fq-name
val importedFqName = importDirective.importedFqName ?: continue
if (!isValidQualifiedName(importedFqName)) continue
val shortName = importedFqName.shortName()
if (shortName.asString() == classDeclaration.simpleName.toString()) continue
// If alias is specified, it also should be valid Java name
val aliasName = importDirective.aliasName
if (aliasName != null /*TODO support aliases */ /*&& getValidIdentifierName(aliasName) == null*/) continue
val importedReference = getReferenceExpression(importDirective.importedReference)
?.let { kaptContext.bindingContext[BindingContext.REFERENCE_TARGET, it] }
if (importedReference is CallableDescriptor) continue
val importedExpr = treeMaker.FqName(importedFqName.asString())
imports += if (importDirective.isAllUnder) {
treeMaker.Import(treeMaker.Select(importedExpr, treeMaker.nameTable.names.asterisk), false)
} else {
treeMaker.Import(importedExpr, false)
}
}
return JavacList.from(imports)
}
private tailrec fun getReferenceExpression(expression: KtExpression?): KtReferenceExpression? = when (expression) {
is KtReferenceExpression -> expression
is KtQualifiedExpression -> getReferenceExpression(expression.selectorExpression)
else -> null
}
/**
* Returns false for the inner classes or if the origin for the class was not found.
*/
private fun convertClass(clazz: ClassNode, packageFqName: String, isTopLevel: Boolean): JCClassDecl? {
if (isSynthetic(clazz.access)) return null
if (checkIfShouldBeIgnored(Type.getObjectType(clazz.name))) return null
val descriptor = kaptContext.origins[clazz]?.descriptor ?: return null
val isNested = (descriptor as? ClassDescriptor)?.isNested ?: false
val isInner = isNested && (descriptor as? ClassDescriptor)?.isInner ?: false
val flags = getClassAccessFlags(clazz, descriptor, isInner, isNested)
val isEnum = clazz.isEnum()
val isAnnotation = clazz.isAnnotation()
val modifiers = convertModifiers(flags,
if (isEnum) ElementKind.ENUM else ElementKind.CLASS,
packageFqName, clazz.visibleAnnotations, clazz.invisibleAnnotations, descriptor.annotations)
val isDefaultImpls = clazz.name.endsWith("${descriptor.name.asString()}\$DefaultImpls")
&& isPublic(clazz.access) && isFinal(clazz.access)
&& descriptor is ClassDescriptor
&& descriptor.kind == ClassKind.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()))) {
return null
}
val simpleName = getClassName(clazz, descriptor, isDefaultImpls, packageFqName)
if (!isValidIdentifier(simpleName)) return null
val interfaces = mapJList(clazz.interfaces) {
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapJList null
treeMaker.FqName(treeMaker.getQualifiedName(it))
}
val superClass = treeMaker.FqName(treeMaker.getQualifiedName(clazz.superName))
val hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
class EnumValueData(val field: FieldNode, val innerClass: InnerClassNode?, val correspondingClass: ClassNode?)
val enumValuesData = clazz.fields.filter { it.isEnumValue() }.map { field ->
var foundInnerClass: InnerClassNode? = null
var correspondingClass: ClassNode? = null
for (innerClass in clazz.innerClasses) {
// Class should have the same name as enum value
if (innerClass.innerName != field.name) continue
val classNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ?: continue
// Super class name of the class should be our enum class
if (classNode.superName != clazz.name) continue
correspondingClass = classNode
foundInnerClass = innerClass
break
}
EnumValueData(field, foundInnerClass, correspondingClass)
}
val enumValues: JavacList<JCTree> = mapJList(enumValuesData) { data ->
val constructorArguments = Type.getArgumentTypes(clazz.methods.firstOrNull {
it.name == "<init>" && Type.getArgumentsAndReturnSizes(it.desc).shr(2) >= 2
}?.desc ?: "()Z")
val args = mapJList(constructorArguments.drop(2)) { convertLiteralExpression(getDefaultValue(it)) }
val def = data.correspondingClass?.let { convertClass(it, packageFqName, false) }
convertField(data.field, packageFqName, treeMaker.NewClass(
/* enclosing = */ null,
/* typeArgs = */ JavacList.nil(),
/* clazz = */ treeMaker.Ident(treeMaker.name(data.field.name)),
/* args = */ args,
/* def = */ def))
}
val fields = mapJList<FieldNode, JCTree>(clazz.fields) {
if (it.isEnumValue()) null else convertField(it, packageFqName)
}
val methods = mapJList<MethodNode, JCTree>(clazz.methods) {
if (isEnum) {
if (it.name == "values" && it.desc == "()[L${clazz.name};") return@mapJList null
if (it.name == "valueOf" && it.desc == "(Ljava/lang/String;)L${clazz.name};") return@mapJList null
}
convertMethod(it, clazz, packageFqName)
}
val nestedClasses = mapJList<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
if (enumValuesData.any { it.innerClass == innerClass }) return@mapJList null
if (innerClass.outerName != clazz.name) return@mapJList null
val innerClassNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ?: return@mapJList null
convertClass(innerClassNode, packageFqName, false)
}
return treeMaker.ClassDef(
modifiers,
treeMaker.name(simpleName),
genericType.typeParameters,
if (hasSuperClass) genericType.superClass else null,
genericType.interfaces,
enumValues + fields + methods + nestedClasses)
}
private tailrec fun checkIfShouldBeIgnored(type: Type): Boolean {
if (type.sort == Type.ARRAY) {
return checkIfShouldBeIgnored(type.elementType)
}
if (type.sort != Type.OBJECT) return false
val internalName = type.internalName
// Ignore type names with Java keywords in it
if (internalName.split('/', '.').any { it in JAVA_KEYWORDS }) {
return true
}
val clazz = kaptContext.compiledClasses.firstOrNull { it.name == internalName } ?: return false
return checkIfInnerClassNameConflictsWithOuter(clazz)
}
private fun findContainingClassNode(clazz: ClassNode): ClassNode? {
val innerClassForOuter = clazz.innerClasses.firstOrNull { it.name == clazz.name } ?: return null
return kaptContext.compiledClasses.firstOrNull { it.name == innerClassForOuter.outerName }
}
// Java forbids outer and inner class names to be the same. Check if the names are different
private tailrec fun checkIfInnerClassNameConflictsWithOuter(
clazz: ClassNode,
outerClass: ClassNode? = findContainingClassNode(clazz)
): Boolean {
if (outerClass == null) return false
if (treeMaker.getSimpleName(clazz) == treeMaker.getSimpleName(outerClass)) return true
// Try to find the containing class for outerClassNode (to check the whole tree recursively)
val containingClassForOuterClass = findContainingClassNode(outerClass) ?: return false
return checkIfInnerClassNameConflictsWithOuter(clazz, containingClassForOuterClass)
}
private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean) = when {
(descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE -> {
// Classes inside interfaces should always be public and static.
// See com.sun.tools.javac.comp.Enter.visitClassDef for more information.
(clazz.access or Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) and
Opcodes.ACC_PRIVATE.inv() and Opcodes.ACC_PROTECTED.inv() // Remove private and protected modifiers
}
!isInner && isNested -> clazz.access or Opcodes.ACC_STATIC
else -> clazz.access
}
private fun getClassName(clazz: ClassNode, descriptor: DeclarationDescriptor, isDefaultImpls: Boolean, packageFqName: String): String {
return when (descriptor) {
is PackageFragmentDescriptor -> {
val className = if (packageFqName.isEmpty()) clazz.name else clazz.name.drop(packageFqName.length + 1)
if (className.isEmpty()) throw IllegalStateException("Invalid package facade class name: ${clazz.name}")
className
}
else -> if (isDefaultImpls) "DefaultImpls" else descriptor.name.asString()
}
}
private fun convertField(
field: FieldNode,
packageFqName: String,
explicitInitializer: JCExpression? = null
): JCVariableDecl? {
if (isSynthetic(field.access)) return null
// not needed anymore
val origin = kaptContext.origins[field]
val descriptor = origin?.descriptor
val modifiers = convertModifiers(
field.access, ElementKind.FIELD, packageFqName,
field.visibleAnnotations, field.invisibleAnnotations, descriptor?.annotations ?: Annotations.EMPTY)
val name = field.name
if (!isValidIdentifier(name)) return null
val type = Type.getType(field.desc)
if (checkIfShouldBeIgnored(type)) {
return null
}
// Enum type must be an identifier (Javac requirement)
val typeExpression = if (isEnum(field.access))
treeMaker.SimpleName(treeMaker.getQualifiedName(type).substringAfterLast('.'))
else
anonymousTypeHandler.getNonAnonymousType(descriptor) {
getNonErrorType((descriptor as? CallableDescriptor)?.returnType,
ktTypeProvider = { (kaptContext.origins[field]?.element as? KtVariableDeclaration)?.typeReference },
ifNonError = { signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type)) })
}
val value = field.value
val initializer = explicitInitializer
?: convertValueOfPrimitiveTypeOrString(value)
?: if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null
return treeMaker.VarDef(modifiers, treeMaker.name(name), typeExpression, initializer)
}
private fun convertMethod(method: MethodNode, containingClass: ClassNode, packageFqName: String): JCMethodDecl? {
val descriptor = kaptContext.origins[method]?.descriptor as? CallableDescriptor ?: return null
val isAnnotationHolderForProperty = descriptor is PropertyDescriptor && isSynthetic(method.access)
&& isStatic(method.access) && method.name.endsWith("\$annotations")
if (isSynthetic(method.access) && !isAnnotationHolderForProperty) return null
val isOverridden = descriptor.overriddenDescriptors.isNotEmpty()
val visibleAnnotations = if (isOverridden) {
(method.visibleAnnotations ?: emptyList()) + AnnotationNode(Type.getType(Override::class.java).descriptor)
} else {
method.visibleAnnotations
}
val isConstructor = method.name == "<init>"
val name = method.name
if (!isValidIdentifier(name, canBeConstructor = isConstructor)) return null
val modifiers = convertModifiers(
if (containingClass.isEnum() && isConstructor)
(method.access.toLong() and VISIBILITY_MODIFIERS.inv())
else
method.access.toLong(),
ElementKind.METHOD, packageFqName, visibleAnnotations, method.invisibleAnnotations, descriptor.annotations)
val asmReturnType = Type.getReturnType(method.desc)
val jcReturnType = if (isConstructor) null else treeMaker.Type(asmReturnType)
val parametersInfo = method.getParametersInfo(containingClass)
if (checkIfShouldBeIgnored(asmReturnType) || parametersInfo.any { checkIfShouldBeIgnored(it.type) }) {
return null
}
@Suppress("NAME_SHADOWING")
val parameters = mapJListIndexed(parametersInfo) { index, info ->
val lastParameter = index == parametersInfo.lastIndex
val isArrayType = info.type.sort == Type.ARRAY
val varargs = if (lastParameter && isArrayType && method.isVarargs()) Flags.VARARGS else 0L
val modifiers = convertModifiers(
info.flags or varargs or Flags.PARAMETER,
ElementKind.PARAMETER,
packageFqName,
info.visibleAnnotations,
info.invisibleAnnotations,
Annotations.EMPTY /* TODO */)
val name = info.name.takeIf { isValidIdentifier(it) } ?: "p${index}_" + info.name.hashCode().ushr(1)
val type = treeMaker.Type(info.type)
treeMaker.VarDef(modifiers, treeMaker.name(name), type, null)
}
val exceptionTypes = mapJList(method.exceptions) { treeMaker.FqName(it) }
val valueParametersFromDescriptor = descriptor.valueParameters
val (genericSignature, returnType) = extractMethodSignatureTypes(
descriptor, exceptionTypes, jcReturnType, method, parameters, valueParametersFromDescriptor)
val defaultValue = method.annotationDefault?.let { convertLiteralExpression(it) }
val body = if (defaultValue != null) {
null
} else if (isAbstract(method.access)) {
null
} else if (isConstructor && containingClass.isEnum()) {
treeMaker.Block(0, JavacList.nil())
} else if (isConstructor) {
// We already checked it in convertClass()
val declaration = kaptContext.origins[containingClass]?.descriptor as ClassDescriptor
val superClass = declaration.getSuperClassOrAny()
val superClassConstructor = superClass.constructors.firstOrNull { it.visibility.isVisible(null, it, declaration) }
val superClassConstructorCall = if (superClassConstructor != null) {
val args = mapJList(superClassConstructor.valueParameters) { param ->
convertLiteralExpression(getDefaultValue(kaptContext.generationState.typeMapper.mapType(param.type)))
}
val call = treeMaker.Apply(JavacList.nil(), treeMaker.SimpleName("super"), args)
JavacList.of<JCStatement>(treeMaker.Exec(call))
} else {
JavacList.nil<JCStatement>()
}
treeMaker.Block(0, superClassConstructorCall)
} else if (asmReturnType == Type.VOID_TYPE) {
treeMaker.Block(0, JavacList.nil())
} else {
val returnStatement = treeMaker.Return(convertLiteralExpression(getDefaultValue(asmReturnType)))
treeMaker.Block(0, JavacList.of(returnStatement))
}
return treeMaker.MethodDef(
modifiers, treeMaker.name(name), returnType, genericSignature.typeParameters,
genericSignature.parameterTypes, genericSignature.exceptionTypes,
body, defaultValue)
}
private fun extractMethodSignatureTypes(
descriptor: CallableDescriptor,
exceptionTypes: JavacList<JCExpression>,
jcReturnType: JCExpression?, method: MethodNode,
parameters: JavacList<JCVariableDecl>,
valueParametersFromDescriptor: List<ValueParameterDescriptor>
): Pair<SignatureParser.MethodGenericSignature, JCExpression?> {
val genericSignature = signatureParser.parseMethodSignature(
method.signature, parameters, exceptionTypes, jcReturnType,
nonErrorParameterTypeProvider = { index, lazyType ->
if (descriptor is PropertySetterDescriptor && valueParametersFromDescriptor.size == 1 && index == 0) {
getNonErrorType(descriptor.correspondingProperty.returnType,
ktTypeProvider = { (kaptContext.origins[method]?.element as? KtVariableDeclaration)?.typeReference },
ifNonError = { lazyType() })
}
else if (descriptor is FunctionDescriptor && valueParametersFromDescriptor.size == parameters.size) {
getNonErrorType(valueParametersFromDescriptor[index].type,
ktTypeProvider = {
(kaptContext.origins[method]?.element as? KtFunction)?.valueParameters?.get(index)?.typeReference
},
ifNonError = { lazyType() })
}
else {
lazyType()
}
})
val returnType = anonymousTypeHandler.getNonAnonymousType(descriptor) {
getNonErrorType(descriptor.returnType,
ktTypeProvider = {
val element = kaptContext.origins[method]?.element
when (element) {
is KtFunction -> element.typeReference
is KtProperty -> if (method.name.startsWith("get")) element.typeReference else null
else -> null
}
},
ifNonError = { genericSignature.returnType })
}
return Pair(genericSignature, returnType)
}
private inline fun <T : JCExpression?> getNonErrorType(
type: KotlinType?,
ktTypeProvider: () -> KtTypeReference?,
ifNonError: () -> T
): T {
if (!correctErrorTypes) {
return ifNonError()
}
if (type?.containsErrorTypes() == true) {
val ktType = ktTypeProvider()
if (ktType != null) {
@Suppress("UNCHECKED_CAST")
return convertKtType(ktType, this) as T
}
}
return ifNonError()
}
private fun isValidQualifiedName(name: FqName) = name.pathSegments().all { isValidIdentifier(it.asString()) }
private fun isValidIdentifier(name: String, canBeConstructor: Boolean = false): Boolean {
if (canBeConstructor && name == "<init>") {
return true
}
if (name in JAVA_KEYWORDS) return false
if (name.isEmpty()
|| !Character.isJavaIdentifierStart(name[0])
|| name.drop(1).any { !Character.isJavaIdentifierPart(it) }
) {
return false
}
return true
}
@Suppress("NOTHING_TO_INLINE")
private inline fun convertModifiers(
access: Int,
kind: ElementKind,
packageFqName: String,
visibleAnnotations: List<AnnotationNode>?,
invisibleAnnotations: List<AnnotationNode>?,
descriptorAnnotations: Annotations
): JCModifiers = convertModifiers(access.toLong(), kind, packageFqName, visibleAnnotations, invisibleAnnotations, descriptorAnnotations)
private fun convertModifiers(
access: Long,
kind: ElementKind,
packageFqName: String,
visibleAnnotations: List<AnnotationNode>?,
invisibleAnnotations: List<AnnotationNode>?,
descriptorAnnotations: Annotations
): JCModifiers {
fun findDescriptorAnnotation(anno: AnnotationNode): AnnotationDescriptor? {
val annoFqName = treeMaker.getQualifiedName(Type.getType(anno.desc))
return descriptorAnnotations.findAnnotation(FqName(annoFqName))
}
var annotations = visibleAnnotations?.fold(JavacList.nil<JCAnnotation>()) { list, anno ->
convertAnnotation(anno, packageFqName, findDescriptorAnnotation(anno))?.let { list.prepend(it) } ?: list
} ?: JavacList.nil()
annotations = invisibleAnnotations?.fold(annotations) { list, anno ->
convertAnnotation(anno, packageFqName, findDescriptorAnnotation(anno))?.let { list.prepend(it) } ?: list
} ?: annotations
val flags = when (kind) {
ElementKind.ENUM -> access and CLASS_MODIFIERS and Opcodes.ACC_ABSTRACT.inv().toLong()
ElementKind.CLASS -> access and CLASS_MODIFIERS
ElementKind.METHOD -> access and METHOD_MODIFIERS
ElementKind.FIELD -> access and FIELD_MODIFIERS
ElementKind.PARAMETER -> access and PARAMETER_MODIFIERS
else -> throw IllegalArgumentException("Invalid element kind: $kind")
}
return treeMaker.Modifiers(flags, annotations)
}
private fun convertAnnotation(
annotation: AnnotationNode,
packageFqName: String? = "",
annotationDescriptor: AnnotationDescriptor? = null,
filtered: Boolean = true
): JCAnnotation? {
val annotationType = Type.getType(annotation.desc)
val fqName = treeMaker.getQualifiedName(annotationType)
if (filtered) {
if (BLACKLISTED_ANNOTATIONS.any { fqName.startsWith(it) }) return null
}
val ktAnnotation = (annotationDescriptor?.source as? PsiSourceElement)?.psi as? KtAnnotationEntry
val argMapping = ktAnnotation?.calleeExpression
?.getResolvedCall(kaptContext.bindingContext)?.valueArguments
?.mapKeys { it.key.name.asString() }
?: emptyMap()
val useSimpleName = '.' in fqName && fqName.substringBeforeLast('.', "") == packageFqName
val annotationFqName = when {
useSimpleName -> treeMaker.FqName(fqName.substring(packageFqName!!.length + 1))
else -> treeMaker.Type(annotationType)
}
val constantValues = pairedListToMap(annotation.values)
val values = if (argMapping.isNotEmpty()) {
argMapping.mapNotNull { (parameterName, arg) ->
if (arg is DefaultValueArgument) return@mapNotNull null
convertAnnotationArgumentWithName(constantValues[parameterName], arg, parameterName)
}
} else {
constantValues.mapNotNull { (parameterName, arg) ->
convertAnnotationArgumentWithName(arg, null, parameterName)
}
}
return treeMaker.Annotation(annotationFqName, JavacList.from(values))
}
private fun convertAnnotationArgumentWithName(constantValue: Any?, value: ResolvedValueArgument?, name: String): JCExpression? {
if (!isValidIdentifier(name)) return null
val expr = convertAnnotationArgument(constantValue, value) ?: return null
return treeMaker.Assign(treeMaker.SimpleName(name), expr)
}
private fun convertAnnotationArgument(constantValue: Any?, value: ResolvedValueArgument?): JCExpression? {
val args = value?.arguments?.mapNotNull { it.getArgumentExpression() } ?: emptyList()
val singleArg by lazy { args.singleOrNull() }
if (constantValue is Int) {
// This may be a resource identifier, we should not inline the id int
tryParseReferenceToAndroidResource(singleArg)?.let { return it }
}
fun tryParseTypeExpression(expression: KtExpression?): JCExpression? {
return when (expression) {
is KtSimpleNameExpression -> treeMaker.SimpleName(expression.getReferencedName())
is KtDotQualifiedExpression -> {
val selector = expression.selectorExpression as? KtSimpleNameExpression ?: return null
val receiver = tryParseTypeExpression(expression.receiverExpression) ?: return null
return treeMaker.Select(receiver, treeMaker.name(selector.getReferencedName()))
}
else -> null
}
}
fun tryParseTypeLiteralExpression(expression: KtExpression?): JCExpression? {
val literalExpression = expression as? KtClassLiteralExpression ?: return null
val typeExpression = tryParseTypeExpression(literalExpression.receiverExpression) ?: return null
return treeMaker.Select(typeExpression, treeMaker.name("class"))
}
// Unresolved class literal
if (constantValue == null && singleArg is KtClassLiteralExpression) {
tryParseTypeLiteralExpression(singleArg)?.let { return it }
}
// Some of class literals in vararg list are unresolved
if (args.isNotEmpty() && args[0] is KtClassLiteralExpression && constantValue is List<*> && args.size != constantValue.size) {
val literalExpressions = mapJList(args, ::tryParseTypeLiteralExpression)
if (literalExpressions.size == args.size) {
return treeMaker.NewArray(null, null, literalExpressions)
}
}
// Probably arrayOf(SomeUnresolvedType::class, ...)
if (constantValue is List<*>) {
val callArgs = when (singleArg) {
is KtCallExpression -> {
val resultingDescriptor = singleArg.getResolvedCall(kaptContext.bindingContext)?.resultingDescriptor
if (resultingDescriptor is FunctionDescriptor && resultingDescriptor.fqNameSafe.asString() == "kotlin.arrayOf")
singleArg.valueArguments.map { it.getArgumentExpression() }
else
null
}
is KtCollectionLiteralExpression -> singleArg.getInnerExpressions()
else -> null
}
// So we make sure something is absent in the constant value
if (callArgs != null && callArgs.size != constantValue.size) {
val literalExpressions = mapJList(callArgs, ::tryParseTypeLiteralExpression)
if (literalExpressions.size == callArgs.size) {
return treeMaker.NewArray(null, null, literalExpressions)
}
}
}
return convertLiteralExpression(constantValue)
}
private fun tryParseReferenceToAndroidResource(expression: KtExpression?): JCExpression? {
val bindingContext = kaptContext.bindingContext
val expressionToResolve = when (expression) {
is KtDotQualifiedExpression -> expression.selectorExpression
else -> expression
}
val resolvedCall = expressionToResolve.getResolvedCall(bindingContext) ?: return null
val fqName = resolvedCall.resultingDescriptor.fqNameOrNull() ?: return null
val jcExpression = treeMaker.FqName(fqName)
return if (doesLookLikeAndroidIdentifier(jcExpression)) jcExpression else null
}
private fun doesLookLikeAndroidIdentifier(expression: JCExpression): Boolean {
// 'expression' here is always a fqName, so we can forget about imports here
val rId = (expression as? JCFieldAccess)?.selected ?: return false
val r = (rId as? JCFieldAccess)?.selected ?: return false
return when {
r is JCIdent && r.name.toString() == "R" -> true
r is JCFieldAccess && r.name.toString() == "R" -> true
else -> false
}
}
private fun convertValueOfPrimitiveTypeOrString(value: Any?): JCExpression? {
return when (value) {
is Char -> treeMaker.Literal(TypeTag.CHAR, value.toInt())
is Byte -> treeMaker.TypeCast(treeMaker.TypeIdent(TypeTag.BYTE), treeMaker.Literal(TypeTag.INT, value.toInt()))
is Short -> treeMaker.TypeCast(treeMaker.TypeIdent(TypeTag.SHORT), treeMaker.Literal(TypeTag.INT, value.toInt()))
is Boolean, is Int, is Long, is Float, is Double, is String -> treeMaker.Literal(value)
else -> null
}
}
private fun convertLiteralExpression(value: Any?): JCExpression {
convertValueOfPrimitiveTypeOrString(value)?.let { return it }
return when (value) {
null -> treeMaker.Literal(TypeTag.BOT, null)
is ByteArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is BooleanArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is CharArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is ShortArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is IntArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is LongArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is FloatArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is DoubleArray -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value.asIterable()) { convertLiteralExpression(it) })
is Array<*> -> { // Two-element String array for enumerations ([desc, fieldName])
assert(value.size == 2)
val enumType = Type.getType(value[0] as String)
val valueName = (value[1] as String).takeIf { isValidIdentifier(it) } ?: run {
kaptContext.compiler.log.report(kaptContext.kaptError("'${value[1]}' is an invalid Java enum value name"))
"InvalidFieldName"
}
treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName))
}
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapJList(value) { convertLiteralExpression(it) })
is Type -> treeMaker.Select(treeMaker.Type(value), treeMaker.name("class"))
is AnnotationNode -> convertAnnotation(value, packageFqName = null, filtered = false)!!
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value::class.java.canonicalName})")
}
}
private fun getDefaultValue(type: Type): Any? = when (type) {
Type.BYTE_TYPE -> 0
Type.BOOLEAN_TYPE -> false
Type.CHAR_TYPE -> '\u0000'
Type.SHORT_TYPE -> 0
Type.INT_TYPE -> 0
Type.LONG_TYPE -> 0L
Type.FLOAT_TYPE -> 0.0F
Type.DOUBLE_TYPE -> 0.0
else -> null
}
}
private val ClassDescriptor.isNested: Boolean
get() = containingDeclaration is ClassDescriptor
@@ -0,0 +1,419 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.stubs
import com.sun.tools.javac.code.BoundKind
import com.sun.tools.javac.code.TypeTag
import com.sun.tools.javac.tree.JCTree.*
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
import java.util.*
import org.jetbrains.kotlin.kapt3.stubs.ElementKind.*
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.mapJList
import org.jetbrains.kotlin.kapt3.mapJListIndexed
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
import com.sun.tools.javac.util.List as JavacList
/*
Root (Class)
* TypeParameter
+ SuperClass
* Interface
Root (Method)
* TypeParameter
* ParameterType
+ ReturnType
* ExceptionType
Root (Field)
+ SuperClass
TypeParameter < Root
+ ClassBound
* InterfaceBound
ParameterType < Root
+ Type
ReturnType < Root
+ Type
Type :: ClassType | TypeVariable | PrimitiveType | ArrayType
ClassBound < TypeParameter
+ ClassType
InterfaceBound < TypeParameter
? ClassType
? TypeVariable
TypeVariable < InterfaceBound
SuperClass < TopLevel
! ClassType
Interface < TopLevel
! ClassType
ClassType < *
* TypeArgument
* InnerClass
InnerClass < ClassType
! TypeArgument
TypeArgument < ClassType | InnerClass
+ ClassType
*/
internal enum class ElementKind {
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, TypeArgument, ParameterType, ReturnType, ExceptionType,
ClassType, InnerClass, TypeVariable, PrimitiveType, ArrayType
}
private class SignatureNode(val kind: ElementKind, val name: String? = null) {
val children: MutableList<SignatureNode> = SmartList<SignatureNode>()
}
class SignatureParser(val treeMaker: KaptTreeMaker) {
class ClassGenericSignature(
val typeParameters: JavacList<JCTypeParameter>,
val superClass: JCExpression,
val interfaces: JavacList<JCExpression>
)
class MethodGenericSignature(
val typeParameters: JavacList<JCTypeParameter>,
val parameterTypes: JavacList<JCVariableDecl>,
val exceptionTypes: JavacList<JCExpression>,
val returnType: JCExpression?
)
fun parseClassSignature(
signature: String?,
rawSuperClass: JCExpression,
rawInterfaces: JavacList<JCExpression>
): ClassGenericSignature {
if (signature == null) {
return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces)
}
val root = parse(signature)
val typeParameters = smartList()
val superClasses = smartList()
val interfaces = smartList()
root.split(typeParameters, TypeParameter, superClasses, SuperClass, interfaces, Interface)
val jcTypeParameters = mapJList(typeParameters) { parseTypeParameter(it) }
val jcSuperClass = parseType(superClasses.single().children.single())
val jcInterfaces = mapJList(interfaces) { parseType(it.children.single()) }
return ClassGenericSignature(jcTypeParameters, jcSuperClass, jcInterfaces)
}
fun parseMethodSignature(
signature: String?,
rawParameters: JavacList<JCVariableDecl>,
rawExceptionTypes: JavacList<JCExpression>,
rawReturnType: JCExpression?,
nonErrorParameterTypeProvider: (Int, () -> JCExpression) -> JCExpression
): MethodGenericSignature {
if (signature == null) {
val parameters = mapJListIndexed(rawParameters) { index, it ->
val nonErrorType = nonErrorParameterTypeProvider(index) { it.vartype }
treeMaker.VarDef(it.modifiers, it.getName(), nonErrorType, it.initializer)
}
return MethodGenericSignature(JavacList.nil(), parameters, rawExceptionTypes, rawReturnType)
}
val root = parse(signature)
val typeParameters = smartList()
val parameterTypes = smartList()
val exceptionTypes = smartList()
val returnTypes = smartList()
root.split(typeParameters, TypeParameter, parameterTypes, ParameterType, exceptionTypes, ExceptionType, returnTypes, ReturnType)
val jcTypeParameters = mapJList(typeParameters) { parseTypeParameter(it) }
assert(rawParameters.size >= parameterTypes.size)
val offset = rawParameters.size - parameterTypes.size
val jcParameters = mapJListIndexed(parameterTypes) { index, it ->
val rawParameter = rawParameters[index + offset]
val nonErrorType = nonErrorParameterTypeProvider(index) { parseType(it.children.single()) }
treeMaker.VarDef(rawParameter.modifiers, rawParameter.getName(), nonErrorType, rawParameter.initializer)
}
val jcExceptionTypes = mapJList(exceptionTypes) { parseType(it) }
val jcReturnType = if (rawReturnType == null) null else parseType(returnTypes.single().children.single())
return MethodGenericSignature(jcTypeParameters, jcParameters, jcExceptionTypes, jcReturnType)
}
fun parseFieldSignature(
signature: String?,
rawType: JCExpression
): JCExpression {
if (signature == null) return rawType
val root = parse(signature)
val superClass = root.children.single()
assert(superClass.kind == SuperClass)
return parseType(superClass.children.single())
}
private fun parseTypeParameter(node: SignatureNode): JCTypeParameter {
assert(node.kind == TypeParameter)
val classBounds = smartList()
val interfaceBounds = smartList()
node.split(classBounds, ClassBound, interfaceBounds, InterfaceBound)
assert(classBounds.size <= 1)
val jcClassBound = classBounds.firstOrNull()?.let { parseBound(it) }
val jcInterfaceBounds = mapJList(interfaceBounds) { parseBound(it) }
val allBounds = if (jcClassBound != null) jcInterfaceBounds.prepend(jcClassBound) else jcInterfaceBounds
return treeMaker.TypeParameter(treeMaker.name(node.name!!), allBounds)
}
private fun parseBound(node: SignatureNode): JCExpression {
assert(node.kind == ClassBound || node.kind == InterfaceBound)
return parseType(node.children.single())
}
private fun parseType(node: SignatureNode): JCExpression {
val kind = node.kind
return when (kind) {
ClassType -> {
val typeArgs = mutableListOf<SignatureNode>()
val innerClasses = mutableListOf<SignatureNode>()
node.split(typeArgs, TypeArgument, innerClasses, InnerClass)
var expression = makeExpressionForClassTypeWithArguments(treeMaker.FqName(node.name!!), typeArgs)
if (innerClasses.isEmpty()) return expression
for (innerClass in innerClasses) {
expression = makeExpressionForClassTypeWithArguments(
treeMaker.Select(expression, treeMaker.name(innerClass.name!!)),
innerClass.children)
}
expression
}
TypeVariable -> treeMaker.SimpleName(node.name!!)
ArrayType -> treeMaker.TypeArray(parseType(node.children.single()))
PrimitiveType -> {
val typeTag = when (node.name!!.single()) {
'V' -> TypeTag.VOID
'Z' -> TypeTag.BOOLEAN
'C' -> TypeTag.CHAR
'B' -> TypeTag.BYTE
'S' -> TypeTag.SHORT
'I' -> TypeTag.INT
'F' -> TypeTag.FLOAT
'J' -> TypeTag.LONG
'D' -> TypeTag.DOUBLE
else -> error("Illegal primitive type ${node.name}")
}
treeMaker.TypeIdent(typeTag)
}
else -> error("Unsupported type: $node")
}
}
private fun makeExpressionForClassTypeWithArguments(fqNameExpression: JCExpression, args: List<SignatureNode>): JCExpression {
if (args.isEmpty()) return fqNameExpression
return treeMaker.TypeApply(fqNameExpression, mapJList(args) { arg ->
assert(arg.kind == TypeArgument) { "Unexpected kind ${arg.kind}, $TypeArgument expected" }
val variance = arg.name ?: return@mapJList treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
val argType = parseType(arg.children.single())
when (variance.single()) {
'=' -> argType
'+' -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.EXTENDS), argType)
'-' -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.SUPER), argType)
else -> error("Unknown variance, '=', '+' or '-' expected")
}
})
}
private fun parse(signature: String): SignatureNode {
val parser = SignatureParserVisitor()
SignatureReader(signature).accept(parser)
return parser.root
}
}
private fun smartList() = SmartList<SignatureNode>()
private fun SignatureNode.split(l1: MutableList<SignatureNode>, e1: ElementKind, l2: MutableList<SignatureNode>, e2: ElementKind) {
for (child in children) {
val kind = child.kind
when (kind) {
e1 -> l1 += child
e2 -> l2 += child
else -> error("Unknown kind: $kind")
}
}
}
private fun SignatureNode.split(
l1: MutableList<SignatureNode>,
e1: ElementKind,
l2: MutableList<SignatureNode>,
e2: ElementKind,
l3: MutableList<SignatureNode>,
e3: ElementKind
) {
for (child in children) {
val kind = child.kind
when (kind) {
e1 -> l1 += child
e2 -> l2 += child
e3 -> l3 += child
else -> error("Unknown kind: $kind")
}
}
}
private fun SignatureNode.split(
l1: MutableList<SignatureNode>,
e1: ElementKind,
l2: MutableList<SignatureNode>,
e2: ElementKind,
l3: MutableList<SignatureNode>,
e3: ElementKind,
l4: MutableList<SignatureNode>,
e4: ElementKind
) {
for (child in children) {
val kind = child.kind
when (kind) {
e1 -> l1 += child
e2 -> l2 += child
e3 -> l3 += child
e4 -> l4 += child
else -> error("Unknown kind: $kind")
}
}
}
private class SignatureParserVisitor : SignatureVisitor(Opcodes.ASM5) {
val root = SignatureNode(Root)
private val stack = ArrayDeque<SignatureNode>(5).apply { add(root) }
private fun popUntil(kind: ElementKind?) {
if (kind != null) {
while (stack.peek().kind != kind) {
stack.pop()
}
}
}
private fun popUntil(vararg kinds: ElementKind) {
while (stack.peek().kind !in kinds) {
stack.pop()
}
}
private fun push(kind: ElementKind, parent: ElementKind? = null, name: String? = null) {
popUntil(parent)
val newNode = SignatureNode(kind, name)
stack.peek().children += newNode
stack.push(newNode)
}
override fun visitSuperclass(): SignatureVisitor {
push(SuperClass, parent = Root)
return super.visitSuperclass()
}
override fun visitInterface(): SignatureVisitor {
push(Interface, parent = Root)
return super.visitInterface()
}
override fun visitFormalTypeParameter(name: String) {
push(TypeParameter, parent = Root, name = name)
}
override fun visitClassBound(): SignatureVisitor {
push(ClassBound, parent = TypeParameter)
return super.visitClassBound()
}
override fun visitInterfaceBound(): SignatureVisitor {
push(InterfaceBound, parent = TypeParameter)
return super.visitInterfaceBound()
}
override fun visitTypeArgument() {
popUntil(ClassType, InnerClass)
push(TypeArgument)
}
override fun visitTypeArgument(variance: Char): SignatureVisitor {
popUntil(ClassType, InnerClass)
push(TypeArgument, name = variance.toString())
return super.visitTypeArgument(variance)
}
override fun visitInnerClassType(name: String) {
push(InnerClass, name = name, parent = ClassType)
}
override fun visitParameterType(): SignatureVisitor {
push(ParameterType, parent = Root)
return super.visitParameterType()
}
override fun visitReturnType(): SignatureVisitor {
push(ReturnType, parent = Root)
return super.visitReturnType()
}
override fun visitExceptionType(): SignatureVisitor {
push(ExceptionType, parent = Root)
return super.visitExceptionType()
}
override fun visitClassType(name: String) {
push(ClassType, name = name)
}
override fun visitTypeVariable(name: String) {
push(TypeVariable, name = name)
}
override fun visitBaseType(descriptor: Char) {
push(PrimitiveType, name = descriptor.toString())
}
override fun visitArrayType(): SignatureVisitor {
push(ArrayType)
return super.visitArrayType()
}
override fun visitEnd() {
while (stack.peek().kind != ClassType) {
stack.pop()
}
stack.pop()
}
}
@@ -0,0 +1,153 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.stubs
import com.sun.tools.javac.code.BoundKind
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.state.updateArgumentModeFromAnnotations
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.kapt3.mapJList
import org.jetbrains.kotlin.kapt3.mapJListIndexed
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.isError
internal fun convertKtType(
reference: KtTypeReference?,
converter: ClassFileToSourceStubConverter,
shouldBeBoxed: Boolean = false,
gotTypeElement: KtTypeElement? = null
): JCTree.JCExpression {
val type = gotTypeElement ?: reference?.typeElement
if (reference != null) {
val kotlinType = converter.kaptContext.bindingContext[BindingContext.TYPE, reference]
if (kotlinType != null && !kotlinType.containsErrorTypes()) {
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
converter.kaptContext.generationState.typeMapper.mapType(kotlinType, signatureWriter,
if (shouldBeBoxed) TypeMappingMode.GENERIC_ARGUMENT else TypeMappingMode.DEFAULT)
return SignatureParser(converter.treeMaker).parseFieldSignature(
signatureWriter.toString(), getDefaultTypeForUnknownType(converter))
}
}
return when (type) {
is KtUserType -> convertUserType(type, converter, reference)
is KtNullableType -> {
// Prevent infinite recursion
val innerType = type.innerType ?: return getDefaultTypeForUnknownType(converter)
convertKtType(reference, converter, shouldBeBoxed = true, gotTypeElement = innerType)
}
is KtFunctionType -> convertFunctionType(type, converter)
else -> getDefaultTypeForUnknownType(converter)
}
}
private fun getDefaultTypeForUnknownType(converter: ClassFileToSourceStubConverter) = converter.treeMaker.FqName("error.NonExistentClass")
private fun convertUserType(type: KtUserType, converter: ClassFileToSourceStubConverter, reference: KtTypeReference?): JCTree.JCExpression {
val qualifierExpression = type.qualifier?.let { convertUserType(it, converter, null) }
val referencedName = type.referencedName ?: "error"
val treeMaker = converter.treeMaker
val baseExpression = if (qualifierExpression == null) {
// This could be List<SomeErrorType> or similar. List should be converted to java.util.List in this case.
val referenceTarget = converter.kaptContext.bindingContext[BindingContext.REFERENCE_TARGET, type.referenceExpression]
if (referenceTarget is ClassDescriptor) {
treeMaker.FqName(converter.kaptContext.generationState.typeMapper.mapType(referenceTarget.defaultType).internalName)
}
else {
treeMaker.SimpleName(referencedName)
}
} else {
treeMaker.Select(qualifierExpression, treeMaker.name(referencedName))
}
val arguments = type.typeArguments
if (arguments.isEmpty()) {
return baseExpression
}
val baseType = reference?.let { converter.kaptContext.bindingContext[BindingContext.TYPE, it] }
return treeMaker.TypeApply(baseExpression, mapJListIndexed(arguments) { index, projection ->
val argumentType = projection.typeReference?.let { converter.kaptContext.bindingContext[BindingContext.TYPE, it] }
val typeParameter = argumentType?.constructor?.parameters?.getOrNull(index)
val argument = baseType?.arguments?.getOrNull(index)
val variance = if (argument != null && typeParameter != null) {
val argumentMode = TypeMappingMode.GENERIC_ARGUMENT.updateArgumentModeFromAnnotations(argument.type)
KotlinTypeMapper.getVarianceForWildcard(typeParameter, argument, argumentMode)
}
else {
null
}
convertTypeProjection(projection, variance, converter)
})
}
private fun convertTypeProjection(type: KtTypeProjection, variance: Variance?, converter: ClassFileToSourceStubConverter): JCTree.JCExpression {
val reference = type.typeReference
val treeMaker = converter.treeMaker
val projectionKind = type.projectionKind
if (variance === Variance.INVARIANT) {
return convertKtType(reference, converter, shouldBeBoxed = true)
}
return when {
projectionKind === KtProjectionKind.STAR -> treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.UNBOUND), null)
projectionKind === KtProjectionKind.IN || variance === Variance.IN_VARIANCE ->
treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.SUPER), convertKtType(reference, converter, shouldBeBoxed = true))
projectionKind === KtProjectionKind.OUT || variance === Variance.OUT_VARIANCE ->
treeMaker.Wildcard(treeMaker.TypeBoundKind(BoundKind.EXTENDS), convertKtType(reference, converter, shouldBeBoxed = true))
else -> convertKtType(reference, converter, shouldBeBoxed = true) // invariant
}
}
private fun convertFunctionType(type: KtFunctionType, converter: ClassFileToSourceStubConverter): JCTree.JCExpression {
val receiverType = type.receiverTypeReference
var parameterTypes = mapJList(type.parameters) { convertKtType(it.typeReference, converter) }
val returnType = convertKtType(type.returnTypeReference, converter)
if (receiverType != null) {
parameterTypes = parameterTypes.prepend(convertKtType(receiverType, converter))
}
parameterTypes = parameterTypes.append(returnType)
val treeMaker = converter.treeMaker
return treeMaker.TypeApply(treeMaker.SimpleName("Function" + (parameterTypes.size - 1)), parameterTypes)
}
fun KotlinType.containsErrorTypes(allowedDepth: Int = 10): Boolean {
// Need to limit recursion depth in case of complex recursive generics
if (allowedDepth <= 0) {
return false
}
if (this.isError) return true
if (this.arguments.any { !it.isStarProjection && it.type.containsErrorTypes(allowedDepth - 1) }) return true
return false
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.stubs
import org.jetbrains.kotlin.kapt3.util.isAbstract
import org.jetbrains.kotlin.kapt3.util.isEnum
import org.jetbrains.kotlin.kapt3.util.isJvmOverloadsGenerated
import org.jetbrains.kotlin.kapt3.util.isStatic
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AnnotationNode
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.*
internal class ParameterInfo(
val flags: Long,
val name: String,
val type: Type,
val visibleAnnotations: List<AnnotationNode>?,
val invisibleAnnotations: List<AnnotationNode>?)
internal fun MethodNode.getParametersInfo(containingClass: ClassNode): List<ParameterInfo> {
val localVariables = this.localVariables ?: emptyList()
val parameters = this.parameters ?: emptyList()
val isStatic = isStatic(access)
val isJvmOverloads = this.isJvmOverloadsGenerated()
// First and second parameters in enum constructors are synthetic, we should ignore them
val isEnumConstructor = (name == "<init>") && containingClass.isEnum()
val startParameterIndex = if (isEnumConstructor) 2 else 0
val parameterTypes = Type.getArgumentTypes(desc)
val parameterInfos = ArrayList<ParameterInfo>(parameterTypes.size - startParameterIndex)
for (index in startParameterIndex..parameterTypes.lastIndex) {
val type = parameterTypes[index]
// Use parameters only in case of the abstract methods (it hasn't local variables table)
var name: String? = if (isAbstract(this.access) && this.name != "<init>")
parameters.getOrNull(index - startParameterIndex)?.name
else
null
val localVariableIndexOffset = when {
isStatic -> 0
isJvmOverloads -> 0
else -> 1
}
// @JvmOverloads constructors and ordinary methods don't have "this" local variable
name = name ?: localVariables.getOrNull(index + localVariableIndexOffset)?.name
?: "p${index - startParameterIndex}"
// Property setters has bad parameter names
if (name.startsWith("<") && name.endsWith(">")) {
name = "p${index - startParameterIndex}"
}
val visibleAnnotations = visibleParameterAnnotations?.get(index)
val invisibleAnnotations = invisibleParameterAnnotations?.get(index)
parameterInfos += ParameterInfo(0, name, type, visibleAnnotations, invisibleAnnotations)
}
return parameterInfos
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.util
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import java.io.PrintWriter
import java.io.StringWriter
class KaptLogger(
val isVerbose: Boolean,
val messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, isVerbose)
) {
private companion object {
val PREFIX = "[kapt] "
}
fun info(message: String) {
if (isVerbose) {
messageCollector.report(CompilerMessageSeverity.INFO, PREFIX + message)
}
}
inline fun info(message: () -> String) {
if (isVerbose) {
info(message())
}
}
fun warn(message: String) {
messageCollector.report(CompilerMessageSeverity.WARNING, PREFIX + message)
}
fun error(message: String) {
messageCollector.report(CompilerMessageSeverity.ERROR, PREFIX + message)
}
fun exception(e: Throwable) {
val stacktrace = run {
val writer = StringWriter()
e.printStackTrace(PrintWriter(writer))
writer.toString()
}
messageCollector.report(CompilerMessageSeverity.ERROR, PREFIX + "An exception occurred: " + stacktrace)
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.util
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import java.io.Writer
class MessageCollectorBackedWriter(val messageCollector: MessageCollector, val severity: CompilerMessageSeverity) : Writer() {
override fun write(buffer: CharArray, offset: Int, length: Int) {
messageCollector.report(severity, String(buffer, offset, length))
}
override fun flush() {
if (messageCollector is GroupingMessageCollector) {
messageCollector.flush()
}
}
override fun close() {
flush()
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.util
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AnnotationNode
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.org.objectweb.asm.tree.FieldNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
internal fun isEnum(access: Int) = (access and Opcodes.ACC_ENUM) != 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 isPrivate(access: Int) = (access and Opcodes.ACC_PRIVATE) != 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 isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) != 0
internal fun ClassNode.isEnum() = (access and Opcodes.ACC_ENUM) != 0
internal fun ClassNode.isAnnotation() = (access and Opcodes.ACC_ANNOTATION) != 0
internal fun MethodNode.isVarargs() = (access and Opcodes.ACC_VARARGS) != 0
internal fun FieldNode.isEnumValue() = (access and Opcodes.ACC_ENUM) != 0
internal fun <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
internal fun MethodNode.isJvmOverloadsGenerated(): Boolean {
return (invisibleAnnotations?.any { it.isJvmOverloadsGenerated() } ?: false)
|| (visibleAnnotations?.any { it.isJvmOverloadsGenerated() } ?: false)
}
// Constant from DefaultParameterValueSubstitutor can't be used in Maven build because of ProGuard
// rename this as well
private val ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS: String =
Type.getObjectType("synthetic/kotlin/jvm/GeneratedByJvmOverloads").descriptor
private fun AnnotationNode.isJvmOverloadsGenerated(): Boolean {
return this.desc == ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.util
import com.intellij.openapi.util.SystemInfo
import com.sun.tools.javac.main.Option
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.util.Options
import com.sun.tools.javac.util.List as JavacList
import org.jetbrains.kotlin.kapt3.plus
internal val isJava9OrLater: Boolean
get() = SystemInfo.isJavaVersionAtLeast("9")
internal fun Options.putJavacOption(jdk8Name: String, jdk9Name: String, value: String) {
val option = if (isJava9OrLater) {
Option.valueOf(jdk9Name)
}
else {
Option.valueOf(jdk8Name)
}
put(option, value)
}
internal fun TreeMaker.TopLevelJava9Aware(packageClause: JCTree.JCExpression?, declarations: JavacList<JCTree>): JCTree.JCCompilationUnit {
return if (isJava9OrLater) {
val topLevelMethod = TreeMaker::class.java.declaredMethods.single { it.name == "TopLevel" }
val packageDecl: JCTree? = packageClause?.let {
val packageDeclMethod = TreeMaker::class.java.methods.single { it.name == "PackageDecl" }
packageDeclMethod.invoke(this, JavacList.nil<JCTree>(), packageClause) as JCTree
}
val allDeclarations = if (packageDecl != null) JavacList.of(packageDecl) + declarations else declarations
topLevelMethod.invoke(this, allDeclarations) as JCTree.JCCompilationUnit
}
else {
TopLevel(JavacList.nil(), packageClause, declarations)
}
}
internal fun JCTree.JCCompilationUnit.getPackageNameJava9Aware(): JCTree? {
return if (isJava9OrLater) {
JCTree.JCCompilationUnit::class.java.getDeclaredMethod("getPackageName").invoke(this) as JCTree?
}
else {
this.packageName
}
}
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3
import com.sun.tools.javac.util.List as JavacList
internal inline fun <T, R> mapJList(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
if (values == null) return JavacList.nil()
var result = JavacList.nil<R>()
for (item in values) {
f(item)?.let { result = result.append(it) }
}
return result
}
internal inline fun <T, R> mapJListIndexed(values: Iterable<T>?, f: (Int, T) -> R?): JavacList<R> {
if (values == null) return JavacList.nil()
var result = JavacList.nil<R>()
values.forEachIndexed { index, item ->
f(index, item)?.let { result = result.append(it) }
}
return result
}
internal inline fun <T> mapPairedValuesJList(valuePairs: List<Any>?, f: (String, Any) -> T?): JavacList<T> {
if (valuePairs == null || valuePairs.isEmpty()) return JavacList.nil()
val size = valuePairs.size
var result = JavacList.nil<T>()
assert(size % 2 == 0)
var index = 0
while (index < size) {
val key = valuePairs[index] as String
val value = valuePairs[index + 1]
f(key, value)?.let { result = result.prepend(it) }
index += 2
}
return result.reverse()
}
internal fun pairedListToMap(valuePairs: List<Any>?): Map<String, Any?> {
val map = mutableMapOf<String, Any?>()
mapPairedValuesJList(valuePairs) { key, value ->
map.put(key, value)
}
return map
}
internal operator fun <T : Any> JavacList<T>.plus(other: JavacList<T>): JavacList<T> {
return this.appendList(other)
}
@@ -0,0 +1,200 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.util.text.StringUtil
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.GenerationUtils
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.kapt3.AbstractKapt3Extension
import org.jetbrains.kotlin.kapt3.AptMode.STUBS_AND_APT
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.nio.file.Files
import javax.annotation.processing.Completion
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.SourceVersion
import javax.lang.model.element.AnnotationMirror
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement
import com.sun.tools.javac.util.List as JavacList
abstract class AbstractKotlinKapt3IntegrationTest : CodegenTestCase() {
private companion object {
val TEST_DATA_DIR = File("plugins/kapt3/kapt3-compiler/testData/kotlinRunner")
}
private var _processors: List<Processor>? = null
private val processors get() = _processors!!
private var _options: Map<String, String>? = null
private val options get() = _options!!
override fun tearDown() {
_processors = null
_options = null
super.tearDown()
}
protected fun test(
name: String,
vararg supportedAnnotations: String,
options: Map<String, String> = emptyMap(),
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit
) = testAP(true, name, options, process, *supportedAnnotations)
protected fun testAP(
shouldRun: Boolean,
name: String,
options: Map<String, String>,
process: (Set<TypeElement>, RoundEnvironment, ProcessingEnvironment) -> Unit,
vararg supportedAnnotations: String
) {
this._options = options
val ktFileName = File(TEST_DATA_DIR, name + ".kt")
var started = false
val processor = object : Processor {
lateinit var processingEnv: ProcessingEnvironment
override fun getSupportedOptions() = options.keys
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
if (!roundEnv.processingOver()) {
started = true
process(annotations, roundEnv, processingEnv)
}
return true
}
override fun init(env: ProcessingEnvironment) {
processingEnv = env
}
override fun getCompletions(
element: Element?,
annotation: AnnotationMirror?,
member: ExecutableElement?,
userText: String?
): Iterable<Completion>? {
return emptyList()
}
override fun getSupportedSourceVersion() = SourceVersion.RELEASE_6
override fun getSupportedAnnotationTypes() = supportedAnnotations.toSet()
}
_processors = listOf(processor)
doTest(ktFileName.canonicalPath)
if (started != shouldRun) {
fail("Annotation processor " + (if (shouldRun) "was not started" else "was started"))
}
}
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray()
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".it.txt")
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
val stubsDir = Files.createTempDirectory("kaptStubs").toFile()
val incrementalDataDir = Files.createTempDirectory("kaptIncrementalData").toFile()
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
val kapt3Extension = Kapt3ExtensionForTests(processors, javaSources.toList(), sourceOutputDir, this.options,
stubsOutputDir = stubsDir, incrementalDataOutputDir = incrementalDataDir)
AnalysisHandlerExtension.registerExtension(myEnvironment.project, kapt3Extension)
try {
loadMultiFiles(files)
GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, Kapt3BuilderFactory()).factory
val actualRaw = kapt3Extension.savedStubs ?: error("Stubs were not saved")
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' }))
.trimTrailingWhitespacesAndAddNewlineAtEOF()
.let { AbstractClassFileToSourceStubConverterTest.removeMetadataAnnotationContents(it) }
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
} finally {
sourceOutputDir.deleteRecursively()
incrementalDataDir.deleteRecursively()
}
}
protected class Kapt3ExtensionForTests(
private val processors: List<Processor>,
javaSourceRoots: List<File>,
outputDir: File,
options: Map<String, String>,
stubsOutputDir: File,
incrementalDataOutputDir: File
) : AbstractKapt3Extension(PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
emptyList(), javaSourceRoots, outputDir, outputDir,
stubsOutputDir, incrementalDataOutputDir, options, emptyMap(), "", STUBS_AND_APT, System.currentTimeMillis(),
KaptLogger(true), correctErrorTypes = true, compilerConfiguration = CompilerConfiguration.EMPTY
) {
internal var savedStubs: String? = null
internal var savedBindings: Map<String, KaptJavaFileObject>? = null
override fun loadProcessors() = processors
override fun saveStubs(stubs: JavacList<JCTree.JCCompilationUnit>) {
if (this.savedStubs != null) {
error("Stubs are already saved")
}
this.savedStubs = stubs
.map { it.toString() }
.sorted()
.joinToString(AbstractKotlinKapt3Test.FILE_SEPARATOR)
super.saveStubs(stubs)
}
override fun saveIncrementalData(
kaptContext: KaptContext<GenerationState>,
messageCollector: MessageCollector,
converter: ClassFileToSourceStubConverter
) {
if (this.savedBindings != null) {
error("Bindings are already saved")
}
this.savedBindings = converter.bindings
super.saveIncrementalData(kaptContext, messageCollector, converter)
}
}
}
@@ -0,0 +1,166 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.util.text.StringUtil
import com.sun.tools.javac.comp.CompileStates
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit
import com.sun.tools.javac.util.JCDiagnostic
import com.sun.tools.javac.util.Log
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.GenerationUtils
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
import org.jetbrains.kotlin.kapt3.javac.KaptJavaLog
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.nio.file.Files
import java.util.*
import com.sun.tools.javac.util.List as JavacList
abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
companion object {
val FILE_SEPARATOR = "\n\n////////////////////\n\n"
val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
}
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray()
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
// Use light analysis mode in tests
AnalysisHandlerExtension.registerExtension(myEnvironment.project, PartialAnalysisHandlerExtension())
loadMultiFiles(files)
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt")
val classBuilderFactory = Kapt3BuilderFactory()
val generationState = GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, classBuilderFactory)
val logger = KaptLogger(isVerbose = true, messageCollector = messageCollector)
val kaptContext = KaptContext(logger, generationState.project, generationState.bindingContext, classBuilderFactory.compiledClasses,
classBuilderFactory.origins, generationState, processorOptions = emptyMap())
try {
check(kaptContext, txtFile, wholeFile)
} finally {
kaptContext.close()
}
}
protected fun convert(
kaptContext: KaptContext<GenerationState>,
generateNonExistentClass: Boolean,
correctErrorTypes: Boolean
): JavacList<JCCompilationUnit> {
val converter = ClassFileToSourceStubConverter(kaptContext, generateNonExistentClass, correctErrorTypes)
return converter.convert()
}
protected abstract fun check(
kaptContext: KaptContext<GenerationState>,
txtFile: File,
wholeFile: File)
}
abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test() {
internal companion object {
private val KOTLIN_METADATA_GROUP = "[a-z0-9]+ = (\\{.+?\\}|[0-9]+)"
private val KOTLIN_METADATA_REGEX = "@kotlin\\.Metadata\\(($KOTLIN_METADATA_GROUP)(, $KOTLIN_METADATA_GROUP)*\\)".toRegex()
fun removeMetadataAnnotationContents(s: String): String = s.replace(KOTLIN_METADATA_REGEX, "@kotlin.Metadata()")
}
override fun check(kaptContext: KaptContext<GenerationState>, txtFile: File, wholeFile: File) {
fun isOptionSet(name: String) = wholeFile.useLines { lines -> lines.any { it.trim() == "// $name" } }
fun getOptionValues(name: String) = wholeFile.useLines { lines ->
lines.filter { it.startsWith("// $name") }
.map { it.drop(name.length + 3).trim() }
.filter { it.isNotEmpty() }
.toList()
}
val generateNonExistentClass = isOptionSet("NON_EXISTENT_CLASS")
val correctErrorTypes = isOptionSet("CORRECT_ERROR_TYPES")
val validate = !isOptionSet("NO_VALIDATION")
val expectedErrors = getOptionValues("EXPECTED_ERROR").sorted()
val javaFiles = convert(kaptContext, generateNonExistentClass, correctErrorTypes)
kaptContext.javaLog.interceptorData.files = javaFiles.map { it.sourceFile to it }.toMap()
if (validate) kaptContext.compiler.enterTrees(javaFiles)
val actualRaw = javaFiles.sortedBy { it.sourceFile.name }.joinToString (FILE_SEPARATOR)
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' }))
.trimTrailingWhitespacesAndAddNewlineAtEOF()
.let { removeMetadataAnnotationContents(it) }
if (kaptContext.compiler.shouldStop(CompileStates.CompileState.ENTER)) {
val log = Log.instance(kaptContext.context) as KaptJavaLog
val actualErrors = log.reportedDiagnostics
.filter { it.type == JCDiagnostic.DiagnosticType.ERROR }
.map { it.getMessage(Locale.US).lines().first() }
.sorted()
log.flush()
if (expectedErrors.isEmpty()) {
error("There were errors during analysis. See errors above. Stubs:\n\n$actual")
} else if (actualErrors != expectedErrors) {
error("Expected error matching assertion. Expected: \n"
+ expectedErrors.joinToString("\n") { "'$it'" }
+ "\n, found: \n"
+ actualErrors.joinToString("\n") { "'$it'" })
}
}
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
}
}
abstract class AbstractKotlinKaptContextTest : AbstractKotlinKapt3Test() {
override fun check(kaptContext: KaptContext<GenerationState>, txtFile: File, wholeFile: File) {
val compilationUnits = convert(kaptContext, generateNonExistentClass = false, correctErrorTypes = true)
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
try {
kaptContext.doAnnotationProcessing(emptyList(), listOf(JavaKaptContextTest.simpleProcessor()),
compileClasspath = PathUtil.getJdkClassesRootsFromCurrentJre() + PathUtil.kotlinPathsForIdeaPlugin.stdlibPath,
annotationProcessingClasspath = emptyList(), annotationProcessors = "",
sourcesOutputDir = sourceOutputDir, classesOutputDir = sourceOutputDir,
additionalSources = compilationUnits, withJdk = true)
val javaFiles = sourceOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" }
val actualRaw = javaFiles.sortedBy { it.name }.joinToString(FILE_SEPARATOR) { it.name + ":\n\n" + it.readText() }
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF()
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
} finally {
sourceOutputDir.deleteRecursively()
}
}
}
@@ -0,0 +1,320 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/kapt3/kapt3-compiler/testData/converter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFileToSourceStubConverterTest {
@TestMetadata("abstractEnum.kt")
public void testAbstractEnum() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/abstractEnum.kt");
doTest(fileName);
}
@TestMetadata("abstractMethods.kt")
public void testAbstractMethods() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/abstractMethods.kt");
doTest(fileName);
}
public void testAllFilesPresentInConverter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/kapt3-compiler/testData/converter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/annotations.kt");
doTest(fileName);
}
@TestMetadata("annotations2.kt")
public void testAnnotations2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/annotations2.kt");
doTest(fileName);
}
@TestMetadata("dataClass.kt")
public void testDataClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/dataClass.kt");
doTest(fileName);
}
@TestMetadata("defaultImpls.kt")
public void testDefaultImpls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/defaultImpls.kt");
doTest(fileName);
}
@TestMetadata("enums.kt")
public void testEnums() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/enums.kt");
doTest(fileName);
}
@TestMetadata("fileFacadeJvmName.kt")
public void testFileFacadeJvmName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/fileFacadeJvmName.kt");
doTest(fileName);
}
@TestMetadata("functions.kt")
public void testFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/functions.kt");
doTest(fileName);
}
@TestMetadata("genericRawSignatures.kt")
public void testGenericRawSignatures() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/genericRawSignatures.kt");
doTest(fileName);
}
@TestMetadata("genericSimple.kt")
public void testGenericSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/genericSimple.kt");
doTest(fileName);
}
@TestMetadata("importsForErrorTypes.kt")
public void testImportsForErrorTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/importsForErrorTypes.kt");
doTest(fileName);
}
@TestMetadata("inheritanceSimple.kt")
public void testInheritanceSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/inheritanceSimple.kt");
doTest(fileName);
}
@TestMetadata("innerClassesWithTypeParameters.kt")
public void testInnerClassesWithTypeParameters() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/innerClassesWithTypeParameters.kt");
doTest(fileName);
}
@TestMetadata("invalidFieldName.kt")
public void testInvalidFieldName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/invalidFieldName.kt");
doTest(fileName);
}
@TestMetadata("javaKeywords.kt")
public void testJavaKeywords() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/javaKeywords.kt");
doTest(fileName);
}
@TestMetadata("javaKeywordsInPackageNames.kt")
public void testJavaKeywordsInPackageNames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/javaKeywordsInPackageNames.kt");
doTest(fileName);
}
@TestMetadata("jvmOverloads.kt")
public void testJvmOverloads() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/jvmOverloads.kt");
doTest(fileName);
}
@TestMetadata("jvmStatic.kt")
public void testJvmStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/jvmStatic.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticFieldInParent.kt")
public void testJvmStaticFieldInParent() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/jvmStaticFieldInParent.kt");
doTest(fileName);
}
@TestMetadata("kt14996.kt")
public void testKt14996() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt14996.kt");
doTest(fileName);
}
@TestMetadata("kt14997.kt")
public void testKt14997() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt14997.kt");
doTest(fileName);
}
@TestMetadata("kt14998.kt")
public void testKt14998() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt14998.kt");
doTest(fileName);
}
@TestMetadata("kt15145.kt")
public void testKt15145() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt15145.kt");
doTest(fileName);
}
@TestMetadata("kt17567.kt")
public void testKt17567() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt17567.kt");
doTest(fileName);
}
@TestMetadata("kt18377.kt")
public void testKt18377() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt18377.kt");
doTest(fileName);
}
@TestMetadata("kt18682.kt")
public void testKt18682() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt18682.kt");
doTest(fileName);
}
@TestMetadata("kt18791.kt")
public void testKt18791() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt18791.kt");
doTest(fileName);
}
@TestMetadata("kt19700.kt")
public void testKt19700() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt19700.kt");
doTest(fileName);
}
@TestMetadata("kt19750.kt")
public void testKt19750() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/kt19750.kt");
doTest(fileName);
}
@TestMetadata("mapEntry.kt")
public void testMapEntry() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/mapEntry.kt");
doTest(fileName);
}
@TestMetadata("methodParameterNames.kt")
public void testMethodParameterNames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/methodParameterNames.kt");
doTest(fileName);
}
@TestMetadata("methodPropertySignatureClash.kt")
public void testMethodPropertySignatureClash() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/methodPropertySignatureClash.kt");
doTest(fileName);
}
@TestMetadata("modifiers.kt")
public void testModifiers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/modifiers.kt");
doTest(fileName);
}
@TestMetadata("multifileClass.kt")
public void testMultifileClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/multifileClass.kt");
doTest(fileName);
}
@TestMetadata("nestedClasses.kt")
public void testNestedClasses() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses.kt");
doTest(fileName);
}
@TestMetadata("nestedClasses2.kt")
public void testNestedClasses2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/nestedClasses2.kt");
doTest(fileName);
}
@TestMetadata("nestedClassesNonRootPackage.kt")
public void testNestedClassesNonRootPackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/nestedClassesNonRootPackage.kt");
doTest(fileName);
}
@TestMetadata("nonExistentClass.kt")
public void testNonExistentClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/nonExistentClass.kt");
doTest(fileName);
}
@TestMetadata("nonExistentClassTypesConversion.kt")
public void testNonExistentClassTypesConversion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/nonExistentClassTypesConversion.kt");
doTest(fileName);
}
@TestMetadata("nonExistentClassWIthoutCorrection.kt")
public void testNonExistentClassWIthoutCorrection() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/nonExistentClassWIthoutCorrection.kt");
doTest(fileName);
}
@TestMetadata("primitiveTypes.kt")
public void testPrimitiveTypes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/primitiveTypes.kt");
doTest(fileName);
}
@TestMetadata("propertyAnnotations.kt")
public void testPropertyAnnotations() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/propertyAnnotations.kt");
doTest(fileName);
}
@TestMetadata("severalPackageParts.kt")
public void testSeveralPackageParts() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/severalPackageParts.kt");
doTest(fileName);
}
@TestMetadata("strangeIdentifiers.kt")
public void testStrangeIdentifiers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers.kt");
doTest(fileName);
}
@TestMetadata("strangeNames.kt")
public void testStrangeNames() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/strangeNames.kt");
doTest(fileName);
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/converter/topLevel.kt");
doTest(fileName);
}
}
@@ -0,0 +1,143 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.command.impl.DummyProject
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.kapt3.KaptContext
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
import org.jetbrains.kotlin.kapt3.util.KaptLogger
import org.jetbrains.kotlin.resolve.BindingContext
import org.junit.Assert.*
import org.junit.Test
import java.io.File
import java.nio.file.Files
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.TypeElement
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class JavaKaptContextTest {
companion object {
private val TEST_DATA_DIR = File("plugins/kapt3/kapt3-compiler/testData/runner")
val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
fun simpleProcessor() = object : AbstractProcessor() {
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
for (annotation in annotations) {
val annotationName = annotation.simpleName.toString()
val annotatedElements = roundEnv.getElementsAnnotatedWith(annotation)
for (annotatedElement in annotatedElements) {
val generatedClassName = annotatedElement.simpleName.toString().capitalize() + annotationName.capitalize()
val file = processingEnv.filer.createSourceFile("generated." + generatedClassName)
file.openWriter().use {
it.write("""
package generated;
class $generatedClassName {}
""".trimIndent())
}
}
}
return true
}
override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation")
}
}
private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) {
KaptContext(KaptLogger(isVerbose = true, messageCollector = messageCollector),
DummyProject.getInstance(),
bindingContext = BindingContext.EMPTY,
compiledClasses = emptyList(),
origins = emptyMap(),
generationState = null,
processorOptions = emptyMap()
).doAnnotationProcessing(
listOf(javaSourceFile),
listOf(processor),
emptyList(), // compile classpath
emptyList(), // annotation processing classpath
"", // list of annotation processor qualified names
outputDir,
outputDir,
withJdk = true)
}
@Test
fun testSimple() {
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
try {
doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), simpleProcessor(), sourceOutputDir)
val myMethodFile = File(sourceOutputDir, "generated/MyMethodMyAnnotation.java")
assertTrue(myMethodFile.exists())
} finally {
sourceOutputDir.deleteRecursively()
}
}
@Test(expected = KaptError::class)
fun testException() {
val exceptionMessage = "Here we are!"
val processor = object : AbstractProcessor() {
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
throw RuntimeException(exceptionMessage)
}
override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation")
}
try {
doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), processor, TEST_DATA_DIR)
} catch (e: KaptError) {
assertEquals(KaptError.Kind.EXCEPTION, e.kind)
assertEquals("Here we are!", e.cause!!.message)
throw e
}
}
@Test(expected = KaptError::class)
fun testParsingError() {
try {
doAnnotationProcessing(File(TEST_DATA_DIR, "ParseError.java"), simpleProcessor(), TEST_DATA_DIR)
} catch (e: KaptError) {
assertEquals(KaptError.Kind.ERROR_RAISED, e.kind)
throw e
}
}
}
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.junit.Test
import java.io.File
import javax.lang.model.element.ElementKind
import javax.lang.model.element.ExecutableElement
class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest() {
@Test
fun testSimple() = test("Simple", "test.MyAnnotation") { set, roundEnv, _ ->
assertEquals(1, set.size)
val annotatedElements = roundEnv.getElementsAnnotatedWith(set.single())
assertEquals(1, annotatedElements.size)
assertEquals("myMethod", annotatedElements.single().simpleName.toString())
}
@Test
fun testSimpleStubsAndIncrementalData() = bindingsTest("Simple") { stubsOutputDir, incrementalDataOutputDir, bindings ->
assert(File(stubsOutputDir, "error/NonExistentClass.java").exists())
assert(File(stubsOutputDir, "test/Simple.java").exists())
assert(File(stubsOutputDir, "test/EnumClass.java").exists())
assert(File(incrementalDataOutputDir, "test/Simple.class").exists())
assert(File(incrementalDataOutputDir, "test/EnumClass.class").exists())
assert(bindings.any { it.key == "test/Simple" && it.value.name == "test/Simple.java" })
assert(bindings.any { it.key == "test/EnumClass" && it.value.name == "test/EnumClass.java" })
}
@Test
fun testStubsAndIncrementalDataForNestedClasses() = bindingsTest("NestedClasses") { stubsOutputDir, incrementalDataOutputDir, bindings ->
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\$Companion.class").exists())
assert(File(incrementalDataOutputDir, "test/Simple\$InnerClass.class").exists())
assert(File(incrementalDataOutputDir, "test/Simple\$NestedClass.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.none { it.key.contains("Companion") })
assert(bindings.none { it.key.contains("InnerClass") })
}
private fun bindingsTest(name: String, test: (File, File, Map<String, KaptJavaFileObject>) -> Unit) {
test(name, "test.MyAnnotation") { _, _, _ ->
val kaptExtension = AnalysisHandlerExtension.getInstances(myEnvironment.project).firstIsInstance<Kapt3ExtensionForTests>()
val stubsOutputDir = kaptExtension.stubsOutputDir
val incrementalDataOutputDir = kaptExtension.incrementalDataOutputDir
val bindings = kaptExtension.savedBindings!!
test(stubsOutputDir, incrementalDataOutputDir!!, bindings)
}
}
@Test
fun testOptions() = test(
"Simple", "test.MyAnnotation",
options = mapOf("firstKey" to "firstValue", "secondKey" to "")
) { _, _, env ->
val options = env.options
assertEquals("firstValue", options["firstKey"])
assertTrue("secondKey" in options)
}
@Test
fun testOverloads() = test("Overloads", "test.MyAnnotation") { set, roundEnv, _ ->
assertEquals(1, set.size)
val annotatedElements = roundEnv.getElementsAnnotatedWith(set.single())
assertEquals(1, annotatedElements.size)
val constructors = annotatedElements
.first()
.enclosedElements
.filter { it.kind == ElementKind.CONSTRUCTOR }
.map { it as ExecutableElement }
.sortedBy { it.parameters.size }
assertEquals(2, constructors.size)
assertEquals(2, constructors[0].parameters.size)
assertEquals(3, constructors[1].parameters.size)
assertEquals("int", constructors[0].parameters[0].asType().toString())
assertEquals("long", constructors[0].parameters[1].asType().toString())
assertEquals("int", constructors[1].parameters[0].asType().toString())
assertEquals("long", constructors[1].parameters[1].asType().toString())
assertEquals("java.lang.String", constructors[1].parameters[2].asType().toString())
assertEquals("someInt", constructors[0].parameters[0].simpleName.toString())
assertEquals("someLong", constructors[0].parameters[1].simpleName.toString())
assertEquals("someInt", constructors[1].parameters[0].simpleName.toString())
assertEquals("someLong", constructors[1].parameters[1].simpleName.toString())
assertEquals("someString", constructors[1].parameters[2].simpleName.toString())
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/kapt3/kapt3-compiler/testData/kotlinRunner")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class KotlinKaptContextTestGenerated extends AbstractKotlinKaptContextTest {
public void testAllFilesPresentInKotlinRunner() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/kapt3-compiler/testData/kotlinRunner"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("NestedClasses.kt")
public void testNestedClasses() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/kotlinRunner/NestedClasses.kt");
doTest(fileName);
}
@TestMetadata("Overloads.kt")
public void testOverloads() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/kotlinRunner/Overloads.kt");
doTest(fileName);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/kapt3-compiler/testData/kotlinRunner/Simple.kt");
doTest(fileName);
}
}
@@ -0,0 +1,37 @@
enum class E {
X {
override fun a() {}
},
Y {
override fun a() {}
};
abstract fun a()
fun b() {}
object Obj
class NestedClass
}
enum class E2 {
X("") {
override fun a() {}
},
Y(5) {
override fun a() {}
};
constructor(n: Int) {}
constructor(s: String) {}
abstract fun a()
}
enum class E3(val a: String) {
X(""), Y("")
}
enum class E4(val a: String, val b: Int, val c: Long, val d: Boolean) {
X("", 4, 2L, true)
}
@@ -0,0 +1,138 @@
@kotlin.Metadata()
public enum E {
/*public static final*/ X /* = new @kotlin.Metadata() X(){
@java.lang.Override()
public void a() {
}
X() {
super();
}
} */,
/*public static final*/ Y /* = new @kotlin.Metadata() Y(){
@java.lang.Override()
public void a() {
}
Y() {
super();
}
} */;
public abstract void a();
public final void b() {
}
E() {
}
@kotlin.Metadata()
public static final class Obj {
public static final E.Obj INSTANCE = null;
private Obj() {
super();
}
}
@kotlin.Metadata()
public static final class NestedClass {
public NestedClass() {
super();
}
}
}
////////////////////
@kotlin.Metadata()
public enum E2 {
/*public static final*/ X /* = new @kotlin.Metadata() X(0){
@java.lang.Override()
public void a() {
}
X() {
super(0);
}
} */,
/*public static final*/ Y /* = new @kotlin.Metadata() Y(0){
@java.lang.Override()
public void a() {
}
Y() {
super(0);
}
} */;
public abstract void a();
E2(int n) {
}
E2(@org.jetbrains.annotations.NotNull()
java.lang.String s) {
}
}
////////////////////
@kotlin.Metadata()
public enum E3 {
/*public static final*/ X /* = new X(null) */,
/*public static final*/ Y /* = new Y(null) */;
@org.jetbrains.annotations.NotNull()
private final java.lang.String a = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getA() {
return null;
}
E3(@org.jetbrains.annotations.NotNull()
java.lang.String a) {
}
}
////////////////////
@kotlin.Metadata()
public enum E4 {
/*public static final*/ X /* = new X(null, 0, 0L, false) */;
@org.jetbrains.annotations.NotNull()
private final java.lang.String a = null;
private final int b = 0;
private final long c = 0L;
private final boolean d = false;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getA() {
return null;
}
public final int getB() {
return 0;
}
public final long getC() {
return 0L;
}
public final boolean getD() {
return false;
}
E4(@org.jetbrains.annotations.NotNull()
java.lang.String a, int b, long c, boolean d) {
}
}
@@ -0,0 +1,9 @@
abstract class Base {
protected abstract fun doJob(job: String, delay: Int)
protected abstract fun <T : CharSequence> doJobGeneric(job: T, delay: Int)
}
class Impl : Base() {
override fun doJob(job: String, delay: Int) {}
override fun <T : CharSequence> doJobGeneric(job: T, delay: Int) {}
}
@@ -0,0 +1,34 @@
@kotlin.Metadata()
public abstract class Base {
protected abstract void doJob(@org.jetbrains.annotations.NotNull()
java.lang.String job, int delay);
protected abstract <T extends java.lang.CharSequence>void doJobGeneric(@org.jetbrains.annotations.NotNull()
T job, int delay);
public Base() {
super();
}
}
////////////////////
@kotlin.Metadata()
public final class Impl extends Base {
@java.lang.Override()
protected void doJob(@org.jetbrains.annotations.NotNull()
java.lang.String job, int delay) {
}
@java.lang.Override()
protected <T extends java.lang.CharSequence>void doJobGeneric(@org.jetbrains.annotations.NotNull()
T job, int delay) {
}
public Impl() {
super();
}
}
@@ -0,0 +1,31 @@
annotation class Anno1
enum class Colors { WHITE, BLACK }
annotation class Anno2(
val i: Int = 5,
val s: String = "ABC",
val ii: IntArray = intArrayOf(1, 2, 3),
val ss: Array<String> = arrayOf("A", "B"),
val a: Anno1,
val color: Colors = Colors.BLACK,
val colors: Array<Colors> = arrayOf(Colors.BLACK, Colors.WHITE),
val clazz: kotlin.reflect.KClass<*>,
val classes: Array<kotlin.reflect.KClass<*>>
)
annotation class Anno3(val value: String)
@Anno1
@Anno2(a = Anno1(), clazz = TestAnno::class, classes = arrayOf(TestAnno::class, Anno1::class))
@Anno3(value = "value")
class TestAnno
@Anno3("value")
@Anno2(i = 6, s = "BCD", ii = intArrayOf(4, 5, 6), ss = arrayOf("Z", "X"),
a = Anno1(), color = Colors.WHITE, colors = arrayOf(Colors.WHITE),
clazz = TestAnno::class, classes = arrayOf(TestAnno::class, Anno1::class))
class TestAnno2 {
@Anno1
fun a(@Anno3("param-pam-pam") param: String) {}
@get:Anno3("getter") @set:Anno3("setter") @property:Anno3("property") @field:Anno3("field") @setparam:Anno3("setparam")
var b: String = "property initializer"
}
@@ -0,0 +1,104 @@
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Anno1 {
}
////////////////////
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Anno2 {
public abstract int i() default 5;
public abstract java.lang.String s() default "ABC";
public abstract int[] ii() default {1, 2, 3};
public abstract java.lang.String[] ss() default {"A", "B"};
public abstract Anno1 a();
public abstract Colors color() default Colors.BLACK;
public abstract Colors[] colors() default {Colors.BLACK, Colors.WHITE};
public abstract java.lang.Class<?> clazz();
public abstract java.lang.Class<?>[] classes();
}
////////////////////
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Anno3 {
public abstract java.lang.String value();
}
////////////////////
@kotlin.Metadata()
public enum Colors {
/*public static final*/ WHITE /* = new WHITE() */,
/*public static final*/ BLACK /* = new BLACK() */;
Colors() {
}
}
////////////////////
@kotlin.Metadata()
@Anno3(value = "value")
@Anno2(a = @Anno1(), clazz = TestAnno.class, classes = {TestAnno.class, Anno1.class})
@Anno1()
public final class TestAnno {
public TestAnno() {
super();
}
}
////////////////////
@kotlin.Metadata()
@Anno2(i = 6, s = "BCD", ii = {4, 5, 6}, ss = {"Z", "X"}, a = @Anno1(), color = Colors.WHITE, colors = {Colors.WHITE}, clazz = TestAnno.class, classes = {TestAnno.class, Anno1.class})
@Anno3(value = "value")
public final class TestAnno2 {
@org.jetbrains.annotations.NotNull()
@Anno3(value = "field")
private java.lang.String b;
@Anno1()
public final void a(@org.jetbrains.annotations.NotNull()
@Anno3(value = "param-pam-pam")
java.lang.String param) {
}
@Anno3(value = "property")
public static void b$annotations() {
}
@org.jetbrains.annotations.NotNull()
@Anno3(value = "getter")
public final java.lang.String getB() {
return null;
}
@Anno3(value = "setter")
public final void setB(@org.jetbrains.annotations.NotNull()
@Anno3(value = "setparam")
java.lang.String p0) {
}
public TestAnno2() {
super();
}
}
@@ -0,0 +1,32 @@
@file:kotlin.jvm.JvmName("AnnotationsTest")
package test
@Anno("anno-class")
annotation class Anno @Anno("anno-constructor") constructor(
@Anno("anno-value") val value: String
)
@Anno("clazz")
abstract class Test @Anno("test-constructor") protected constructor(@param:Anno("v-param")
@setparam:Anno("v-setparam")
@property:Anno("v-property")
@get:Anno("v-get")
@set:Anno("v-set") var v: String) {
@Anno("abstract-method")
abstract fun abstractMethod(): String
@Anno("abstract-val")
abstract val abstractVal: String
}
@Anno("top-level-fun")
fun @receiver:Anno("top-level-fun-receiver") String.topLevelFun() {}
@Anno("top-level-val")
val @receiver:Anno("top-level-val-receiver") Int.topLevelVal: String
get() = ""
@Anno("enum")
enum class Enum @Anno("enum-constructor") constructor(@Anno("x") val x: Int) {
@Anno("white") WHITE(1), @Anno("black") BLACK(2)
}
@@ -0,0 +1,103 @@
package test;
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Anno(value = "anno-class")
public abstract @interface Anno {
public abstract java.lang.String value();
}
////////////////////
package test;
@kotlin.Metadata()
public final class AnnotationsTest {
public AnnotationsTest() {
super();
}
@Anno(value = "top-level-fun")
public static final void topLevelFun(@org.jetbrains.annotations.NotNull()
@Anno(value = "top-level-fun-receiver")
java.lang.String $receiver) {
}
@Anno(value = "top-level-val")
public static void topLevelVal$annotations(int p0) {
}
@org.jetbrains.annotations.NotNull()
public static final java.lang.String getTopLevelVal(@Anno(value = "top-level-val-receiver")
int $receiver) {
return null;
}
}
////////////////////
package test;
@kotlin.Metadata()
@Anno(value = "enum")
public enum Enum {
/*public static final*/ WHITE /* = new WHITE(0) */,
/*public static final*/ BLACK /* = new BLACK(0) */;
private final int x = 0;
public final int getX() {
return 0;
}
@Anno(value = "enum-constructor")
Enum(@Anno(value = "x")
int x) {
}
}
////////////////////
package test;
@kotlin.Metadata()
@Anno(value = "clazz")
public abstract class Test {
@org.jetbrains.annotations.NotNull()
private java.lang.String v;
@org.jetbrains.annotations.NotNull()
@Anno(value = "abstract-method")
public abstract java.lang.String abstractMethod();
@Anno(value = "abstract-val")
public static void abstractVal$annotations() {
}
@org.jetbrains.annotations.NotNull()
public abstract java.lang.String getAbstractVal();
@Anno(value = "v-property")
public static void v$annotations() {
}
@org.jetbrains.annotations.NotNull()
@Anno(value = "v-get")
public final java.lang.String getV() {
return null;
}
@Anno(value = "v-set")
public final void setV(@org.jetbrains.annotations.NotNull()
@Anno(value = "v-setparam")
java.lang.String p0) {
}
@Anno(value = "test-constructor")
protected Test(@org.jetbrains.annotations.NotNull()
@Anno(value = "v-param")
java.lang.String v) {
super();
}
}
@@ -0,0 +1,3 @@
data class User(val firstName: String, val secondName: String, val age: Int) {
fun procedure() {}
}
@@ -0,0 +1,67 @@
@kotlin.Metadata()
public final class User {
@org.jetbrains.annotations.NotNull()
private final java.lang.String firstName = null;
@org.jetbrains.annotations.NotNull()
private final java.lang.String secondName = null;
private final int age = 0;
public final void procedure() {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getFirstName() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getSecondName() {
return null;
}
public final int getAge() {
return 0;
}
public User(@org.jetbrains.annotations.NotNull()
java.lang.String firstName, @org.jetbrains.annotations.NotNull()
java.lang.String secondName, int age) {
super();
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String component1() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String component2() {
return null;
}
public final int component3() {
return 0;
}
@org.jetbrains.annotations.NotNull()
public final User copy(@org.jetbrains.annotations.NotNull()
java.lang.String firstName, @org.jetbrains.annotations.NotNull()
java.lang.String secondName, int age) {
return null;
}
@java.lang.Override()
public java.lang.String toString() {
return null;
}
@java.lang.Override()
public int hashCode() {
return 0;
}
@java.lang.Override()
public boolean equals(java.lang.Object p0) {
return false;
}
}
@@ -0,0 +1,15 @@
interface IntfWithoutDefaultImpls
interface IntfWithDefaultImpls {
fun a() {}
}
interface Intf {
companion object {
val BLACK = 1
const val WHITE = 2
}
val color: Int
get() = BLACK
}
@@ -0,0 +1,60 @@
@kotlin.Metadata()
public abstract interface Intf {
public static final Intf.Companion Companion = null;
public static final int WHITE = 2;
public abstract int getColor();
@kotlin.Metadata()
public static final class DefaultImpls {
public DefaultImpls() {
super();
}
public static int getColor(Intf $this) {
return 0;
}
}
@kotlin.Metadata()
public static final class Companion {
private static final int BLACK = 1;
public static final int WHITE = 2;
public final int getBLACK() {
return 0;
}
private Companion() {
super();
}
}
}
////////////////////
@kotlin.Metadata()
public abstract interface IntfWithDefaultImpls {
public abstract void a();
@kotlin.Metadata()
public static final class DefaultImpls {
public DefaultImpls() {
super();
}
public static void a(IntfWithDefaultImpls $this) {
}
}
}
////////////////////
@kotlin.Metadata()
public abstract interface IntfWithoutDefaultImpls {
}
@@ -0,0 +1,13 @@
enum class Enum1 {
BLACK, WHITE
}
annotation class Anno1(val value: String)
enum class Enum2(@Anno1("first") val col: String, @Anno1("second") val col2: Int) {
RED("red", 1), WHITE("white", 2);
fun color() = col
private fun privateEnumFun() {}
public fun publicEnumFun() {}
}
@@ -0,0 +1,56 @@
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Anno1 {
public abstract java.lang.String value();
}
////////////////////
@kotlin.Metadata()
public enum Enum1 {
/*public static final*/ BLACK /* = new BLACK() */,
/*public static final*/ WHITE /* = new WHITE() */;
Enum1() {
}
}
////////////////////
@kotlin.Metadata()
public enum Enum2 {
/*public static final*/ RED /* = new RED(null, 0) */,
/*public static final*/ WHITE /* = new WHITE(null, 0) */;
@org.jetbrains.annotations.NotNull()
private final java.lang.String col = null;
private final int col2 = 0;
@org.jetbrains.annotations.NotNull()
public final java.lang.String color() {
return null;
}
private final void privateEnumFun() {
}
public final void publicEnumFun() {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getCol() {
return null;
}
public final int getCol2() {
return 0;
}
Enum2(@org.jetbrains.annotations.NotNull()
@Anno1(value = "first")
java.lang.String col, @Anno1(value = "second")
int col2) {
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
@file:JvmName("FacadeName")
package a.b.c
fun foo() {}
val bar = 3
@@ -0,0 +1,17 @@
package a.b.c;
@kotlin.Metadata()
public final class FacadeName {
public FacadeName() {
super();
}
private static final int bar = 3;
public static final void foo() {
}
public static final int getBar() {
return 0;
}
}
@@ -0,0 +1,6 @@
class FunctionsTest {
fun f() = String::length
fun f2() = fun (a: Int, b: Int) = a > b
fun f3() = run {}
fun f4() = run { 3 }
}
@@ -0,0 +1,24 @@
@kotlin.Metadata()
public final class FunctionsTest {
@org.jetbrains.annotations.NotNull()
public final kotlin.reflect.KProperty1<java.lang.String, java.lang.Integer> f() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final kotlin.jvm.functions.Function2<java.lang.Integer, java.lang.Integer, java.lang.Boolean> f2() {
return null;
}
public final void f3() {
}
public final int f4() {
return 0;
}
public FunctionsTest() {
super();
}
}
@@ -0,0 +1,4 @@
class GenericRawSignatures {
fun <T> genericFun(): T? = null
fun nonGenericFun(): String? = null
}
@@ -0,0 +1,17 @@
@kotlin.Metadata()
public final class GenericRawSignatures {
@org.jetbrains.annotations.Nullable()
public final <T extends java.lang.Object>T genericFun() {
return null;
}
@org.jetbrains.annotations.Nullable()
public final java.lang.String nonGenericFun() {
return null;
}
public GenericRawSignatures() {
super();
}
}
@@ -0,0 +1,15 @@
import java.io.Serializable
import java.util.*
interface Intf<I1, I2 : Serializable>
interface Intf2<out T : List<String>, M : T>
interface OtherIntf<O : CharSequence>
open class BaseClass<B : Any>
class MyClass<M1, M2> : Intf<Any, java.util.Date>, OtherIntf<String>, BaseClass<RuntimeException>() {
val fld: List<Map<String, M1>>? = null
}
interface ABC {
fun <T : CharSequence> abc(item: T, items: List<T>, vararg otherItems: T): List<T>
fun <X> bcd(vararg a: Char): Int
}
@@ -0,0 +1,62 @@
@kotlin.Metadata()
public abstract interface ABC {
@org.jetbrains.annotations.NotNull()
public abstract <T extends java.lang.CharSequence>java.util.List<T> abc(@org.jetbrains.annotations.NotNull()
T item, @org.jetbrains.annotations.NotNull()
java.util.List<? extends T> items, @org.jetbrains.annotations.NotNull()
T... otherItems);
public abstract <X extends java.lang.Object>int bcd(@org.jetbrains.annotations.NotNull()
char... a);
}
////////////////////
@kotlin.Metadata()
public class BaseClass<B extends java.lang.Object> {
public BaseClass() {
super();
}
}
////////////////////
@kotlin.Metadata()
public abstract interface Intf<I1 extends java.lang.Object, I2 extends java.io.Serializable> {
}
////////////////////
@kotlin.Metadata()
public abstract interface Intf2<T extends java.util.List<? extends java.lang.String>, M extends T> {
}
////////////////////
@kotlin.Metadata()
public final class MyClass<M1 extends java.lang.Object, M2 extends java.lang.Object> extends BaseClass<java.lang.RuntimeException> implements Intf<java.lang.Object, java.util.Date>, OtherIntf<java.lang.String> {
@org.jetbrains.annotations.Nullable()
private final java.util.List<java.util.Map<java.lang.String, M1>> fld = null;
@org.jetbrains.annotations.Nullable()
public final java.util.List<java.util.Map<java.lang.String, M1>> getFld() {
return null;
}
public MyClass() {
super();
}
}
////////////////////
@kotlin.Metadata()
public abstract interface OtherIntf<O extends java.lang.CharSequence> {
}
@@ -0,0 +1,12 @@
// CORRECT_ERROR_TYPES
import java.util.zip.*
import java.util.Date
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.MICROSECONDS
import java.util.concurrent.TimeUnit.*
import java.util.Calendar.*
fun test(): Any? {
return null
}
@@ -0,0 +1,19 @@
import java.util.zip.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit.MICROSECONDS;
import java.util.concurrent.TimeUnit.*;
import java.util.Calendar.*;
@kotlin.Metadata()
public final class ImportsForErrorTypesKt {
public ImportsForErrorTypesKt() {
super();
}
@org.jetbrains.annotations.Nullable()
public static final java.lang.Object test() {
return null;
}
}
@@ -0,0 +1,13 @@
interface Context
enum class Result {
SUCCESS, ERROR
}
abstract class BaseClass(context: Context, num: Int, bool: Boolean) {
abstract fun doJob(): Result
}
class Inheritor(context: Context) : BaseClass(context, 5, true) {
override fun doJob() = Result.SUCCESS
}
@@ -0,0 +1,48 @@
@kotlin.Metadata()
public abstract class BaseClass {
@org.jetbrains.annotations.NotNull()
public abstract Result doJob();
public BaseClass(@org.jetbrains.annotations.NotNull()
Context context, int num, boolean bool) {
super();
}
}
////////////////////
@kotlin.Metadata()
public abstract interface Context {
}
////////////////////
@kotlin.Metadata()
public final class Inheritor extends BaseClass {
@org.jetbrains.annotations.NotNull()
@java.lang.Override()
public Result doJob() {
return null;
}
public Inheritor(@org.jetbrains.annotations.NotNull()
Context context) {
super(null, 0, false);
}
}
////////////////////
@kotlin.Metadata()
public enum Result {
/*public static final*/ SUCCESS /* = new SUCCESS() */,
/*public static final*/ ERROR /* = new ERROR() */;
Result() {
}
}
@@ -0,0 +1,16 @@
class Test {
private var a = FilterValueDelegate<Float>()
private inner class FilterValueDelegate<T>
}
class Test2 {
inner class FilterValueDelegate<T> {
private var a = Filter2<String>()
inner class Filter2<X>
}
}
class Test3 {
private var a = FilterValueDelegate<Float>()
private class FilterValueDelegate<T>
}
@@ -0,0 +1,64 @@
@kotlin.Metadata()
public final class Test {
private Test.FilterValueDelegate<java.lang.Float> a;
public Test() {
super();
}
@kotlin.Metadata()
final class FilterValueDelegate<T extends java.lang.Object> {
public FilterValueDelegate() {
super();
}
}
}
////////////////////
@kotlin.Metadata()
public final class Test2 {
public Test2() {
super();
}
@kotlin.Metadata()
public final class FilterValueDelegate<T extends java.lang.Object> {
private Test2.FilterValueDelegate<T>.Filter2<java.lang.String> a;
public FilterValueDelegate() {
super();
}
@kotlin.Metadata()
public final class Filter2<X extends java.lang.Object> {
public Filter2() {
super();
}
}
}
}
////////////////////
@kotlin.Metadata()
public final class Test3 {
private Test3.FilterValueDelegate<java.lang.Float> a;
public Test3() {
super();
}
@kotlin.Metadata()
static final class FilterValueDelegate<T extends java.lang.Object> {
public FilterValueDelegate() {
super();
}
}
}
@@ -0,0 +1,10 @@
// EXPECTED_ERROR 'WHI-TE' is an invalid Java enum value name
// EXPECTED_ERROR an enum annotation value must be an enum constant
// EXPECTED_ERROR cannot find symbol
enum class Color {
BLACK, `WHI-TE`
}
@Anno(Color.`WHI-TE`)
annotation class Anno(val color: Color)
@@ -0,0 +1,18 @@
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Anno(color = Color.InvalidFieldName)
public abstract @interface Anno {
public abstract Color color();
}
////////////////////
@kotlin.Metadata()
public enum Color {
/*public static final*/ BLACK /* = new BLACK() */;
Color() {
}
}
@@ -0,0 +1,4 @@
class default {
lateinit val extends: String
fun implements(instanceof: Int) {}
}
@@ -0,0 +1 @@
@@ -0,0 +1,19 @@
// FILE: a.kt
package a.b.c
class A
// FILE: b.kt
package a.`do`.c
class B
// FILE: c.kt
package case.a
class C
// FILE: d.kt
package a.b.c.d.e.`for`
class D
// FILE: e.kt
package a.b.`typealias`.c
class E
@@ -0,0 +1,21 @@
package a.b.c;
@kotlin.Metadata()
public final class A {
public A() {
super();
}
}
////////////////////
package a.b.typealias.c;
@kotlin.Metadata()
public final class E {
public E() {
super();
}
}
@@ -0,0 +1,17 @@
class State @JvmOverloads constructor(
val someInt: Int,
val someLong: Long,
val someString: String = ""
)
class State2 @JvmOverloads constructor(
@JvmField val someInt: Int,
@JvmField val someLong: Long = 2,
@JvmField val someString: String = ""
) {
@JvmOverloads
fun test(someInt: Int, someLong: Long = 1, someString: String = "A"): Int = 5
fun someMethod(str: String) {}
fun methodWithoutArgs() {}
}
@@ -0,0 +1,73 @@
@kotlin.Metadata()
public final class State {
private final int someInt = 0;
private final long someLong = 0L;
@org.jetbrains.annotations.NotNull()
private final java.lang.String someString = null;
public final int getSomeInt() {
return 0;
}
public final long getSomeLong() {
return 0L;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getSomeString() {
return null;
}
public State(int someInt, long someLong, @org.jetbrains.annotations.NotNull()
java.lang.String someString) {
super();
}
public State(int someInt, long someLong) {
super();
}
}
////////////////////
@kotlin.Metadata()
public final class State2 {
public final int someInt = 0;
public final long someLong = 0L;
@org.jetbrains.annotations.NotNull()
public final java.lang.String someString = null;
public final int test(int someInt, long someLong, @org.jetbrains.annotations.NotNull()
java.lang.String someString) {
return 0;
}
public final int test(int someInt, long someLong) {
return 0;
}
public final int test(int someInt) {
return 0;
}
public final void someMethod(@org.jetbrains.annotations.NotNull()
java.lang.String str) {
}
public final void methodWithoutArgs() {
}
public State2(int someInt, long someLong, @org.jetbrains.annotations.NotNull()
java.lang.String someString) {
super();
}
public State2(int someInt, long someLong) {
super();
}
public State2(int someInt) {
super();
}
}
@@ -0,0 +1,13 @@
class JvmStaticTest {
companion object {
@JvmStatic
val one = 1
val two = 2
const val c: Char = 'C'
}
val three: Byte = 3.toByte()
val d: Char = 'D'
}
@@ -0,0 +1,44 @@
@kotlin.Metadata()
public final class JvmStaticTest {
private final byte three = (byte)3;
private final char d = 'D';
private static final int one = 1;
private static final int two = 2;
public static final char c = 'C';
public static final JvmStaticTest.Companion Companion = null;
public final byte getThree() {
return 0;
}
public final char getD() {
return '\u0000';
}
public JvmStaticTest() {
super();
}
public static final int getOne() {
return 0;
}
@kotlin.Metadata()
public static final class Companion {
public static void one$annotations() {
}
public final int getOne() {
return 0;
}
public final int getTwo() {
return 0;
}
private Companion() {
super();
}
}
}
@@ -0,0 +1,6 @@
class Test {
companion object A {
@JvmStatic
val test: String = ""
}
}
@@ -0,0 +1,31 @@
@kotlin.Metadata()
public final class Test {
@org.jetbrains.annotations.NotNull()
private static final java.lang.String test = "";
public static final Test.A A = null;
public Test() {
super();
}
@org.jetbrains.annotations.NotNull()
public static final java.lang.String getTest() {
return null;
}
@kotlin.Metadata()
public static final class A {
public static void test$annotations() {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getTest() {
return null;
}
private A() {
super();
}
}
}
@@ -0,0 +1,7 @@
fun crashMe(values: List<String>): String {
throw UnsupportedOperationException()
}
fun crashMe(values: List<CharSequence>): CharSequence {
throw UnsupportedOperationException()
}
@@ -0,0 +1,19 @@
@kotlin.Metadata()
public final class Kt14996Kt {
public Kt14996Kt() {
super();
}
@org.jetbrains.annotations.NotNull()
public static final java.lang.String crashMe(@org.jetbrains.annotations.NotNull()
java.util.List<java.lang.String> values) {
return null;
}
@org.jetbrains.annotations.NotNull()
public static final java.lang.CharSequence crashMe(@org.jetbrains.annotations.NotNull()
java.util.List<? extends java.lang.CharSequence> values) {
return null;
}
}
@@ -0,0 +1,21 @@
@file:Suppress("AMBIGUOUS_ANONYMOUS_TYPE_INFERRED")
open class CrashMe {
private val notReally = object : Runnable {
override fun run() {
throw UnsupportedOperationException()
}
}
}
fun a() = object : Runnable {
override fun run() {}
}
fun b() = object : java.io.Serializable, Runnable {
override fun run() {}
}
fun c() = object : CrashMe(), Runnable {
override fun run() {}
}
@@ -0,0 +1,35 @@
@kotlin.Metadata()
public class CrashMe {
private final java.lang.Runnable notReally = null;
public CrashMe() {
super();
}
}
////////////////////
@kotlin.Suppress(names = {"AMBIGUOUS_ANONYMOUS_TYPE_INFERRED"})
@kotlin.Metadata()
public final class Kt14997Kt {
public Kt14997Kt() {
super();
}
@org.jetbrains.annotations.NotNull()
public static final java.lang.Runnable a() {
return null;
}
@org.jetbrains.annotations.NotNull()
public static final java.lang.Runnable b() {
return null;
}
@org.jetbrains.annotations.NotNull()
public static final CrashMe c() {
return null;
}
}
@@ -0,0 +1,10 @@
class Outer {
private inner class Inner(val foo: String, val bar: String)
private class Nested(val foo: String, val bar: String)
fun nonAbstract(s: String, i: Int) {
}
abstract fun abstract(s: String, i: Int)
}
@@ -0,0 +1,59 @@
@kotlin.Metadata()
public final class Outer {
public final void nonAbstract(@org.jetbrains.annotations.NotNull()
java.lang.String s, int i) {
}
public Outer() {
super();
}
@kotlin.Metadata()
final class Inner {
@org.jetbrains.annotations.NotNull()
private final java.lang.String foo = null;
@org.jetbrains.annotations.NotNull()
private final java.lang.String bar = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getFoo() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getBar() {
return null;
}
public Inner(@org.jetbrains.annotations.NotNull()
java.lang.String foo, @org.jetbrains.annotations.NotNull()
java.lang.String bar) {
super();
}
}
@kotlin.Metadata()
static final class Nested {
@org.jetbrains.annotations.NotNull()
private final java.lang.String foo = null;
@org.jetbrains.annotations.NotNull()
private final java.lang.String bar = null;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getFoo() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getBar() {
return null;
}
public Nested(@org.jetbrains.annotations.NotNull()
java.lang.String foo, @org.jetbrains.annotations.NotNull()
java.lang.String bar) {
super();
}
}
}
@@ -0,0 +1,4 @@
interface MyInterface {
fun someFun()
private class MyDefaultInferface()
}
@@ -0,0 +1,13 @@
@kotlin.Metadata()
public abstract interface MyInterface {
public abstract void someFun();
@kotlin.Metadata()
public static final class MyDefaultInferface {
public MyDefaultInferface() {
super();
}
}
}
@@ -0,0 +1,6 @@
package test
internal class MutableEntry<K, V>(
private val internal: MutableMap<K, V>,
override val key: K, value: V
): MutableMap.MutableEntry<K, V>
@@ -0,0 +1,17 @@
package test;
@kotlin.Metadata()
public final class MutableEntry<K extends java.lang.Object, V extends java.lang.Object> implements java.util.Map.Entry<K, V>, kotlin.jvm.internal.markers.KMutableMap.Entry {
private final java.util.Map<K, V> internal = null;
private final K key = null;
@java.lang.Override()
public K getKey() {
return null;
}
public MutableEntry(@org.jetbrains.annotations.NotNull()
java.util.Map<K, V> internal, K key, V value) {
super();
}
}
@@ -0,0 +1,3 @@
import java.util.Date
fun Date(double: Double): Date = Date(double.times(1000).toLong())
@@ -0,0 +1,12 @@
@kotlin.Metadata()
public final class Kt18377Kt {
public Kt18377Kt() {
super();
}
@org.jetbrains.annotations.NotNull()
public static final java.util.Date Date(double p0_1484504552) {
return null;
}
}
@@ -0,0 +1,25 @@
// WITH_RUNTIME
fun test1() = (0..10).map { n ->
object {
override fun hashCode() = n
}
}
fun test2() = (0..10).map { n ->
object : Runnable {
override fun run() {}
}
}
abstract class Foo
fun test3() = (0..10).map { n ->
object : Foo() {}
}
fun test4() = (0..10).map { n ->
object : Foo(), Runnable {
override fun run() {}
}
}
@@ -0,0 +1,38 @@
@kotlin.Metadata()
public abstract class Foo {
public Foo() {
super();
}
}
////////////////////
@kotlin.Metadata()
public final class Kt18682Kt {
public Kt18682Kt() {
super();
}
@org.jetbrains.annotations.NotNull()
public static final java.util.List<java.lang.Object> test1() {
return null;
}
@org.jetbrains.annotations.NotNull()
public static final java.util.List<java.lang.Runnable> test2() {
return null;
}
@org.jetbrains.annotations.NotNull()
public static final java.util.List<Foo> test3() {
return null;
}
@org.jetbrains.annotations.NotNull()
public static final java.util.List<Foo> test4() {
return null;
}
}
@@ -0,0 +1,51 @@
//FILE: lib/R.java
package lib;
public class R {
public static class id {
public final static int textView = 100;
}
}
//FILE: app/R.java
package app;
public class R {
public static class layout {
public final static int mainActivity = 100;
}
}
//FILE: app/B.java
package app;
public class B {
public static class id {
public final static int textView = 200;
}
}
//FILE: test.kt
package app
import lib.R as LibR
import lib.R.id.textView
annotation class Bind(val id: Int)
class MyActivity {
@Bind(LibR.id.textView)
fun foo() {}
@Bind(lib.R.id.textView)
fun foo2() {}
@Bind(app.R.layout.mainActivity)
fun foo3() {}
@Bind(R.layout.mainActivity)
fun foo4() {}
@Bind(B.id.textView)
fun notResource() {}
}
@@ -0,0 +1,40 @@
package app;
@kotlin.Metadata()
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
public abstract @interface Bind {
public abstract int id();
}
////////////////////
package app;
@kotlin.Metadata()
public final class MyActivity {
@Bind(id = lib.R.id.textView)
public final void foo() {
}
@Bind(id = lib.R.id.textView)
public final void foo2() {
}
@Bind(id = app.R.layout.mainActivity)
public final void foo3() {
}
@Bind(id = app.R.layout.mainActivity)
public final void foo4() {
}
@Bind(id = 200)
public final void notResource() {
}
public MyActivity() {
super();
}
}
@@ -0,0 +1,11 @@
package test
class Test<T : CharSequence, N : Number> {
private val x = object : ListUpdateCallback {
override fun onInserted(position: Int, count: Int) {}
}
}
interface ListUpdateCallback {
fun onInserted(position: Int, count: Int)
}
@@ -0,0 +1,20 @@
package test;
@kotlin.Metadata()
public abstract interface ListUpdateCallback {
public abstract void onInserted(int position, int count);
}
////////////////////
package test;
@kotlin.Metadata()
public final class Test<T extends java.lang.CharSequence, N extends java.lang.Number> {
private final test.ListUpdateCallback x = null;
public Test() {
super();
}
}
@@ -0,0 +1,11 @@
package test
class Test<T : CharSequence, N : Number> {
private val x = object : TypedListUpdateCallback<String, Long> {
override fun onInserted(position: Long, count: Long, item: String) {}
}
}
interface TypedListUpdateCallback<T : Any, C : Number> {
fun onInserted(position: C, count: C, item: T)
}
@@ -0,0 +1,23 @@
package test;
@kotlin.Metadata()
public final class Test<T extends java.lang.CharSequence, N extends java.lang.Number> {
private final test.TypedListUpdateCallback<java.lang.String, java.lang.Long> x = null;
public Test() {
super();
}
}
////////////////////
package test;
@kotlin.Metadata()
public abstract interface TypedListUpdateCallback<T extends java.lang.Object, C extends java.lang.Number> {
public abstract void onInserted(@org.jetbrains.annotations.NotNull()
C position, @org.jetbrains.annotations.NotNull()
C count, @org.jetbrains.annotations.NotNull()
T item);
}
@@ -0,0 +1,4 @@
interface EntryHolder {
fun entry(p: Map.Entry<CharSequence, Map.Entry<String, Int>>): Map.Entry<String, Any>
val entryProperty: Map.Entry<String, Any>
}
@@ -0,0 +1,10 @@
@kotlin.Metadata()
public abstract interface EntryHolder {
@org.jetbrains.annotations.NotNull()
public abstract java.util.Map.Entry<java.lang.String, java.lang.Object> entry(@org.jetbrains.annotations.NotNull()
java.util.Map.Entry<? extends java.lang.CharSequence, ? extends java.util.Map.Entry<java.lang.String, java.lang.Integer>> p);
@org.jetbrains.annotations.NotNull()
public abstract java.util.Map.Entry<java.lang.String, java.lang.Object> getEntryProperty();
}
@@ -0,0 +1,15 @@
interface Intf {
fun foo(abc: String)
fun bar(bcd: Int): String {
return ""
}
}
abstract class Cls {
abstract fun foo(abc: String)
fun bar(bcd: Int): String {
return ""
}
}
@@ -0,0 +1,41 @@
@kotlin.Metadata()
public abstract class Cls {
public abstract void foo(@org.jetbrains.annotations.NotNull()
java.lang.String abc);
@org.jetbrains.annotations.NotNull()
public final java.lang.String bar(int bcd) {
return null;
}
public Cls() {
super();
}
}
////////////////////
@kotlin.Metadata()
public abstract interface Intf {
public abstract void foo(@org.jetbrains.annotations.NotNull()
java.lang.String abc);
@org.jetbrains.annotations.NotNull()
public abstract java.lang.String bar(int bcd);
@kotlin.Metadata()
public static final class DefaultImpls {
public DefaultImpls() {
super();
}
@org.jetbrains.annotations.NotNull()
public static java.lang.String bar(Intf $this, int bcd) {
return null;
}
}
}
@@ -0,0 +1,7 @@
class CrashMe {
val resources = 1
fun getResources(): String {
return ""
}
}
@@ -0,0 +1,17 @@
@kotlin.Metadata()
public final class CrashMe {
private final int resources = 1;
public final int getResources() {
return 0;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getResources() {
return null;
}
public CrashMe() {
super();
}
}
@@ -0,0 +1,37 @@
package modifiers
public class PublicClass public constructor()
public open class PublicClassProtectedConstructor protected constructor() {
protected interface ProtectedInterface
private interface PrivateInterface
}
public abstract class PublicClassPrivateConstructor private constructor()
internal class InternalClass
private class PrivateClass
public interface PublicInterface
internal interface InternalInterface
private interface PrivateInterface
sealed class SealedClass {
class One : SealedClass()
open class Two : SealedClass()
abstract class Three : Two()
final class Four : Three()
}
class Modifiers {
@Transient
val transientField: String = ""
@Volatile
var volatileField: String = ""
@Strictfp
fun strictFp() {}
@JvmOverloads
fun overloads(a: String = "", n: Int = 5): String = null!!
}
@@ -0,0 +1,183 @@
package modifiers;
@kotlin.Metadata()
public final class InternalClass {
public InternalClass() {
super();
}
}
////////////////////
package modifiers;
@kotlin.Metadata()
public abstract interface InternalInterface {
}
////////////////////
package modifiers;
@kotlin.Metadata()
public final class Modifiers {
@org.jetbrains.annotations.NotNull()
private final transient java.lang.String transientField = "";
@org.jetbrains.annotations.NotNull()
private volatile java.lang.String volatileField;
@org.jetbrains.annotations.NotNull()
public final java.lang.String getTransientField() {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String getVolatileField() {
return null;
}
public final void setVolatileField(@org.jetbrains.annotations.NotNull()
java.lang.String p0) {
}
public final strictfp void strictFp() {
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String overloads(@org.jetbrains.annotations.NotNull()
java.lang.String a, int n) {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String overloads(@org.jetbrains.annotations.NotNull()
java.lang.String a) {
return null;
}
@org.jetbrains.annotations.NotNull()
public final java.lang.String overloads() {
return null;
}
public Modifiers() {
super();
}
}
////////////////////
package modifiers;
@kotlin.Metadata()
final class PrivateClass {
public PrivateClass() {
super();
}
}
////////////////////
package modifiers;
@kotlin.Metadata()
abstract interface PrivateInterface {
}
////////////////////
package modifiers;
@kotlin.Metadata()
public final class PublicClass {
public PublicClass() {
super();
}
}
////////////////////
package modifiers;
@kotlin.Metadata()
public abstract class PublicClassPrivateConstructor {
private PublicClassPrivateConstructor() {
super();
}
}
////////////////////
package modifiers;
@kotlin.Metadata()
public class PublicClassProtectedConstructor {
protected PublicClassProtectedConstructor() {
super();
}
@kotlin.Metadata()
public static abstract interface ProtectedInterface {
}
@kotlin.Metadata()
static abstract interface PrivateInterface {
}
}
////////////////////
package modifiers;
@kotlin.Metadata()
public abstract interface PublicInterface {
}
////////////////////
package modifiers;
@kotlin.Metadata()
public abstract class SealedClass {
private SealedClass() {
super();
}
@kotlin.Metadata()
public static final class One extends modifiers.SealedClass {
public One() {
super();
}
}
@kotlin.Metadata()
public static class Two extends modifiers.SealedClass {
public Two() {
super();
}
}
@kotlin.Metadata()
public static abstract class Three extends modifiers.SealedClass.Two {
public Three() {
super();
}
}
@kotlin.Metadata()
public static final class Four extends modifiers.SealedClass.Three {
public Four() {
super();
}
}
}
@@ -0,0 +1,22 @@
// WITH_RUNTIME
// FILE: a.kt
@file:JvmMultifileClass
@file:JvmName("M1")
package test
fun foo() {}
// FILE: b.kt
@file:JvmMultifileClass
@file:JvmName("M1")
package test
fun bar() {}
// FILE: c.kt
@file:JvmMultifileClass
@file:JvmName("M2")
package test
fun baz() {}
@@ -0,0 +1,30 @@
package test;
@kotlin.Metadata()
public final class M1 {
public M1() {
super();
}
public static final void bar() {
}
public static final void foo() {
}
}
////////////////////
package test;
@kotlin.Metadata()
public final class M2 {
public M2() {
super();
}
public static final void baz() {
}
}
@@ -0,0 +1,58 @@
class Test {
class Nested {
class NestedNested
}
inner class Inner
object NestedObject
interface NestedInterface
enum class NestedEnum {
BLACK, WHITE
}
}
class Foo {
companion object Foo
}
class A {
val x: A? = null
fun f1(a: A, b: B): A? = null
interface B {
val y: B?
fun f2(a: A, b: B): A? = null
class A {
val x: A? = null
val y: B? = null
fun f3(a: A, b: B) {}
object B
}
}
object C {
interface C
}
}
class A2 {
class B {
class C {
class D {
class A2
class B
class Cme
class D
class E
}
}
}
}
@@ -0,0 +1,164 @@
@kotlin.Metadata()
public final class A {
@org.jetbrains.annotations.Nullable()
private final A x = null;
@org.jetbrains.annotations.Nullable()
public final A getX() {
return null;
}
@org.jetbrains.annotations.Nullable()
public final A f1(@org.jetbrains.annotations.NotNull()
A a, @org.jetbrains.annotations.NotNull()
A.B b) {
return null;
}
public A() {
super();
}
@kotlin.Metadata()
public static abstract interface B {
@org.jetbrains.annotations.Nullable()
public abstract A.B getY();
@kotlin.Metadata()
public static final class DefaultImpls {
public DefaultImpls() {
super();
}
}
}
@kotlin.Metadata()
public static final class C {
public static final A.C INSTANCE = null;
private C() {
super();
}
}
}
////////////////////
@kotlin.Metadata()
public final class A2 {
public A2() {
super();
}
@kotlin.Metadata()
public static final class B {
public B() {
super();
}
@kotlin.Metadata()
public static final class C {
public C() {
super();
}
@kotlin.Metadata()
public static final class D {
public D() {
super();
}
@kotlin.Metadata()
public static final class Cme {
public Cme() {
super();
}
}
@kotlin.Metadata()
public static final class E {
public E() {
super();
}
}
}
}
}
}
////////////////////
@kotlin.Metadata()
public final class Foo {
public Foo() {
super();
}
}
////////////////////
@kotlin.Metadata()
public final class Test {
public Test() {
super();
}
@kotlin.Metadata()
public static final class Nested {
public Nested() {
super();
}
@kotlin.Metadata()
public static final class NestedNested {
public NestedNested() {
super();
}
}
}
@kotlin.Metadata()
public final class Inner {
public Inner() {
super();
}
}
@kotlin.Metadata()
public static final class NestedObject {
public static final Test.NestedObject INSTANCE = null;
private NestedObject() {
super();
}
}
@kotlin.Metadata()
public static abstract interface NestedInterface {
}
@kotlin.Metadata()
public static enum NestedEnum {
/*public static final*/ BLACK /* = new BLACK() */,
/*public static final*/ WHITE /* = new WHITE() */;
NestedEnum() {
}
}
}

Some files were not shown because too many files have changed in this diff Show More