Kapt: Support Java 9 in compiler plugin
This commit is contained in:
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.kapt3.AptMode.*
|
|||||||
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
|
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
|
||||||
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
||||||
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware
|
||||||
import org.jetbrains.kotlin.modules.TargetId
|
import org.jetbrains.kotlin.modules.TargetId
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -271,7 +272,7 @@ abstract class AbstractKapt3Extension(
|
|||||||
for (stub in stubs) {
|
for (stub in stubs) {
|
||||||
val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString()
|
val className = (stub.defs.first { it is JCTree.JCClassDecl } as JCTree.JCClassDecl).simpleName.toString()
|
||||||
|
|
||||||
val packageName = stub.packageName?.toString() ?: ""
|
val packageName = stub.getPackageNameJava9Aware()?.toString() ?: ""
|
||||||
val packageDir = if (packageName.isEmpty()) stubsOutputDir else File(stubsOutputDir, packageName.replace('.', '/'))
|
val packageDir = if (packageName.isEmpty()) stubsOutputDir else File(stubsOutputDir, packageName.replace('.', '/'))
|
||||||
packageDir.mkdirs()
|
packageDir.mkdirs()
|
||||||
File(packageDir, className + ".java").writeText(stub.toString())
|
File(packageDir, className + ".java").writeText(stub.toString())
|
||||||
|
|||||||
@@ -25,9 +25,12 @@ import com.sun.tools.javac.processing.JavacFiler
|
|||||||
import com.sun.tools.javac.processing.JavacProcessingEnvironment
|
import com.sun.tools.javac.processing.JavacProcessingEnvironment
|
||||||
import com.sun.tools.javac.tree.JCTree
|
import com.sun.tools.javac.tree.JCTree
|
||||||
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
|
import org.jetbrains.kotlin.kapt3.diagnostic.KaptError
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.isJava9OrLater
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.putJavacOption
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.annotation.processing.Processor
|
import javax.annotation.processing.Processor
|
||||||
import javax.tools.JavaFileManager
|
import javax.tools.JavaFileManager
|
||||||
|
import javax.tools.JavaFileObject
|
||||||
import com.sun.tools.javac.util.List as JavacList
|
import com.sun.tools.javac.util.List as JavacList
|
||||||
|
|
||||||
fun KaptContext<*>.doAnnotationProcessing(
|
fun KaptContext<*>.doAnnotationProcessing(
|
||||||
@@ -45,32 +48,55 @@ fun KaptContext<*>.doAnnotationProcessing(
|
|||||||
put(Option.PROC, "only") // Only process annotations
|
put(Option.PROC, "only") // Only process annotations
|
||||||
|
|
||||||
if (!withJdk) {
|
if (!withJdk) {
|
||||||
put(Option.BOOTCLASSPATH, "") // No boot classpath
|
putJavacOption("BOOTCLASSPATH", "BOOT_CLASS_PATH", "") // No boot classpath
|
||||||
}
|
}
|
||||||
|
|
||||||
put(Option.CLASSPATH, compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
putJavacOption("CLASSPATH", "CLASS_PATH", compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||||
put(Option.PROCESSORPATH, annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH", annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||||
put(Option.PROCESSOR, annotationProcessors)
|
put(Option.PROCESSOR, annotationProcessors)
|
||||||
put(Option.S, sourcesOutputDir.canonicalPath)
|
put(Option.S, sourcesOutputDir.canonicalPath)
|
||||||
put(Option.D, classesOutputDir.canonicalPath)
|
put(Option.D, classesOutputDir.canonicalPath)
|
||||||
put(Option.ENCODING, "UTF-8")
|
put(Option.ENCODING, "UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
|
|
||||||
val processingEnvironment = JavacProcessingEnvironment.instance(context)
|
val processingEnvironment = JavacProcessingEnvironment.instance(context)
|
||||||
|
|
||||||
val compilerAfterAP: JavaCompiler
|
val compilerAfterAP: JavaCompiler
|
||||||
try {
|
try {
|
||||||
compiler.initProcessAnnotations(processors)
|
if (isJava9OrLater) {
|
||||||
|
val initProcessAnnotationsMethod = JavaCompiler::class.java.declaredMethods.single { it.name == "initProcessAnnotations" }
|
||||||
|
initProcessAnnotationsMethod.invoke(compiler, processors, emptyList<JavaFileObject>(), emptyList<String>())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compiler.initProcessAnnotations(processors)
|
||||||
|
}
|
||||||
|
|
||||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||||
val parsedJavaFiles = compiler.parseFiles(javaFileObjects)
|
var parsedJavaFiles = compiler.stopIfErrorOccurred(
|
||||||
|
CompileStates.CompileState.PARSE, compiler.parseFiles(javaFileObjects))
|
||||||
|
|
||||||
|
if (isJava9OrLater) {
|
||||||
|
val initModulesMethod = compiler.javaClass.getMethod("initModules", JavacList::class.java)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
parsedJavaFiles = compiler.stopIfErrorOccurred(
|
||||||
|
CompileStates.CompileState.PARSE,
|
||||||
|
initModulesMethod.invoke(compiler, parsedJavaFiles) as JavacList<JCTree.JCCompilationUnit>)
|
||||||
|
}
|
||||||
|
|
||||||
compilerAfterAP = try {
|
compilerAfterAP = try {
|
||||||
javaLog.interceptorData.files = parsedJavaFiles.map { it.sourceFile to it }.toMap()
|
javaLog.interceptorData.files = parsedJavaFiles.map { it.sourceFile to it }.toMap()
|
||||||
val analyzedFiles = compiler.stopIfErrorOccurred(
|
val analyzedFiles = compiler.stopIfErrorOccurred(
|
||||||
CompileStates.CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources))
|
CompileStates.CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources))
|
||||||
compiler.processAnnotations(analyzedFiles)
|
|
||||||
|
if (isJava9OrLater) {
|
||||||
|
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
|
||||||
|
processAnnotationsMethod.invoke(compiler, analyzedFiles)
|
||||||
|
compiler
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compiler.processAnnotations(analyzedFiles)
|
||||||
|
}
|
||||||
} catch (e: AnnotationProcessingError) {
|
} catch (e: AnnotationProcessingError) {
|
||||||
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
|
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.kapt3.javac
|
package org.jetbrains.kotlin.kapt3.javac
|
||||||
|
|
||||||
import com.sun.tools.javac.file.BaseFileObject
|
|
||||||
import com.sun.tools.javac.file.JavacFileManager
|
|
||||||
import com.sun.tools.javac.tree.JCTree
|
import com.sun.tools.javac.tree.JCTree
|
||||||
import java.io.*
|
import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import javax.lang.model.element.Modifier
|
import javax.lang.model.element.Modifier
|
||||||
@@ -29,12 +27,9 @@ import javax.tools.JavaFileObject
|
|||||||
class KaptJavaFileObject(
|
class KaptJavaFileObject(
|
||||||
val compilationUnit: JCTree.JCCompilationUnit,
|
val compilationUnit: JCTree.JCCompilationUnit,
|
||||||
val clazz: JCTree.JCClassDecl,
|
val clazz: JCTree.JCClassDecl,
|
||||||
fileManager: JavacFileManager,
|
|
||||||
val timestamp: Long = System.currentTimeMillis()
|
val timestamp: Long = System.currentTimeMillis()
|
||||||
) : BaseFileObject(fileManager) {
|
) : JavaFileObject {
|
||||||
override fun getShortName() = clazz.simpleName.toString()
|
override fun toString() = "${javaClass.simpleName}[$name]"
|
||||||
|
|
||||||
override fun inferBinaryName(path: MutableIterable<File>?) = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?): Boolean {
|
override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?): Boolean {
|
||||||
if (simpleName == null || kind == null) return false
|
if (simpleName == null || kind == null) return false
|
||||||
@@ -44,7 +39,7 @@ class KaptJavaFileObject(
|
|||||||
override fun getKind() = JavaFileObject.Kind.SOURCE
|
override fun getKind() = JavaFileObject.Kind.SOURCE
|
||||||
|
|
||||||
override fun getName(): String {
|
override fun getName(): String {
|
||||||
val packageName = compilationUnit.packageName
|
val packageName = compilationUnit.getPackageNameJava9Aware()
|
||||||
if (packageName == null || packageName.toString() == "") {
|
if (packageName == null || packageName.toString() == "") {
|
||||||
return clazz.name.toString() + ".java"
|
return clazz.name.toString() + ".java"
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -120,8 +120,9 @@ class ClassFileToSourceStubConverter(
|
|||||||
JavacList.nil(),
|
JavacList.nil(),
|
||||||
JavacList.nil())
|
JavacList.nil())
|
||||||
|
|
||||||
val topLevel = treeMaker.TopLevel(JavacList.nil(), treeMaker.SimpleName("error"), JavacList.of(nonExistentClass))
|
val topLevel = treeMaker.TopLevelJava9Aware(treeMaker.SimpleName("error"), JavacList.of(nonExistentClass))
|
||||||
topLevel.sourcefile = KaptJavaFileObject(topLevel, nonExistentClass, fileManager)
|
|
||||||
|
topLevel.sourcefile = KaptJavaFileObject(topLevel, nonExistentClass)
|
||||||
|
|
||||||
// We basically don't need to add binding for NonExistentClass
|
// We basically don't need to add binding for NonExistentClass
|
||||||
return topLevel
|
return topLevel
|
||||||
@@ -135,7 +136,6 @@ class ClassFileToSourceStubConverter(
|
|||||||
// Nested classes will be processed during the outer classes conversion
|
// Nested classes will be processed during the outer classes conversion
|
||||||
if ((descriptor as? ClassDescriptor)?.isNested ?: false) return null
|
if ((descriptor as? ClassDescriptor)?.isNested ?: false) return null
|
||||||
|
|
||||||
val packageAnnotations = JavacList.nil<JCAnnotation>()
|
|
||||||
val packageName = ktFile.packageFqName.asString()
|
val packageName = ktFile.packageFqName.asString()
|
||||||
val packageClause = if (packageName.isEmpty()) null else treeMaker.FqName(packageName)
|
val packageClause = if (packageName.isEmpty()) null else treeMaker.FqName(packageName)
|
||||||
|
|
||||||
@@ -144,9 +144,9 @@ class ClassFileToSourceStubConverter(
|
|||||||
val imports = if (correctErrorTypes) convertImports(ktFile, classDeclaration) else JavacList.nil()
|
val imports = if (correctErrorTypes) convertImports(ktFile, classDeclaration) else JavacList.nil()
|
||||||
val classes = JavacList.of<JCTree>(classDeclaration)
|
val classes = JavacList.of<JCTree>(classDeclaration)
|
||||||
|
|
||||||
val topLevel = treeMaker.TopLevel(packageAnnotations, packageClause, imports + classes)
|
val topLevel = treeMaker.TopLevelJava9Aware(packageClause, imports + classes)
|
||||||
|
|
||||||
KaptJavaFileObject(topLevel, classDeclaration, fileManager).apply {
|
KaptJavaFileObject(topLevel, classDeclaration).apply {
|
||||||
topLevel.sourcefile = this
|
topLevel.sourcefile = this
|
||||||
_bindings[clazz.name] = this
|
_bindings[clazz.name] = this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.kapt3.util
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.SystemInfo
|
||||||
|
import com.sun.tools.javac.main.Option
|
||||||
|
import com.sun.tools.javac.tree.JCTree
|
||||||
|
import com.sun.tools.javac.tree.TreeMaker
|
||||||
|
import com.sun.tools.javac.util.Options
|
||||||
|
import com.sun.tools.javac.util.List as JavacList
|
||||||
|
import org.jetbrains.kotlin.kapt3.plus
|
||||||
|
|
||||||
|
internal val isJava9OrLater: Boolean
|
||||||
|
get() = SystemInfo.isJavaVersionAtLeast("9")
|
||||||
|
|
||||||
|
internal fun Options.putJavacOption(jdk8Name: String, jdk9Name: String, value: String) {
|
||||||
|
val option = if (isJava9OrLater) {
|
||||||
|
Option.valueOf(jdk9Name)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Option.valueOf(jdk8Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
put(option, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun TreeMaker.TopLevelJava9Aware(packageClause: JCTree.JCExpression?, declarations: JavacList<JCTree>): JCTree.JCCompilationUnit {
|
||||||
|
return if (isJava9OrLater) {
|
||||||
|
val topLevelMethod = TreeMaker::class.java.declaredMethods.single { it.name == "TopLevel" }
|
||||||
|
val packageDecl: JCTree? = packageClause?.let {
|
||||||
|
val packageDeclMethod = TreeMaker::class.java.methods.single { it.name == "PackageDecl" }
|
||||||
|
packageDeclMethod.invoke(this, JavacList.nil<JCTree>(), packageClause) as JCTree
|
||||||
|
}
|
||||||
|
val allDeclarations = if (packageDecl != null) JavacList.of(packageDecl) + declarations else declarations
|
||||||
|
topLevelMethod.invoke(this, allDeclarations) as JCTree.JCCompilationUnit
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TopLevel(JavacList.nil(), packageClause, declarations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun JCTree.JCCompilationUnit.getPackageNameJava9Aware(): JCTree? {
|
||||||
|
return if (isJava9OrLater) {
|
||||||
|
JCTree.JCCompilationUnit::class.java.getDeclaredMethod("getPackageName").invoke(this) as JCTree?
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.packageName
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user