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.compiler.*
|
||||||
import org.jetbrains.kotlin.jvm.runtime.AbstractJvm8RuntimeDescriptorLoaderTest
|
import org.jetbrains.kotlin.jvm.runtime.AbstractJvm8RuntimeDescriptorLoaderTest
|
||||||
import org.jetbrains.kotlin.jvm.runtime.AbstractJvmRuntimeDescriptorLoaderTest
|
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.kapt3.test.AbstractKotlinKaptRunnerTest
|
||||||
import org.jetbrains.kotlin.kdoc.AbstractKDocLexerTest
|
import org.jetbrains.kotlin.kdoc.AbstractKDocLexerTest
|
||||||
import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBoxTest
|
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") {
|
testGroup("plugins/kapt3/test", "plugins/kapt3/testData") {
|
||||||
testClass<AbstractJCTreeConverterTest> {
|
testClass<AbstractClassFileToSourceStubConverterTest> {
|
||||||
model("converter")
|
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.config.JVMConfigurationKeys
|
||||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||||
import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3
|
import org.jetbrains.kotlin.kapt3.diagnostic.DefaultErrorMessagesKapt3
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
|||||||
|
|
||||||
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesKapt3())
|
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesKapt3())
|
||||||
|
|
||||||
val logger = Logger(isVerbose)
|
val logger = KaptLogger(isVerbose)
|
||||||
if (isVerbose) {
|
if (isVerbose) {
|
||||||
logger.info("Kapt3 is enabled.")
|
logger.info("Kapt3 is enabled.")
|
||||||
logger.info("Do annotation processing only: $isAptOnly")
|
logger.info("Do annotation processing only: $isAptOnly")
|
||||||
@@ -151,7 +152,7 @@ class Kapt3ComponentRegistrar : ComponentRegistrar {
|
|||||||
logger.info("Options: $apOptions")
|
logger.info("Options: $apOptions")
|
||||||
}
|
}
|
||||||
|
|
||||||
val kapt3AnalysisCompletedHandlerExtension = Kapt3AnalysisCompletedHandlerExtension(
|
val kapt3AnalysisCompletedHandlerExtension = Kapt3Extension(
|
||||||
classpath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, stubsOutputDir, apOptions,
|
classpath, javaSourceRoots, sourcesOutputDir, classFilesOutputDir, stubsOutputDir, apOptions,
|
||||||
isAptOnly, System.currentTimeMillis(), logger)
|
isAptOnly, System.currentTimeMillis(), logger)
|
||||||
AnalysisCompletedHandlerExtension.registerExtension(project, kapt3AnalysisCompletedHandlerExtension)
|
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.
|
* 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.comp.CompileStates
|
||||||
import com.sun.tools.javac.main.JavaCompiler
|
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)
|
public override fun shouldStop(cs: CompileStates.CompileState) = super.shouldStop(cs)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun preRegister(context: Context) {
|
internal fun preRegister(context: Context) {
|
||||||
context.put(compilerKey, Context.Factory<JavaCompiler>(::KaptJavaCompiler))
|
context.put(compilerKey, Context.Factory<JavaCompiler>(::KaptJavaCompiler))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* 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.BaseFileObject
|
||||||
import com.sun.tools.javac.file.JavacFileManager
|
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.lang.model.element.NestingKind
|
||||||
import javax.tools.JavaFileObject
|
import javax.tools.JavaFileObject
|
||||||
|
|
||||||
class SyntheticJavaFileObject(
|
class KaptJavaFileObject(
|
||||||
val compilationUnit: JCTree.JCCompilationUnit,
|
val compilationUnit: JCTree.JCCompilationUnit,
|
||||||
val clazz: JCTree.JCClassDecl,
|
val clazz: JCTree.JCClassDecl,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
@@ -81,7 +81,7 @@ class SyntheticJavaFileObject(
|
|||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other?.javaClass != javaClass) return false
|
if (other?.javaClass != javaClass) return false
|
||||||
|
|
||||||
other as SyntheticJavaFileObject
|
other as KaptJavaFileObject
|
||||||
|
|
||||||
if (compilationUnit != other.compilationUnit) return false
|
if (compilationUnit != other.compilationUnit) return false
|
||||||
if (clazz != other.clazz) return false
|
if (clazz != other.clazz) return false
|
||||||
+10
-10
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* 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.code.TypeTag
|
||||||
import com.sun.tools.javac.tree.JCTree
|
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
|
||||||
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
|
private val nameTable = Names.instance(context).table
|
||||||
|
|
||||||
fun convertType(type: Type): JCTree.JCExpression {
|
fun Type(type: Type): JCTree.JCExpression {
|
||||||
convertBuiltinType(type)?.let { return it }
|
convertBuiltinType(type)?.let { return it }
|
||||||
if (type.sort == ARRAY) {
|
if (type.sort == ARRAY) {
|
||||||
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('.')
|
val path = internalOrFqName.replace('/', '.').split('.')
|
||||||
assert(path.isNotEmpty())
|
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) {
|
for (index in 2..path.lastIndex) {
|
||||||
expr = Select(expr, name(path[index]))
|
expr = Select(expr, name(path[index]))
|
||||||
}
|
}
|
||||||
@@ -63,12 +63,12 @@ class KaptTreeMaker(context: Context?) : TreeMaker(context) {
|
|||||||
return TypeIdent(typeTag)
|
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)
|
fun name(name: String) = nameTable.fromString(name)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun preRegister(context: Context) {
|
internal fun preRegister(context: Context) {
|
||||||
context.put(treeMakerKey, Context.Factory<TreeMaker>(::KaptTreeMaker))
|
context.put(treeMakerKey, Context.Factory<TreeMaker>(::KaptTreeMaker))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+31
-83
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* 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.Flags
|
||||||
import com.sun.tools.javac.code.TypeTag
|
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.JCTree.*
|
import com.sun.tools.javac.tree.JCTree.*
|
||||||
import com.sun.tools.javac.tree.TreeMaker
|
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.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
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.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
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.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import java.util.*
|
|
||||||
import javax.lang.model.element.ElementKind
|
import javax.lang.model.element.ElementKind
|
||||||
import javax.tools.JavaFileManager
|
import javax.tools.JavaFileManager
|
||||||
import com.sun.tools.javac.util.List as JavacList
|
import com.sun.tools.javac.util.List as JavacList
|
||||||
|
|
||||||
class JCTreeConverter(
|
class ClassFileToSourceStubConverter(val kaptContext: KaptContext, val typeMapper: KotlinTypeMapper) {
|
||||||
context: Context,
|
|
||||||
val typeMapper: KotlinTypeMapper,
|
|
||||||
val classes: List<ClassNode>,
|
|
||||||
val origins: Map<Any, JvmDeclarationOrigin>
|
|
||||||
) {
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
|
private val VISIBILITY_MODIFIERS = (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).toLong()
|
||||||
private val MODALITY_MODIFIERS = (Opcodes.ACC_FINAL or Opcodes.ACC_ABSTRACT).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 fileManager = kaptContext.context.get(JavaFileManager::class.java) as JavacFileManager
|
||||||
private val treeMaker = TreeMaker.instance(context) as KaptTreeMaker
|
private val treeMaker = TreeMaker.instance(kaptContext.context) as KaptTreeMaker
|
||||||
private val signatureParser = SignatureParser(treeMaker)
|
private val signatureParser = SignatureParser(treeMaker)
|
||||||
|
|
||||||
private var done = false
|
private var done = false
|
||||||
|
|
||||||
fun convert(): JavacList<JCCompilationUnit> {
|
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
|
done = true
|
||||||
return mapValues(classes) { convertTopLevelClass(it) }
|
return mapValues(kaptContext.compiledClasses) { convertTopLevelClass(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertTopLevelClass(clazz: ClassNode): JCCompilationUnit? {
|
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 ktFile = origin.element?.containingFile as? KtFile ?: return null
|
||||||
val descriptor = origin.descriptor as? ClassDescriptor ?: return null
|
val descriptor = origin.descriptor as? ClassDescriptor ?: return null
|
||||||
|
|
||||||
@@ -92,13 +89,13 @@ class JCTreeConverter(
|
|||||||
|
|
||||||
val packageAnnotations = JavacList.nil<JCAnnotation>()
|
val packageAnnotations = JavacList.nil<JCAnnotation>()
|
||||||
val packageName = ktFile.packageFqName.asString()
|
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 imports = JavacList.nil<JCTree>()
|
||||||
val classes = JavacList.of<JCTree>(classDeclaration)
|
val classes = JavacList.of<JCTree>(classDeclaration)
|
||||||
|
|
||||||
val topLevel = treeMaker.TopLevel(packageAnnotations, packageClause, imports + classes)
|
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
|
topLevel.sourcefile = javaFileObject
|
||||||
return topLevel
|
return topLevel
|
||||||
}
|
}
|
||||||
@@ -109,7 +106,7 @@ class JCTreeConverter(
|
|||||||
private fun convertClass(clazz: ClassNode, isTopLevel: Boolean): JCClassDecl? {
|
private fun convertClass(clazz: ClassNode, isTopLevel: Boolean): JCClassDecl? {
|
||||||
if (isSynthetic(clazz.access)) return null
|
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(
|
val modifiers = convertModifiers(
|
||||||
if (!descriptor.isInner && descriptor.isNested) (clazz.access or Opcodes.ACC_STATIC) else clazz.access,
|
if (!descriptor.isInner && descriptor.isNested) (clazz.access or Opcodes.ACC_STATIC) else clazz.access,
|
||||||
ElementKind.CLASS, clazz.visibleAnnotations, clazz.invisibleAnnotations)
|
ElementKind.CLASS, clazz.visibleAnnotations, clazz.invisibleAnnotations)
|
||||||
@@ -130,10 +127,10 @@ class JCTreeConverter(
|
|||||||
|
|
||||||
val interfaces = mapValues(clazz.interfaces) {
|
val interfaces = mapValues(clazz.interfaces) {
|
||||||
if (isAnnotation && it == "java/lang/annotation/Annotation") return@mapValues null
|
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 hasSuperClass = clazz.superName != "java/lang/Object" && !isEnum
|
||||||
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
|
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
|
||||||
@@ -149,7 +146,7 @@ class JCTreeConverter(
|
|||||||
}
|
}
|
||||||
val nestedClasses = mapValues<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
|
val nestedClasses = mapValues<InnerClassNode, JCTree>(clazz.innerClasses) { innerClass ->
|
||||||
if (innerClass.outerName != clazz.name) return@mapValues null
|
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)
|
convertClass(innerClassNode, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,9 +168,9 @@ class JCTreeConverter(
|
|||||||
|
|
||||||
// Enum type must be an identifier (Javac requirement)
|
// Enum type must be an identifier (Javac requirement)
|
||||||
val typeExpression = if (isEnum(field.access)) {
|
val typeExpression = if (isEnum(field.access)) {
|
||||||
treeMaker.convertSimpleName(type.className.substringAfterLast('.'))
|
treeMaker.SimpleName(type.className.substringAfterLast('.'))
|
||||||
} else {
|
} else {
|
||||||
signatureParser.parseFieldSignature(field.signature, treeMaker.convertType(type))
|
signatureParser.parseFieldSignature(field.signature, treeMaker.Type(type))
|
||||||
}
|
}
|
||||||
|
|
||||||
val value = field.value
|
val value = field.value
|
||||||
@@ -189,7 +186,7 @@ class JCTreeConverter(
|
|||||||
|
|
||||||
private fun convertMethod(method: MethodNode, containingClass: ClassNode): JCMethodDecl? {
|
private fun convertMethod(method: MethodNode, containingClass: ClassNode): JCMethodDecl? {
|
||||||
if (isSynthetic(method.access)) return null
|
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 isOverridden = descriptor.overriddenDescriptors.isNotEmpty()
|
||||||
val visibleAnnotations = if (isOverridden) {
|
val visibleAnnotations = if (isOverridden) {
|
||||||
@@ -206,7 +203,7 @@ class JCTreeConverter(
|
|||||||
val name = treeMaker.name(method.name)
|
val name = treeMaker.name(method.name)
|
||||||
|
|
||||||
val returnType = Type.getReturnType(method.desc)
|
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)
|
val parametersInfo = method.getParametersInfo(containingClass)
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
@@ -219,11 +216,11 @@ class JCTreeConverter(
|
|||||||
info.flags or varargs or Flags.PARAMETER,
|
info.flags or varargs or Flags.PARAMETER,
|
||||||
ElementKind.PARAMETER, info.visibleAnnotations, info.invisibleAnnotations)
|
ElementKind.PARAMETER, info.visibleAnnotations, info.invisibleAnnotations)
|
||||||
val name = treeMaker.name(info.name)
|
val name = treeMaker.name(info.name)
|
||||||
val type = treeMaker.convertType(info.type)
|
val type = treeMaker.Type(info.type)
|
||||||
treeMaker.VarDef(modifiers, name, type, null)
|
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)
|
val genericType = signatureParser.parseMethodSignature(method.signature, parameters, exceptionTypes, jcReturnType)
|
||||||
|
|
||||||
@@ -237,7 +234,7 @@ class JCTreeConverter(
|
|||||||
treeMaker.Block(0, JavacList.nil())
|
treeMaker.Block(0, JavacList.nil())
|
||||||
} else if (isConstructor) {
|
} else if (isConstructor) {
|
||||||
// We already checked it in convertClass()
|
// 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 superClass = declaration.getSuperClassOrAny()
|
||||||
val superClassConstructor = superClass.constructors.firstOrNull { it.visibility.isVisible(null, it, declaration) }
|
val superClassConstructor = superClass.constructors.firstOrNull { it.visibility.isVisible(null, it, declaration) }
|
||||||
|
|
||||||
@@ -245,7 +242,7 @@ class JCTreeConverter(
|
|||||||
val args = mapValues(superClassConstructor.valueParameters) { param ->
|
val args = mapValues(superClassConstructor.valueParameters) { param ->
|
||||||
convertLiteralExpression(getDefaultValue(typeMapper.mapType(param.type)))
|
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))
|
JavacList.of<JCStatement>(treeMaker.Exec(call))
|
||||||
} else {
|
} else {
|
||||||
JavacList.nil<JCStatement>()
|
JavacList.nil<JCStatement>()
|
||||||
@@ -301,9 +298,9 @@ class JCTreeConverter(
|
|||||||
val fqName = annotationType.className
|
val fqName = annotationType.className
|
||||||
if (BLACKLISTED_ANNOTATATIONS.any { fqName.startsWith(it) }) return null
|
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 ->
|
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)
|
return treeMaker.Annotation(name, values)
|
||||||
}
|
}
|
||||||
@@ -326,11 +323,11 @@ class JCTreeConverter(
|
|||||||
assert(value.size == 2)
|
assert(value.size == 2)
|
||||||
val enumType = Type.getType(value[0] as String)
|
val enumType = Type.getType(value[0] as String)
|
||||||
val valueName = value[1] 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")
|
is AnnotationNode -> convertAnnotation(value) ?: error("Annotation is filtered out")
|
||||||
else -> throw IllegalArgumentException("Illegal literal expression value: $value (${value.javaClass.canonicalName})")
|
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
|
private val ClassDescriptor.isNested: Boolean
|
||||||
get() = containingDeclaration is ClassDescriptor
|
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()
|
|
||||||
+19
-16
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* 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.BoundKind
|
||||||
import com.sun.tools.javac.code.TypeTag
|
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.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
|
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
|
||||||
import java.util.*
|
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.kotlin.utils.SmartList
|
||||||
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||||
import com.sun.tools.javac.util.List as JavacList
|
import com.sun.tools.javac.util.List as JavacList
|
||||||
@@ -76,35 +79,35 @@ import com.sun.tools.javac.util.List as JavacList
|
|||||||
+ ClassType
|
+ ClassType
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum class ElementKind {
|
internal enum class ElementKind {
|
||||||
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, TypeArgument, ParameterType, ReturnType, ExceptionType,
|
Root, TypeParameter, ClassBound, InterfaceBound, SuperClass, Interface, TypeArgument, ParameterType, ReturnType, ExceptionType,
|
||||||
ClassType, TypeVariable, PrimitiveType, ArrayType
|
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>()
|
val children: MutableList<SignatureNode> = SmartList<SignatureNode>()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SignatureParser(val treeMaker: KaptTreeMaker) {
|
class SignatureParser(val treeMaker: KaptTreeMaker) {
|
||||||
class ClassGenericSignature(
|
class ClassGenericSignature(
|
||||||
val typeParameters: JavacList<JCTypeParameter>,
|
val typeParameters: com.sun.tools.javac.util.List<JCTypeParameter>,
|
||||||
val superClass: JCExpression,
|
val superClass: JCExpression,
|
||||||
val interfaces: JavacList<JCExpression>)
|
val interfaces: com.sun.tools.javac.util.List<JCExpression>)
|
||||||
|
|
||||||
class MethodGenericSignature(
|
class MethodGenericSignature(
|
||||||
val typeParameters: JavacList<JCTypeParameter>,
|
val typeParameters: com.sun.tools.javac.util.List<JCTypeParameter>,
|
||||||
val parameterTypes: JavacList<JCVariableDecl>,
|
val parameterTypes: com.sun.tools.javac.util.List<JCVariableDecl>,
|
||||||
val exceptionTypes: JavacList<JCExpression>,
|
val exceptionTypes: com.sun.tools.javac.util.List<JCExpression>,
|
||||||
val returnType: JCExpression?
|
val returnType: JCExpression?
|
||||||
)
|
)
|
||||||
|
|
||||||
fun parseClassSignature(
|
fun parseClassSignature(
|
||||||
signature: String?,
|
signature: String?,
|
||||||
rawSuperClass: JCExpression,
|
rawSuperClass: JCExpression,
|
||||||
rawInterfaces: JavacList<JCExpression>
|
rawInterfaces: com.sun.tools.javac.util.List<JCExpression>
|
||||||
): ClassGenericSignature {
|
): ClassGenericSignature {
|
||||||
if (signature == null) {
|
if (signature == null) {
|
||||||
return ClassGenericSignature(JavacList.nil(), rawSuperClass, rawInterfaces)
|
return ClassGenericSignature(com.sun.tools.javac.util.List.nil(), rawSuperClass, rawInterfaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
val root = parse(signature)
|
val root = parse(signature)
|
||||||
@@ -121,12 +124,12 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
|||||||
|
|
||||||
fun parseMethodSignature(
|
fun parseMethodSignature(
|
||||||
signature: String?,
|
signature: String?,
|
||||||
rawParameters: JavacList<JCVariableDecl>,
|
rawParameters: com.sun.tools.javac.util.List<JCVariableDecl>,
|
||||||
rawExceptionTypes: JavacList<JCExpression>,
|
rawExceptionTypes: com.sun.tools.javac.util.List<JCExpression>,
|
||||||
rawReturnType: JCExpression?
|
rawReturnType: JCExpression?
|
||||||
): MethodGenericSignature {
|
): MethodGenericSignature {
|
||||||
if (signature == null) {
|
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)
|
val root = parse(signature)
|
||||||
@@ -186,7 +189,7 @@ class SignatureParser(val treeMaker: KaptTreeMaker) {
|
|||||||
ClassType -> {
|
ClassType -> {
|
||||||
val classFqName = node.name!!.replace('/', '.')
|
val classFqName = node.name!!.replace('/', '.')
|
||||||
val args = node.children
|
val args = node.children
|
||||||
val fqNameExpression = treeMaker.convertFqName(classFqName)
|
val fqNameExpression = treeMaker.FqName(classFqName)
|
||||||
if (args.isEmpty()) return fqNameExpression
|
if (args.isEmpty()) return fqNameExpression
|
||||||
|
|
||||||
treeMaker.TypeApply(fqNameExpression, mapValues(args) { arg ->
|
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()))
|
ArrayType -> treeMaker.TypeArray(parseType(node.children.single()))
|
||||||
PrimitiveType -> {
|
PrimitiveType -> {
|
||||||
val typeTag = when (node.name!!.single()) {
|
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.
|
* 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 {
|
private companion object {
|
||||||
val PREFIX = "[kapt] "
|
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
|
package org.jetbrains.kotlin.kapt3
|
||||||
|
|
||||||
import com.sun.tools.javac.util.List as JavacList
|
import com.sun.tools.javac.util.List as JavacList
|
||||||
|
|
||||||
internal inline fun <T, R> mapValues(values: Iterable<T>?, f: (T) -> R?): JavacList<R> {
|
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.intellij.openapi.util.text.StringUtil
|
||||||
import com.sun.tools.javac.comp.CompileStates
|
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.CodegenTestCase
|
||||||
import org.jetbrains.kotlin.codegen.CodegenTestUtil
|
import org.jetbrains.kotlin.codegen.CodegenTestUtil
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.kapt3.JCTreeConverter
|
import org.jetbrains.kotlin.kapt3.*
|
||||||
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
|
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
||||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||||
import org.jetbrains.kotlin.kapt3.Logger
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
|
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 com.sun.tools.javac.util.List as JavacList
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@@ -51,35 +48,29 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
|||||||
val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory)
|
val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory)
|
||||||
val typeMapper = factory.generationState.typeMapper
|
val typeMapper = factory.generationState.typeMapper
|
||||||
|
|
||||||
val logger = Logger(isVerbose = true)
|
val logger = KaptLogger(isVerbose = true)
|
||||||
val kaptRunner = KaptRunner(logger)
|
val kaptContext = KaptContext(logger, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
||||||
try {
|
try {
|
||||||
check(kaptRunner, typeMapper, classBuilderFactory, txtFile)
|
check(kaptContext, typeMapper, txtFile)
|
||||||
} finally {
|
} finally {
|
||||||
kaptRunner.close()
|
kaptContext.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun convert(
|
protected fun convert(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper): JavacList<JCCompilationUnit> {
|
||||||
kaptRunner: KaptRunner,
|
val converter = ClassFileToSourceStubConverter(kaptRunner, typeMapper)
|
||||||
typeMapper: KotlinTypeMapper,
|
|
||||||
compiledClasses: List<ClassNode>,
|
|
||||||
origins: Map<Any, JvmDeclarationOrigin>
|
|
||||||
): JavacList<JCTree.JCCompilationUnit> {
|
|
||||||
val converter = JCTreeConverter(kaptRunner.context, typeMapper, compiledClasses, origins)
|
|
||||||
return converter.convert()
|
return converter.convert()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun check(
|
protected abstract fun check(
|
||||||
kaptRunner: KaptRunner,
|
kaptRunner: KaptContext,
|
||||||
typeMapper: KotlinTypeMapper,
|
typeMapper: KotlinTypeMapper,
|
||||||
classBuilderFactory: Kapt3BuilderFactory,
|
|
||||||
txtFile: File)
|
txtFile: File)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractJCTreeConverterTest : AbstractKotlinKapt3Test() {
|
abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test() {
|
||||||
override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) {
|
override fun check(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper, txtFile: File) {
|
||||||
val javaFiles = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
val javaFiles = convert(kaptRunner, typeMapper)
|
||||||
kaptRunner.compiler.enterTrees(javaFiles)
|
kaptRunner.compiler.enterTrees(javaFiles)
|
||||||
|
|
||||||
val actualRaw = javaFiles.joinToString (FILE_SEPARATOR)
|
val actualRaw = javaFiles.joinToString (FILE_SEPARATOR)
|
||||||
@@ -93,8 +84,8 @@ abstract class AbstractJCTreeConverterTest : AbstractKotlinKapt3Test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractKotlinKaptRunnerTest : AbstractKotlinKapt3Test() {
|
abstract class AbstractKotlinKaptRunnerTest : AbstractKotlinKapt3Test() {
|
||||||
override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) {
|
override fun check(kaptRunner: KaptContext, typeMapper: KotlinTypeMapper, txtFile: File) {
|
||||||
val compilationUnits = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
|
val compilationUnits = convert(kaptRunner, typeMapper)
|
||||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||||
try {
|
try {
|
||||||
kaptRunner.doAnnotationProcessing(emptyList(), listOf(KaptRunnerTest.simpleProcessor()),
|
kaptRunner.doAnnotationProcessing(emptyList(), listOf(KaptRunnerTest.simpleProcessor()),
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
|
|||||||
@TestMetadata("plugins/kapt3/testData/converter")
|
@TestMetadata("plugins/kapt3/testData/converter")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public class JCTreeConverterTestGenerated extends AbstractJCTreeConverterTest {
|
public class ClassFileToSourceStubConverterTestGenerated extends AbstractClassFileToSourceStubConverterTest {
|
||||||
public void testAllFilesPresentInConverter() throws Exception {
|
public void testAllFilesPresentInConverter() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/testData/converter"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/testData/converter"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
@@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.kapt3.test
|
package org.jetbrains.kotlin.kapt3.test
|
||||||
|
|
||||||
import org.jetbrains.kotlin.kapt3.KaptError
|
import org.jetbrains.kotlin.kapt3.KaptContext
|
||||||
import org.jetbrains.kotlin.kapt3.KaptRunner
|
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
|
||||||
import org.jetbrains.kotlin.kapt3.Logger
|
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import javax.annotation.processing.AbstractProcessor
|
import javax.annotation.processing.AbstractProcessor
|
||||||
|
import javax.annotation.processing.Processor
|
||||||
import javax.annotation.processing.RoundEnvironment
|
import javax.annotation.processing.RoundEnvironment
|
||||||
import javax.lang.model.element.TypeElement
|
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
|
@Test
|
||||||
fun testSimple() {
|
fun testSimple() {
|
||||||
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
|
||||||
try {
|
try {
|
||||||
KaptRunner(Logger(isVerbose = true)).doAnnotationProcessing(
|
doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), simpleProcessor(), sourceOutputDir)
|
||||||
listOf(File(TEST_DATA_DIR, "Simple.java")),
|
|
||||||
listOf(simpleProcessor()),
|
|
||||||
emptyList(), // classpath
|
|
||||||
sourceOutputDir,
|
|
||||||
sourceOutputDir)
|
|
||||||
val myMethodFile = File(sourceOutputDir, "generated/MyMethodMyAnnotation.java")
|
val myMethodFile = File(sourceOutputDir, "generated/MyMethodMyAnnotation.java")
|
||||||
assertTrue(myMethodFile.exists())
|
assertTrue(myMethodFile.exists())
|
||||||
} finally {
|
} finally {
|
||||||
@@ -102,12 +108,7 @@ class KaptRunnerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
KaptRunner(Logger(isVerbose = true)).doAnnotationProcessing(
|
doAnnotationProcessing(File(TEST_DATA_DIR, "Simple.java"), processor, TEST_DATA_DIR)
|
||||||
listOf(File(TEST_DATA_DIR, "Simple.java")),
|
|
||||||
listOf(processor),
|
|
||||||
emptyList(),
|
|
||||||
TEST_DATA_DIR,
|
|
||||||
TEST_DATA_DIR)
|
|
||||||
} catch (e: KaptError) {
|
} catch (e: KaptError) {
|
||||||
assertEquals(KaptError.Kind.EXCEPTION, e.kind)
|
assertEquals(KaptError.Kind.EXCEPTION, e.kind)
|
||||||
assertEquals("Here we are!", e.cause!!.message)
|
assertEquals("Here we are!", e.cause!!.message)
|
||||||
@@ -116,15 +117,14 @@ class KaptRunnerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testParsingError() {
|
fun testParsingError() {
|
||||||
|
var catched = false
|
||||||
try {
|
try {
|
||||||
KaptRunner(Logger(isVerbose = true)).doAnnotationProcessing(
|
doAnnotationProcessing(File(TEST_DATA_DIR, "ParseError.java"), simpleProcessor(), TEST_DATA_DIR)
|
||||||
listOf(File(TEST_DATA_DIR, "ParseError.java")),
|
|
||||||
listOf(simpleProcessor()),
|
|
||||||
emptyList(),
|
|
||||||
TEST_DATA_DIR,
|
|
||||||
TEST_DATA_DIR)
|
|
||||||
} catch (e: KaptError) {
|
} catch (e: KaptError) {
|
||||||
assertEquals(KaptError.Kind.JAVA_FILE_PARSING_ERROR, e.kind)
|
assertEquals(KaptError.Kind.JAVA_FILE_PARSING_ERROR, e.kind)
|
||||||
|
catched = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertTrue("Exception was not catched", catched)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user