Kapt: Add runtime library, move all modules inside the 'kapt3' directory
This commit is contained in:
@@ -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()
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.kapt3.Kapt3CommandLineProcessor
|
||||
+1
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
@@ -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) })
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+820
@@ -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
|
||||
+419
@@ -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()
|
||||
}
|
||||
}
|
||||
+153
@@ -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)
|
||||
}
|
||||
}
|
||||
+38
@@ -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)
|
||||
}
|
||||
+200
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+166
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
+320
@@ -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);
|
||||
}
|
||||
}
|
||||
+143
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+113
@@ -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())
|
||||
}
|
||||
}
|
||||
+56
@@ -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() {
|
||||
}
|
||||
}
|
||||
+16
@@ -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>
|
||||
}
|
||||
+64
@@ -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 @@
|
||||
|
||||
+19
@@ -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
|
||||
+21
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class CrashMe {
|
||||
val resources = 1
|
||||
|
||||
fun getResources(): String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
+17
@@ -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
Reference in New Issue
Block a user