Kapt3: Minor: Refactor kapt3 module (move/rename)
This commit is contained in:
committed by
Yan Zhulanow
parent
e61a7c7f2c
commit
86aa82da6c
@@ -136,7 +136,7 @@ import org.jetbrains.kotlin.js.test.semantics.*
|
||||
import org.jetbrains.kotlin.jvm.compiler.*
|
||||
import org.jetbrains.kotlin.jvm.runtime.AbstractJvm8RuntimeDescriptorLoaderTest
|
||||
import org.jetbrains.kotlin.jvm.runtime.AbstractJvmRuntimeDescriptorLoaderTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractJCTreeConverterTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractClassFileToSourceStubConverterTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptRunnerTest
|
||||
import org.jetbrains.kotlin.kdoc.AbstractKDocLexerTest
|
||||
import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBoxTest
|
||||
@@ -1140,7 +1140,7 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
testGroup("plugins/kapt3/test", "plugins/kapt3/testData") {
|
||||
testClass<AbstractJCTreeConverterTest> {
|
||||
testClass<AbstractClassFileToSourceStubConverterTest> {
|
||||
model("converter")
|
||||
}
|
||||
|
||||
|
||||
-220
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* 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.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.kapt3.diagnostic.ErrorsKapt3
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||
import org.jetbrains.org.objectweb.asm.FieldVisitor
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
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 Kapt3AnalysisCompletedHandlerExtension(
|
||||
val annotationProcessingClasspath: List<File>,
|
||||
val javaSourceRoots: List<File>,
|
||||
val sourcesOutputDir: File,
|
||||
val classFilesOutputDir: File,
|
||||
val stubsOutputDir: File?,
|
||||
val options: Map<String, String>, //TODO
|
||||
val aptOnly: Boolean,
|
||||
val pluginInitializedTime: Long,
|
||||
val logger: Logger
|
||||
) : AnalysisCompletedHandlerExtension {
|
||||
private var annotationProcessingComplete = false
|
||||
|
||||
override fun analysisCompleted(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
bindingTrace: BindingTrace,
|
||||
files: Collection<KtFile>
|
||||
): AnalysisResult? {
|
||||
if (annotationProcessingComplete) {
|
||||
return null
|
||||
}
|
||||
|
||||
annotationProcessingComplete = true
|
||||
|
||||
fun doNotGenerateCode() = AnalysisResult.Companion.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
|
||||
|
||||
if (files.isEmpty()) {
|
||||
logger.info("No Kotlin source files, aborting")
|
||||
return if (aptOnly) doNotGenerateCode() else null
|
||||
}
|
||||
|
||||
logger.info { "Initial analysis took ${System.currentTimeMillis() - pluginInitializedTime} ms" }
|
||||
logger.info { "Kotlin files: " + files.map { it.virtualFile?.name ?: "<in memory ${it.hashCode()}>" } }
|
||||
|
||||
val processors = loadProcessors(annotationProcessingClasspath)
|
||||
if (processors.isEmpty()) {
|
||||
logger.info("No annotation processors available, aborting")
|
||||
return if (aptOnly) doNotGenerateCode() else null
|
||||
}
|
||||
|
||||
logger.info { "Annotation processors: " + processors.joinToString { it.javaClass.canonicalName } }
|
||||
|
||||
val builderFactory = Kapt3BuilderFactory()
|
||||
|
||||
val generationState = GenerationState(
|
||||
project,
|
||||
builderFactory,
|
||||
module,
|
||||
bindingTrace.bindingContext,
|
||||
files.toList(),
|
||||
disableCallAssertions = false,
|
||||
disableParamAssertions = false)
|
||||
|
||||
try {
|
||||
val (stubCompilationTime) = measureTimeMillis {
|
||||
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
|
||||
}
|
||||
|
||||
val compiledClasses = builderFactory.compiledClasses
|
||||
val origins = builderFactory.origins
|
||||
logger.info { "Compiled classes: " + compiledClasses.joinToString { it.name } }
|
||||
|
||||
val javaFilesFromJavaSourceRoots = javaSourceRoots.flatMap {
|
||||
root -> root.walk().filter { it.isFile && it.extension == "java" }.toList()
|
||||
}
|
||||
logger.info { "Java source files: " + javaFilesFromJavaSourceRoots.joinToString { it.canonicalPath } }
|
||||
|
||||
val kaptRunner = KaptRunner(logger)
|
||||
|
||||
val (jcStubGenerationTime, jcCompilationUnitsForKotlinClasses) = measureTimeMillis {
|
||||
val treeConverter = JCTreeConverter(kaptRunner.context, generationState.typeMapper, compiledClasses, origins)
|
||||
treeConverter.convert()
|
||||
}
|
||||
|
||||
logger.info { "Stubs for Kotlin classes: " + jcCompilationUnitsForKotlinClasses.joinToString { it.sourcefile.name } }
|
||||
|
||||
logger.info { "Stubs compilation took $stubCompilationTime ms" }
|
||||
logger.info { "Java stub generation took $jcStubGenerationTime ms" }
|
||||
|
||||
if (stubsOutputDir != null) {
|
||||
saveStubs(stubsOutputDir, jcCompilationUnitsForKotlinClasses)
|
||||
}
|
||||
|
||||
val (annotationProcessingTime) = measureTimeMillis {
|
||||
kaptRunner.doAnnotationProcessing(
|
||||
javaFilesFromJavaSourceRoots, processors,
|
||||
annotationProcessingClasspath, sourcesOutputDir, classFilesOutputDir, jcCompilationUnitsForKotlinClasses)
|
||||
}
|
||||
|
||||
logger.info { "Annotation processing took $annotationProcessingTime ms" }
|
||||
} catch (thr: Throwable) {
|
||||
if (thr !is KaptError || thr.kind != KaptError.Kind.ERROR_RAISED) {
|
||||
logger.exception(thr)
|
||||
}
|
||||
bindingTrace.report(ErrorsKapt3.KAPT3_PROCESSING_ERROR.on(files.first()))
|
||||
return null // Compilation will be aborted anyway because of the error above
|
||||
} finally {
|
||||
generationState.destroy()
|
||||
}
|
||||
|
||||
return if (aptOnly) {
|
||||
doNotGenerateCode()
|
||||
} else {
|
||||
AnalysisResult.RetryWithAdditionalJavaRoots(
|
||||
bindingTrace.bindingContext,
|
||||
module,
|
||||
listOf(sourcesOutputDir),
|
||||
addToEnvironment = true)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> measureTimeMillis(block: () -> T) : Pair<Long, T> {
|
||||
val start = System.currentTimeMillis()
|
||||
val result = block()
|
||||
return Pair(System.currentTimeMillis() - start, result)
|
||||
}
|
||||
|
||||
private fun saveStubs(outputDir: File, 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.packageName?.toString() ?: ""
|
||||
val packageDir = if (packageName.isEmpty()) outputDir else File(outputDir, packageName.replace('.', '/'))
|
||||
packageDir.mkdirs()
|
||||
File(packageDir, className + ".java").writeText(stub.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadProcessors(classpath: List<File>): List<Processor> {
|
||||
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray())
|
||||
return ServiceLoader.load(Processor::class.java, classLoader).toList()
|
||||
}
|
||||
}
|
||||
|
||||
class Kapt3BuilderFactory : ClassBuilderFactory {
|
||||
val compiledClasses = mutableListOf<ClassNode>()
|
||||
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 object : 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)
|
||||
return methodNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException()
|
||||
override fun asBytes(builder: ClassBuilder) = throw UnsupportedOperationException()
|
||||
override fun close() {}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.FieldVisitor
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class Kapt3BuilderFactory : ClassBuilderFactory {
|
||||
val compiledClasses = mutableListOf<ClassNode>()
|
||||
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 object : 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)
|
||||
return methodNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException()
|
||||
override fun asBytes(builder: ClassBuilder) = throw UnsupportedOperationException()
|
||||
override fun close() {}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.kapt3.diagnostic.ErrorsKapt3
|
||||
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.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||
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 Kapt3Extension(
|
||||
val annotationProcessingClasspath: List<File>,
|
||||
val javaSourceRoots: List<File>,
|
||||
val sourcesOutputDir: File,
|
||||
val classFilesOutputDir: File,
|
||||
val stubsOutputDir: File?,
|
||||
val options: Map<String, String>, //TODO
|
||||
val aptOnly: Boolean,
|
||||
val pluginInitializedTime: Long,
|
||||
val logger: KaptLogger
|
||||
) : AnalysisCompletedHandlerExtension {
|
||||
private var annotationProcessingComplete = false
|
||||
|
||||
private fun setAnnotationProcessingComplete(): Boolean {
|
||||
if (annotationProcessingComplete) return true
|
||||
|
||||
annotationProcessingComplete = true
|
||||
return false
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if (files.isEmpty()) {
|
||||
logger.info("No Kotlin source files, aborting")
|
||||
return if (aptOnly) doNotGenerateCode() else null
|
||||
}
|
||||
|
||||
logger.info { "Initial analysis took ${System.currentTimeMillis() - pluginInitializedTime} ms" }
|
||||
logger.info { "Kotlin files to compile: " + files.map { it.virtualFile?.name ?: "<in memory ${it.hashCode()}>" } }
|
||||
|
||||
val processors = loadProcessors(annotationProcessingClasspath)
|
||||
if (processors.isEmpty()) return if (aptOnly) doNotGenerateCode() else null
|
||||
|
||||
val (kaptContext, generationState) = compileStubs(project, module, bindingTrace.bindingContext, files.toList())
|
||||
|
||||
try {
|
||||
val javaSourceFiles = collectJavaSourceFiles()
|
||||
val kotlinSourceStubs = generateKotlinSourceStubs(kaptContext, generationState.typeMapper)
|
||||
|
||||
val (annotationProcessingTime) = measureTimeMillis {
|
||||
kaptContext.doAnnotationProcessing(
|
||||
javaSourceFiles, processors,
|
||||
annotationProcessingClasspath, sourcesOutputDir, classFilesOutputDir, kotlinSourceStubs)
|
||||
}
|
||||
|
||||
logger.info { "Annotation processing took $annotationProcessingTime ms" }
|
||||
} catch (thr: Throwable) {
|
||||
if (thr !is KaptError || thr.kind != KaptError.Kind.ERROR_RAISED) {
|
||||
logger.exception(thr)
|
||||
}
|
||||
bindingTrace.report(ErrorsKapt3.KAPT3_PROCESSING_ERROR.on(files.first()))
|
||||
return null // Compilation will be aborted anyway because of the error above
|
||||
} finally {
|
||||
generationState.destroy()
|
||||
kaptContext.close()
|
||||
}
|
||||
|
||||
return if (aptOnly) {
|
||||
doNotGenerateCode()
|
||||
} else {
|
||||
AnalysisResult.RetryWithAdditionalJavaRoots(
|
||||
bindingTrace.bindingContext,
|
||||
module,
|
||||
listOf(sourcesOutputDir),
|
||||
addToEnvironment = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileStubs(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
files: List<KtFile>
|
||||
): Pair<KaptContext, GenerationState> {
|
||||
val builderFactory = Kapt3BuilderFactory()
|
||||
|
||||
val generationState = GenerationState(
|
||||
project,
|
||||
builderFactory,
|
||||
module,
|
||||
bindingContext,
|
||||
files,
|
||||
CompilerConfiguration.EMPTY)
|
||||
|
||||
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 Pair(KaptContext(logger, compiledClasses, origins), generationState)
|
||||
}
|
||||
|
||||
private fun generateKotlinSourceStubs(kaptContext: KaptContext, typeMapper: KotlinTypeMapper): JavacList<JCCompilationUnit> {
|
||||
val (stubGenerationTime, kotlinSourceStubs) = measureTimeMillis {
|
||||
ClassFileToSourceStubConverter(kaptContext, typeMapper).convert()
|
||||
}
|
||||
|
||||
logger.info { "Java stub generation took $stubGenerationTime ms" }
|
||||
logger.info { "Stubs for Kotlin classes: " + kotlinSourceStubs.joinToString { it.sourcefile.name } }
|
||||
|
||||
if (stubsOutputDir != null) {
|
||||
saveStubs(stubsOutputDir, kotlinSourceStubs)
|
||||
}
|
||||
|
||||
return kotlinSourceStubs
|
||||
}
|
||||
|
||||
private fun saveStubs(outputDir: File, 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.packageName?.toString() ?: ""
|
||||
val packageDir = if (packageName.isEmpty()) outputDir else File(outputDir, packageName.replace('.', '/'))
|
||||
packageDir.mkdirs()
|
||||
File(packageDir, className + ".java").writeText(stub.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectJavaSourceFiles(): List<File> {
|
||||
val javaFilesFromJavaSourceRoots = javaSourceRoots.flatMap {
|
||||
root -> root.walk().filter { it.isFile && it.extension == "java" }.toList()
|
||||
}
|
||||
logger.info { "Java source files: " + javaFilesFromJavaSourceRoots.joinToString { it.canonicalPath } }
|
||||
|
||||
return javaFilesFromJavaSourceRoots
|
||||
}
|
||||
|
||||
private fun loadProcessors(classpath: List<File>): List<Processor> {
|
||||
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray())
|
||||
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.javaClass.canonicalName } }
|
||||
}
|
||||
|
||||
return processors
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> measureTimeMillis(block: () -> T) : Pair<Long, T> {
|
||||
val start = System.currentTimeMillis()
|
||||
val result = block()
|
||||
return Pair(System.currentTimeMillis() - start, result)
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3
|
||||
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||
import java.io.File
|
||||
|
||||
@@ -139,7 +140,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
|
||||
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesKapt3())
|
||||
|
||||
val logger = Logger(isVerbose)
|
||||
val logger = KaptLogger(isVerbose)
|
||||
if (isVerbose) {
|
||||
logger.info("Kapt3 is enabled.")
|
||||
logger.info("Do annotation processing only: $isAptOnly")
|
||||
@@ -151,7 +152,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
logger.info("Options: $apOptions")
|
||||
}
|
||||
|
||||
val kapt3AnalysisCompletedHandlerExtension = Kapt3AnalysisCompletedHandlerExtension(
|
||||
val kapt3AnalysisCompletedHandlerExtension = Kapt3Extension(
|
||||
classpath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, stubsOutputDir, apOptions,
|
||||
isAptOnly, System.currentTimeMillis(), logger)
|
||||
AnalysisCompletedHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.file.JavacFileManager
|
||||
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.kapt3.javac.KaptJavaCompiler
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
||||
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
import javax.tools.JavaFileManager
|
||||
|
||||
class KaptContext(
|
||||
val logger: KaptLogger,
|
||||
val compiledClasses: List<ClassNode>,
|
||||
val origins: Map<Any, JvmDeclarationOrigin>
|
||||
) {
|
||||
val context = Context()
|
||||
val compiler: KaptJavaCompiler
|
||||
val fileManager: JavacFileManager
|
||||
val options: Options
|
||||
|
||||
init {
|
||||
JavacFileManager.preRegister(context)
|
||||
KaptTreeMaker.preRegister(context)
|
||||
KaptJavaCompiler.preRegister(context)
|
||||
|
||||
fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
compiler = JavaCompiler.instance(context) as KaptJavaCompiler
|
||||
|
||||
options = Options.instance(context)
|
||||
}
|
||||
|
||||
fun close() {
|
||||
compiler.close()
|
||||
fileManager.close()
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* 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.JavacMessager
|
||||
import com.sun.tools.javac.processing.JavacProcessingEnvironment
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Log
|
||||
import com.sun.tools.javac.util.Options
|
||||
import java.io.File
|
||||
import javax.annotation.processing.Processor
|
||||
import javax.tools.JavaFileManager
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
class KaptError : RuntimeException {
|
||||
val kind: Kind
|
||||
|
||||
enum class Kind(val message: String) {
|
||||
JAVA_FILE_PARSING_ERROR("Java file parsing error"),
|
||||
EXCEPTION("Exception while annotation processing"),
|
||||
ERROR_RAISED("Error while annotation processing"),
|
||||
UNKNOWN("Unknown error while annotation processing")
|
||||
}
|
||||
|
||||
constructor(kind: Kind) : super(kind.message) {
|
||||
this.kind = kind
|
||||
}
|
||||
|
||||
constructor(kind: Kind, cause: Throwable) : super(kind.message, cause) {
|
||||
this.kind = kind
|
||||
}
|
||||
}
|
||||
|
||||
class KaptRunner(val logger: Logger) {
|
||||
val context = Context()
|
||||
val compiler: KaptJavaCompiler
|
||||
val fileManager: JavacFileManager
|
||||
private val options: Options
|
||||
|
||||
init {
|
||||
JavacFileManager.preRegister(context)
|
||||
KaptTreeMaker.preRegister(context)
|
||||
KaptJavaCompiler.preRegister(context)
|
||||
|
||||
fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
compiler = JavaCompiler.instance(context) as KaptJavaCompiler
|
||||
|
||||
options = Options.instance(context)
|
||||
}
|
||||
|
||||
fun close() {
|
||||
compiler.close()
|
||||
fileManager.close()
|
||||
}
|
||||
|
||||
fun parseJavaFiles(
|
||||
javaSourceFiles: List<File>,
|
||||
classpath: List<File>
|
||||
): JavacList<JCTree.JCCompilationUnit> {
|
||||
classpath.forEach { options.put(Option.CLASSPATH, it.canonicalPath) }
|
||||
|
||||
val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
|
||||
try {
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
return compiler.parseFiles(javaFileObjects)
|
||||
} finally {
|
||||
fileManager.close()
|
||||
compiler.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun doAnnotationProcessing(
|
||||
javaSourceFiles: List<File>,
|
||||
processors: List<Processor>,
|
||||
classpath: List<File>,
|
||||
sourcesOutputDir: File,
|
||||
classesOutputDir: File,
|
||||
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil()
|
||||
) {
|
||||
options.put(Option.PROC, "only") // Only process annotations
|
||||
options.put(Option.CLASSPATH, classpath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
options.put(Option.S, sourcesOutputDir.canonicalPath)
|
||||
options.put(Option.D, classesOutputDir.canonicalPath)
|
||||
|
||||
val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
val processingEnvironment = JavacProcessingEnvironment.instance(context)
|
||||
|
||||
try {
|
||||
compiler.initProcessAnnotations(processors)
|
||||
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
val parsedJavaFiles = compiler.parseFiles(javaFileObjects)
|
||||
if (compiler.shouldStop(CompileStates.CompileState.PARSE)) {
|
||||
throw KaptError(KaptError.Kind.JAVA_FILE_PARSING_ERROR)
|
||||
}
|
||||
|
||||
val log = Log.instance(context)
|
||||
val errorCountBeforeAp = log.nerrors
|
||||
val warningsBeforeAp = log.nwarnings
|
||||
|
||||
val compilerAfterAnnotationProcessing: JavaCompiler? = null
|
||||
try {
|
||||
compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles + additionalSources))
|
||||
} catch (e: AnnotationProcessingError) {
|
||||
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
|
||||
}
|
||||
|
||||
val filer = processingEnvironment.filer as JavacFiler
|
||||
val errorCount = Math.max(log.nerrors, errorCountBeforeAp)
|
||||
val warningCount = log.nwarnings - warningsBeforeAp
|
||||
|
||||
logger.info { "Annotation processing complete, errors: $errorCount, warnings: $warningCount" }
|
||||
if (logger.isVerbose) {
|
||||
filer.displayState()
|
||||
}
|
||||
|
||||
if (log.nerrors > 0) {
|
||||
throw KaptError(KaptError.Kind.ERROR_RAISED)
|
||||
}
|
||||
|
||||
compilerAfterAnnotationProcessing?.close()
|
||||
} finally {
|
||||
processingEnvironment.close()
|
||||
compiler.close()
|
||||
fileManager.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 com.sun.tools.javac.util.Log
|
||||
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
|
||||
import java.io.File
|
||||
import javax.annotation.processing.Processor
|
||||
import javax.tools.JavaFileManager
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
fun KaptContext.doAnnotationProcessing(
|
||||
javaSourceFiles: List<File>,
|
||||
processors: List<Processor>,
|
||||
classpath: List<File>,
|
||||
sourcesOutputDir: File,
|
||||
classesOutputDir: File,
|
||||
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil()
|
||||
) {
|
||||
with (options) {
|
||||
put(Option.PROC, "only") // Only process annotations
|
||||
put(Option.CLASSPATH, classpath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
put(Option.S, sourcesOutputDir.canonicalPath)
|
||||
put(Option.D, classesOutputDir.canonicalPath)
|
||||
}
|
||||
|
||||
val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
val processingEnvironment = JavacProcessingEnvironment.instance(context)
|
||||
|
||||
try {
|
||||
compiler.initProcessAnnotations(processors)
|
||||
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
val parsedJavaFiles = compiler.parseFiles(javaFileObjects)
|
||||
if (compiler.shouldStop(CompileStates.CompileState.PARSE)) {
|
||||
throw KaptError(KaptError.Kind.JAVA_FILE_PARSING_ERROR)
|
||||
}
|
||||
|
||||
val log = Log.instance(context)
|
||||
val errorCountBeforeAp = log.nerrors
|
||||
val warningsBeforeAp = log.nwarnings
|
||||
|
||||
val compilerAfterAnnotationProcessing: JavaCompiler? = null
|
||||
try {
|
||||
compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles + additionalSources))
|
||||
} catch (e: AnnotationProcessingError) {
|
||||
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
|
||||
}
|
||||
|
||||
val filer = processingEnvironment.filer as JavacFiler
|
||||
val errorCount = Math.max(log.nerrors, errorCountBeforeAp)
|
||||
val warningCount = log.nwarnings - warningsBeforeAp
|
||||
|
||||
logger.info { "Annotation processing complete, errors: $errorCount, warnings: $warningCount" }
|
||||
if (logger.isVerbose) {
|
||||
filer.displayState()
|
||||
}
|
||||
|
||||
if (log.nerrors > 0) {
|
||||
throw KaptError(KaptError.Kind.ERROR_RAISED)
|
||||
}
|
||||
|
||||
compilerAfterAnnotationProcessing?.close()
|
||||
} 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.diagnostic
|
||||
|
||||
class KaptError : RuntimeException {
|
||||
val kind: Kind
|
||||
|
||||
enum class Kind(val message: String) {
|
||||
JAVA_FILE_PARSING_ERROR("Java file parsing error"),
|
||||
EXCEPTION("Exception while annotation processing"),
|
||||
ERROR_RAISED("Error while annotation processing"),
|
||||
UNKNOWN("Unknown error while annotation processing")
|
||||
}
|
||||
|
||||
constructor(kind: Kind) : super(kind.message) {
|
||||
this.kind = kind
|
||||
}
|
||||
|
||||
constructor(kind: Kind, cause: Throwable) : super(kind.message, cause) {
|
||||
this.kind = kind
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
package org.jetbrains.kotlin.kapt3.javac
|
||||
|
||||
import com.sun.tools.javac.comp.CompileStates
|
||||
import com.sun.tools.javac.main.JavaCompiler
|
||||
@@ -24,7 +24,7 @@ class KaptJavaCompiler(context: Context) : JavaCompiler(context) {
|
||||
public override fun shouldStop(cs: CompileStates.CompileState) = super.shouldStop(cs)
|
||||
|
||||
companion object {
|
||||
fun preRegister(context: Context) {
|
||||
internal fun preRegister(context: Context) {
|
||||
context.put(compilerKey, Context.Factory<JavaCompiler>(::KaptJavaCompiler))
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
package org.jetbrains.kotlin.kapt3.javac
|
||||
|
||||
import com.sun.tools.javac.file.BaseFileObject
|
||||
import com.sun.tools.javac.file.JavacFileManager
|
||||
@@ -26,7 +26,7 @@ import javax.lang.model.element.Modifier
|
||||
import javax.lang.model.element.NestingKind
|
||||
import javax.tools.JavaFileObject
|
||||
|
||||
class SyntheticJavaFileObject(
|
||||
class KaptJavaFileObject(
|
||||
val compilationUnit: JCTree.JCCompilationUnit,
|
||||
val clazz: JCTree.JCClassDecl,
|
||||
val timestamp: Long,
|
||||
@@ -81,7 +81,7 @@ class SyntheticJavaFileObject(
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
|
||||
other as SyntheticJavaFileObject
|
||||
other as KaptJavaFileObject
|
||||
|
||||
if (compilationUnit != other.compilationUnit) return false
|
||||
if (clazz != other.clazz) return false
|
||||
+10
-10
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
package org.jetbrains.kotlin.kapt3.javac
|
||||
|
||||
import com.sun.tools.javac.code.TypeTag
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
@@ -24,23 +24,23 @@ import com.sun.tools.javac.util.Names
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Type.*
|
||||
|
||||
class KaptTreeMaker(context: Context?) : TreeMaker(context) {
|
||||
class KaptTreeMaker(context: Context) : TreeMaker(context) {
|
||||
private val nameTable = Names.instance(context).table
|
||||
|
||||
fun convertType(type: Type): JCTree.JCExpression {
|
||||
fun Type(type: Type): JCTree.JCExpression {
|
||||
convertBuiltinType(type)?.let { return it }
|
||||
if (type.sort == ARRAY) {
|
||||
return TypeArray(convertType(type.elementType))
|
||||
return TypeArray(Type(type.elementType))
|
||||
}
|
||||
return convertFqName(type.className)
|
||||
return FqName(type.className)
|
||||
}
|
||||
|
||||
fun convertFqName(internalOrFqName: String): JCTree.JCExpression {
|
||||
fun FqName(internalOrFqName: String): JCTree.JCExpression {
|
||||
val path = internalOrFqName.replace('/', '.').split('.')
|
||||
assert(path.isNotEmpty())
|
||||
if (path.size == 1) return convertSimpleName(path.single())
|
||||
if (path.size == 1) return SimpleName(path.single())
|
||||
|
||||
var expr = Select(convertSimpleName(path[0]), name(path[1]))
|
||||
var expr = Select(SimpleName(path[0]), name(path[1]))
|
||||
for (index in 2..path.lastIndex) {
|
||||
expr = Select(expr, name(path[index]))
|
||||
}
|
||||
@@ -63,12 +63,12 @@ class KaptTreeMaker(context: Context?) : TreeMaker(context) {
|
||||
return TypeIdent(typeTag)
|
||||
}
|
||||
|
||||
fun convertSimpleName(name: String): JCTree.JCExpression = Ident(name(name))
|
||||
fun SimpleName(name: String): JCTree.JCExpression = Ident(name(name))
|
||||
|
||||
fun name(name: String) = nameTable.fromString(name)
|
||||
|
||||
companion object {
|
||||
fun preRegister(context: Context) {
|
||||
internal fun preRegister(context: Context) {
|
||||
context.put(treeMakerKey, Context.Factory<TreeMaker>(::KaptTreeMaker))
|
||||
}
|
||||
}
|
||||
+32
-84
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
package org.jetbrains.kotlin.kapt3.stubs
|
||||
|
||||
import com.sun.tools.javac.code.Flags
|
||||
import com.sun.tools.javac.code.TypeTag
|
||||
@@ -22,28 +22,25 @@ import com.sun.tools.javac.file.JavacFileManager
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.tree.JCTree.*
|
||||
import com.sun.tools.javac.tree.TreeMaker
|
||||
import com.sun.tools.javac.util.Context
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
|
||||
import org.jetbrains.kotlin.kapt3.util.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.util.*
|
||||
import javax.lang.model.element.ElementKind
|
||||
import javax.tools.JavaFileManager
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
class JCTreeConverter(
|
||||
context: Context,
|
||||
val typeMapper: KotlinTypeMapper,
|
||||
val classes: List<ClassNode>,
|
||||
val origins: Map<Any, JvmDeclarationOrigin>
|
||||
) {
|
||||
class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMapper: KotlinTypeMapper) {
|
||||
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()
|
||||
@@ -68,20 +65,20 @@ class JCTreeConverter(
|
||||
)
|
||||
}
|
||||
|
||||
private val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
private val treeMaker = TreeMaker.instance(context) as KaptTreeMaker
|
||||
private val fileManager = kaptContext.context.get(JavaFileManager::class.java) as JavacFileManager
|
||||
private val treeMaker = TreeMaker.instance(kaptContext.context) as KaptTreeMaker
|
||||
private val signatureParser = SignatureParser(treeMaker)
|
||||
|
||||
private var done = false
|
||||
|
||||
fun convert(): JavacList<JCCompilationUnit> {
|
||||
if (done) error(JCTreeConverter::class.java.simpleName + " can convert classes only once")
|
||||
if (done) error(ClassFileToSourceStubConverter::class.java.simpleName + " can convert classes only once")
|
||||
done = true
|
||||
return mapValues(classes) { convertTopLevelClass(it) }
|
||||
return mapValues(kaptContext.compiledClasses) { convertTopLevelClass(it) }
|
||||
}
|
||||
|
||||
private fun convertTopLevelClass(clazz: ClassNode): JCCompilationUnit? {
|
||||
val origin = origins[clazz] ?: return null
|
||||
val origin = kaptContext.origins[clazz] ?: return null
|
||||
val ktFile = origin.element?.containingFile as? KtFile ?: return null
|
||||
val descriptor = origin.descriptor as? ClassDescriptor ?: return null
|
||||
|
||||
@@ -92,13 +89,13 @@ class JCTreeConverter(
|
||||
|
||||
val packageAnnotations = JavacList.nil<JCAnnotation>()
|
||||
val packageName = ktFile.packageFqName.asString()
|
||||
val packageClause = if (packageName.isEmpty()) null else treeMaker.convertFqName(packageName)
|
||||
val packageClause = if (packageName.isEmpty()) null else treeMaker.FqName(packageName)
|
||||
|
||||
val imports = JavacList.nil<JCTree>()
|
||||
val classes = JavacList.of<JCTree>(classDeclaration)
|
||||
|
||||
val topLevel = treeMaker.TopLevel(packageAnnotations, packageClause, imports + classes)
|
||||
val javaFileObject = SyntheticJavaFileObject(topLevel, classDeclaration, System.currentTimeMillis(), fileManager)
|
||||
val javaFileObject = KaptJavaFileObject(topLevel, classDeclaration, System.currentTimeMillis(), fileManager)
|
||||
topLevel.sourcefile = javaFileObject
|
||||
return topLevel
|
||||
}
|
||||
@@ -109,7 +106,7 @@ class JCTreeConverter(
|
||||
private fun convertClass(clazz: ClassNode, isTopLevel: Boolean): JCClassDecl? {
|
||||
if (isSynthetic(clazz.access)) return null
|
||||
|
||||
val descriptor = origins[clazz]?.descriptor as? ClassDescriptor ?: return null
|
||||
val descriptor = kaptContext.origins[clazz]?.descriptor as? ClassDescriptor ?: return null
|
||||
val modifiers = convertModifiers(
|
||||
if (!descriptor.isInner && descriptor.isNested) (clazz.access or Opcodes.ACC_STATIC) else clazz.access,
|
||||
ElementKind.CLASS, clazz.visibleAnnotations, clazz.invisibleAnnotations)
|
||||
@@ -130,10 +127,10 @@ class JCTreeConverter(
|
||||
|
||||
val interfaces = mapValues(clazz.interfaces) {
|
||||
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapValues null
|
||||
treeMaker.convertFqName(it)
|
||||
treeMaker.FqName(it)
|
||||
}
|
||||
|
||||
val superClass = treeMaker.convertFqName(clazz.superName)
|
||||
val superClass = treeMaker.FqName(clazz.superName)
|
||||
|
||||
val hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum
|
||||
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
|
||||
@@ -149,7 +146,7 @@ class JCTreeConverter(
|
||||
}
|
||||
val nestedClasses = mapValues<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
|
||||
if (innerClass.outerName != clazz.name) return@mapValues null
|
||||
val innerClassNode = classes.firstOrNull { it.name == innerClass.name } ?: return@mapValues null
|
||||
val innerClassNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ?: return@mapValues null
|
||||
convertClass(innerClassNode, false)
|
||||
}
|
||||
|
||||
@@ -171,9 +168,9 @@ class JCTreeConverter(
|
||||
|
||||
// Enum type must be an identifier (Javac requirement)
|
||||
val typeExpression = if (isEnum(field.access)) {
|
||||
treeMaker.convertSimpleName(type.className.substringAfterLast('.'))
|
||||
treeMaker.SimpleName(type.className.substringAfterLast('.'))
|
||||
} else {
|
||||
signatureParser.parseFieldSignature(field.signature, treeMaker.convertType(type))
|
||||
signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type))
|
||||
}
|
||||
|
||||
val value = field.value
|
||||
@@ -189,7 +186,7 @@ class JCTreeConverter(
|
||||
|
||||
private fun convertMethod(method: MethodNode, containingClass: ClassNode): JCMethodDecl? {
|
||||
if (isSynthetic(method.access)) return null
|
||||
val descriptor = origins[method]?.descriptor as? CallableDescriptor ?: return null
|
||||
val descriptor = kaptContext.origins[method]?.descriptor as? CallableDescriptor ?: return null
|
||||
|
||||
val isOverridden = descriptor.overriddenDescriptors.isNotEmpty()
|
||||
val visibleAnnotations = if (isOverridden) {
|
||||
@@ -206,7 +203,7 @@ class JCTreeConverter(
|
||||
val name = treeMaker.name(method.name)
|
||||
|
||||
val returnType = Type.getReturnType(method.desc)
|
||||
val jcReturnType = if (isConstructor) null else treeMaker.convertType(returnType)
|
||||
val jcReturnType = if (isConstructor) null else treeMaker.Type(returnType)
|
||||
|
||||
val parametersInfo = method.getParametersInfo(containingClass)
|
||||
@Suppress("NAME_SHADOWING")
|
||||
@@ -219,11 +216,11 @@ class JCTreeConverter(
|
||||
info.flags or varargs or Flags.PARAMETER,
|
||||
ElementKind.PARAMETER, info.visibleAnnotations, info.invisibleAnnotations)
|
||||
val name = treeMaker.name(info.name)
|
||||
val type = treeMaker.convertType(info.type)
|
||||
val type = treeMaker.Type(info.type)
|
||||
treeMaker.VarDef(modifiers, name, type, null)
|
||||
}
|
||||
|
||||
val exceptionTypes = mapValues(method.exceptions) { treeMaker.convertFqName(it) }
|
||||
val exceptionTypes = mapValues(method.exceptions) { treeMaker.FqName(it) }
|
||||
|
||||
val genericType = signatureParser.parseMethodSignature(method.signature, parameters, exceptionTypes, jcReturnType)
|
||||
|
||||
@@ -237,7 +234,7 @@ class JCTreeConverter(
|
||||
treeMaker.Block(0, JavacList.nil())
|
||||
} else if (isConstructor) {
|
||||
// We already checked it in convertClass()
|
||||
val declaration = origins[containingClass]?.descriptor as ClassDescriptor
|
||||
val declaration = kaptContext.origins[containingClass]?.descriptor as ClassDescriptor
|
||||
val superClass = declaration.getSuperClassOrAny()
|
||||
val superClassConstructor = superClass.constructors.firstOrNull { it.visibility.isVisible(null, it, declaration) }
|
||||
|
||||
@@ -245,7 +242,7 @@ class JCTreeConverter(
|
||||
val args = mapValues(superClassConstructor.valueParameters) { param ->
|
||||
convertLiteralExpression(getDefaultValue(typeMapper.mapType(param.type)))
|
||||
}
|
||||
val call = treeMaker.Apply(JavacList.nil(), treeMaker.convertSimpleName("super"), args)
|
||||
val call = treeMaker.Apply(JavacList.nil(), treeMaker.SimpleName("super"), args)
|
||||
JavacList.of<JCStatement>(treeMaker.Exec(call))
|
||||
} else {
|
||||
JavacList.nil<JCStatement>()
|
||||
@@ -301,9 +298,9 @@ class JCTreeConverter(
|
||||
val fqName = annotationType.className
|
||||
if (BLACKLISTED_ANNOTATATIONS.any { fqName.startsWith(it) }) return null
|
||||
|
||||
val name = treeMaker.convertType(annotationType)
|
||||
val name = treeMaker.Type(annotationType)
|
||||
val values = mapPairedValues<JCExpression>(annotation.values) { key, value ->
|
||||
treeMaker.Assign(treeMaker.convertSimpleName(key), convertLiteralExpression(value))
|
||||
treeMaker.Assign(treeMaker.SimpleName(key), convertLiteralExpression(value))
|
||||
}
|
||||
return treeMaker.Annotation(name, values)
|
||||
}
|
||||
@@ -326,11 +323,11 @@ class JCTreeConverter(
|
||||
assert(value.size == 2)
|
||||
val enumType = Type.getType(value[0] as String)
|
||||
val valueName = value[1] as String
|
||||
treeMaker.Select(treeMaker.convertType(enumType), treeMaker.name(valueName))
|
||||
treeMaker.Select(treeMaker.Type(enumType), treeMaker.name(valueName))
|
||||
}
|
||||
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), mapValues(value) { convertLiteralExpression(it) })
|
||||
is List<*> -> treeMaker.NewArray(null, JavacList.nil(), org.jetbrains.kotlin.kapt3.mapValues(value) { convertLiteralExpression(it) })
|
||||
|
||||
is Type -> treeMaker.Select(treeMaker.convertType(value), treeMaker.name("class"))
|
||||
is Type -> treeMaker.Select(treeMaker.Type(value), treeMaker.name("class"))
|
||||
is AnnotationNode -> convertAnnotation(value) ?: error("Annotation is filtered out")
|
||||
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value.javaClass.canonicalName})")
|
||||
}
|
||||
@@ -349,54 +346,5 @@ class JCTreeConverter(
|
||||
}
|
||||
}
|
||||
|
||||
private class ParameterInfo(
|
||||
val flags: Long,
|
||||
val name: String,
|
||||
val type: Type,
|
||||
val visibleAnnotations: List<AnnotationNode>?,
|
||||
val invisibleAnnotations: List<AnnotationNode>?)
|
||||
|
||||
private fun MethodNode.getParametersInfo(containingClass: ClassNode): List<ParameterInfo> {
|
||||
val localVariables = this.localVariables ?: emptyList()
|
||||
val parameters = this.parameters ?: emptyList()
|
||||
val isStatic = isStatic(access)
|
||||
|
||||
// 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]
|
||||
var name = parameters.getOrNull(index - startParameterIndex)?.name
|
||||
?: localVariables.getOrNull(index + (if (isStatic) 0 else 1))?.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
|
||||
}
|
||||
|
||||
private val ClassDescriptor.isNested: Boolean
|
||||
get() = containingDeclaration is ClassDescriptor
|
||||
|
||||
private fun isEnum(access: Int) = (access and Opcodes.ACC_ENUM) > 0
|
||||
private fun isPublic(access: Int) = (access and Opcodes.ACC_PUBLIC) > 0
|
||||
private fun isSynthetic(access: Int) = (access and Opcodes.ACC_SYNTHETIC) > 0
|
||||
private fun isFinal(access: Int) = (access and Opcodes.ACC_FINAL) > 0
|
||||
private fun isStatic(access: Int) = (access and Opcodes.ACC_STATIC) > 0
|
||||
private fun isAbstract(access: Int) = (access and Opcodes.ACC_ABSTRACT) > 0
|
||||
private fun ClassNode.isEnum() = (access and Opcodes.ACC_ENUM) > 0
|
||||
private fun ClassNode.isAnnotation() = (access and Opcodes.ACC_ANNOTATION) > 0
|
||||
private fun MethodNode.isVarargs() = (access and Opcodes.ACC_VARARGS) > 0
|
||||
|
||||
private fun <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
|
||||
get() = containingDeclaration is ClassDescriptor
|
||||
+19
-16
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
package org.jetbrains.kotlin.kapt3.stubs
|
||||
|
||||
import com.sun.tools.javac.code.BoundKind
|
||||
import com.sun.tools.javac.code.TypeTag
|
||||
@@ -22,7 +22,10 @@ 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.ElementKind.*
|
||||
import org.jetbrains.kotlin.kapt3.stubs.ElementKind.*
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
|
||||
import org.jetbrains.kotlin.kapt3.mapValues
|
||||
import org.jetbrains.kotlin.kapt3.mapValuesIndexed
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
@@ -76,35 +79,35 @@ import com.sun.tools.javac.util.List as JavacList
|
||||
+ ClassType
|
||||
*/
|
||||
|
||||
enum class ElementKind {
|
||||
internal enum class ElementKind {
|
||||
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, TypeArgument, ParameterType, ReturnType, ExceptionType,
|
||||
ClassType, TypeVariable, PrimitiveType, ArrayType
|
||||
}
|
||||
|
||||
class SignatureNode(val kind: ElementKind, val name: String? = null) {
|
||||
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 typeParameters: com.sun.tools.javac.util.List<JCTypeParameter>,
|
||||
val superClass: JCExpression,
|
||||
val interfaces: JavacList<JCExpression>)
|
||||
val interfaces: com.sun.tools.javac.util.List<JCExpression>)
|
||||
|
||||
class MethodGenericSignature(
|
||||
val typeParameters: JavacList<JCTypeParameter>,
|
||||
val parameterTypes: JavacList<JCVariableDecl>,
|
||||
val exceptionTypes: JavacList<JCExpression>,
|
||||
val typeParameters: com.sun.tools.javac.util.List<JCTypeParameter>,
|
||||
val parameterTypes: com.sun.tools.javac.util.List<JCVariableDecl>,
|
||||
val exceptionTypes: com.sun.tools.javac.util.List<JCExpression>,
|
||||
val returnType: JCExpression?
|
||||
)
|
||||
|
||||
fun parseClassSignature(
|
||||
signature: String?,
|
||||
rawSuperClass: JCExpression,
|
||||
rawInterfaces: JavacList<JCExpression>
|
||||
rawInterfaces: com.sun.tools.javac.util.List<JCExpression>
|
||||
): ClassGenericSignature {
|
||||
if (signature == null) {
|
||||
return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces)
|
||||
return ClassGenericSignature(com.sun.tools.javac.util.List.nil(), rawSuperClass, rawInterfaces)
|
||||
}
|
||||
|
||||
val root = parse(signature)
|
||||
@@ -121,12 +124,12 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
|
||||
fun parseMethodSignature(
|
||||
signature: String?,
|
||||
rawParameters: JavacList<JCVariableDecl>,
|
||||
rawExceptionTypes: JavacList<JCExpression>,
|
||||
rawParameters: com.sun.tools.javac.util.List<JCVariableDecl>,
|
||||
rawExceptionTypes: com.sun.tools.javac.util.List<JCExpression>,
|
||||
rawReturnType: JCExpression?
|
||||
): MethodGenericSignature {
|
||||
if (signature == null) {
|
||||
return MethodGenericSignature(JavacList.nil(), rawParameters, rawExceptionTypes, rawReturnType)
|
||||
return MethodGenericSignature(com.sun.tools.javac.util.List.nil(), rawParameters, rawExceptionTypes, rawReturnType)
|
||||
}
|
||||
|
||||
val root = parse(signature)
|
||||
@@ -186,7 +189,7 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
ClassType -> {
|
||||
val classFqName = node.name!!.replace('/', '.')
|
||||
val args = node.children
|
||||
val fqNameExpression = treeMaker.convertFqName(classFqName)
|
||||
val fqNameExpression = treeMaker.FqName(classFqName)
|
||||
if (args.isEmpty()) return fqNameExpression
|
||||
|
||||
treeMaker.TypeApply(fqNameExpression, mapValues(args) { arg ->
|
||||
@@ -202,7 +205,7 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||
}
|
||||
})
|
||||
}
|
||||
TypeVariable -> treeMaker.convertSimpleName(node.name!!)
|
||||
TypeVariable -> treeMaker.SimpleName(node.name!!)
|
||||
ArrayType -> treeMaker.TypeArray(parseType(node.children.single()))
|
||||
PrimitiveType -> {
|
||||
val typeTag = when (node.name!!.single()) {
|
||||
@@ -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.stubs
|
||||
|
||||
import org.jetbrains.kotlin.kapt3.util.isEnum
|
||||
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)
|
||||
|
||||
// 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]
|
||||
var name = parameters.getOrNull(index - startParameterIndex)?.name
|
||||
?: localVariables.getOrNull(index + (if (isStatic) 0 else 1))?.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
|
||||
}
|
||||
+2
-2
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
package org.jetbrains.kotlin.kapt3.util
|
||||
|
||||
class Logger(val isVerbose: Boolean) {
|
||||
class KaptLogger(val isVerbose: Boolean) {
|
||||
private companion object {
|
||||
val PREFIX = "[kapt] "
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.tree.ClassNode
|
||||
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 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 <T> List<T>?.isNullOrEmpty() = this == null || this.isEmpty()
|
||||
+1
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
internal inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
|
||||
@@ -18,19 +18,16 @@ 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
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestUtil
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.kapt3.JCTreeConverter
|
||||
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
|
||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
||||
import org.jetbrains.kotlin.kapt3.Logger
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
||||
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
@@ -51,35 +48,29 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory)
|
||||
val typeMapper = factory.generationState.typeMapper
|
||||
|
||||
val logger = Logger(isVerbose = true)
|
||||
val kaptRunner = KaptRunner(logger)
|
||||
val logger = KaptLogger(isVerbose = true)
|
||||
val kaptContext = KaptContext(logger, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
||||
try {
|
||||
check(kaptRunner, typeMapper, classBuilderFactory, txtFile)
|
||||
check(kaptContext, typeMapper, txtFile)
|
||||
} finally {
|
||||
kaptRunner.close()
|
||||
kaptContext.close()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun convert(
|
||||
kaptRunner: KaptRunner,
|
||||
typeMapper: KotlinTypeMapper,
|
||||
compiledClasses: List<ClassNode>,
|
||||
origins: Map<Any, JvmDeclarationOrigin>
|
||||
): JavacList<JCTree.JCCompilationUnit> {
|
||||
val converter = JCTreeConverter(kaptRunner.context, typeMapper, compiledClasses, origins)
|
||||
protected fun convert(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper): JavacList<JCCompilationUnit> {
|
||||
val converter = ClassFileToSourceStubConverter(kaptRunner, typeMapper)
|
||||
return converter.convert()
|
||||
}
|
||||
|
||||
protected abstract fun check(
|
||||
kaptRunner: KaptRunner,
|
||||
kaptRunner: KaptContext,
|
||||
typeMapper: KotlinTypeMapper,
|
||||
classBuilderFactory: Kapt3BuilderFactory,
|
||||
txtFile: File)
|
||||
}
|
||||
|
||||
abstract class AbstractJCTreeConverterTest : AbstractKotlinKapt3Test() {
|
||||
override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) {
|
||||
val javaFiles = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
||||
abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test() {
|
||||
override fun check(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper, txtFile: File) {
|
||||
val javaFiles = convert(kaptRunner, typeMapper)
|
||||
kaptRunner.compiler.enterTrees(javaFiles)
|
||||
|
||||
val actualRaw = javaFiles.joinToString (FILE_SEPARATOR)
|
||||
@@ -93,8 +84,8 @@ abstract class AbstractJCTreeConverterTest : AbstractKotlinKapt3Test() {
|
||||
}
|
||||
|
||||
abstract class AbstractKotlinKaptRunnerTest : AbstractKotlinKapt3Test() {
|
||||
override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) {
|
||||
val compilationUnits = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
||||
override fun check(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper, txtFile: File) {
|
||||
val compilationUnits = convert(kaptRunner, typeMapper)
|
||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||
try {
|
||||
kaptRunner.doAnnotationProcessing(emptyList(), listOf(KaptRunnerTest.simpleProcessor()),
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
|
||||
@TestMetadata("plugins/kapt3/testData/converter")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class JCTreeConverterTestGenerated extends AbstractJCTreeConverterTest {
|
||||
public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFileToSourceStubConverterTest {
|
||||
public void testAllFilesPresentInConverter() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/testData/converter"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
@@ -16,14 +16,16 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.test
|
||||
|
||||
import org.jetbrains.kotlin.kapt3.KaptError
|
||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
||||
import org.jetbrains.kotlin.kapt3.Logger
|
||||
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.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
|
||||
|
||||
@@ -72,16 +74,20 @@ class KaptRunnerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) {
|
||||
KaptContext(KaptLogger(isVerbose = true), emptyList(), emptyMap()).doAnnotationProcessing(
|
||||
listOf(javaSourceFile),
|
||||
listOf(processor),
|
||||
emptyList(), // classpath
|
||||
outputDir,
|
||||
outputDir)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimple() {
|
||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||
try {
|
||||
KaptRunner(Logger(isVerbose = true)).doAnnotationProcessing(
|
||||
listOf(File(TEST_DATA_DIR, "Simple.java")),
|
||||
listOf(simpleProcessor()),
|
||||
emptyList(), // classpath
|
||||
sourceOutputDir,
|
||||
sourceOutputDir)
|
||||
doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), simpleProcessor(), sourceOutputDir)
|
||||
val myMethodFile = File(sourceOutputDir, "generated/MyMethodMyAnnotation.java")
|
||||
assertTrue(myMethodFile.exists())
|
||||
} finally {
|
||||
@@ -102,12 +108,7 @@ class KaptRunnerTest {
|
||||
}
|
||||
|
||||
try {
|
||||
KaptRunner(Logger(isVerbose = true)).doAnnotationProcessing(
|
||||
listOf(File(TEST_DATA_DIR, "Simple.java")),
|
||||
listOf(processor),
|
||||
emptyList(),
|
||||
TEST_DATA_DIR,
|
||||
TEST_DATA_DIR)
|
||||
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)
|
||||
@@ -116,15 +117,14 @@ class KaptRunnerTest {
|
||||
|
||||
@Test
|
||||
fun testParsingError() {
|
||||
var catched = false
|
||||
try {
|
||||
KaptRunner(Logger(isVerbose = true)).doAnnotationProcessing(
|
||||
listOf(File(TEST_DATA_DIR, "ParseError.java")),
|
||||
listOf(simpleProcessor()),
|
||||
emptyList(),
|
||||
TEST_DATA_DIR,
|
||||
TEST_DATA_DIR)
|
||||
doAnnotationProcessing(File(TEST_DATA_DIR, "ParseError.java"), simpleProcessor(), TEST_DATA_DIR)
|
||||
} catch (e: KaptError) {
|
||||
assertEquals(KaptError.Kind.JAVA_FILE_PARSING_ERROR, e.kind)
|
||||
catched = true
|
||||
}
|
||||
|
||||
assertTrue("Exception was not catched", catched)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user