diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index 0222f657415..6a58c01a0ce 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.kapt3.AptMode.* import org.jetbrains.kotlin.kapt3.diagnostic.KaptError import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter import org.jetbrains.kotlin.kapt3.util.KaptLogger +import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.BindingContext @@ -271,7 +272,7 @@ abstract class AbstractKapt3Extension( for (stub in stubs) { 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('.', '/')) packageDir.mkdirs() File(packageDir, className + ".java").writeText(stub.toString()) diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt index c981e29610c..7d3f865f7da 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/annotationProcessing.kt @@ -25,9 +25,12 @@ import com.sun.tools.javac.processing.JavacFiler import com.sun.tools.javac.processing.JavacProcessingEnvironment import com.sun.tools.javac.tree.JCTree import org.jetbrains.kotlin.kapt3.diagnostic.KaptError +import org.jetbrains.kotlin.kapt3.util.isJava9OrLater +import org.jetbrains.kotlin.kapt3.util.putJavacOption import java.io.File import javax.annotation.processing.Processor import javax.tools.JavaFileManager +import javax.tools.JavaFileObject import com.sun.tools.javac.util.List as JavacList fun KaptContext<*>.doAnnotationProcessing( @@ -45,32 +48,55 @@ fun KaptContext<*>.doAnnotationProcessing( put(Option.PROC, "only") // Only process annotations 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 }) - put(Option.PROCESSORPATH, annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath }) + putJavacOption("CLASSPATH", "CLASS_PATH", compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath }) + putJavacOption("PROCESSORPATH", "PROCESSOR_PATH", annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath }) put(Option.PROCESSOR, annotationProcessors) put(Option.S, sourcesOutputDir.canonicalPath) put(Option.D, classesOutputDir.canonicalPath) put(Option.ENCODING, "UTF-8") } - val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager val processingEnvironment = JavacProcessingEnvironment.instance(context) val compilerAfterAP: JavaCompiler try { - compiler.initProcessAnnotations(processors) + if (isJava9OrLater) { + val initProcessAnnotationsMethod = JavaCompiler::class.java.declaredMethods.single { it.name == "initProcessAnnotations" } + initProcessAnnotationsMethod.invoke(compiler, processors, emptyList(), emptyList()) + } + else { + compiler.initProcessAnnotations(processors) + } 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) + } compilerAfterAP = try { javaLog.interceptorData.files = parsedJavaFiles.map { it.sourceFile to it }.toMap() val analyzedFiles = compiler.stopIfErrorOccurred( 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) { throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e) } diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaFileObject.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaFileObject.kt index 4fba5f6f6ec..846c085661c 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaFileObject.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaFileObject.kt @@ -16,10 +16,8 @@ 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 java.io.* +import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware import java.net.URI import java.net.URL import javax.lang.model.element.Modifier @@ -29,12 +27,9 @@ import javax.tools.JavaFileObject class KaptJavaFileObject( val compilationUnit: JCTree.JCCompilationUnit, val clazz: JCTree.JCClassDecl, - fileManager: JavacFileManager, val timestamp: Long = System.currentTimeMillis() -) : BaseFileObject(fileManager) { - override fun getShortName() = clazz.simpleName.toString() - - override fun inferBinaryName(path: MutableIterable?) = throw UnsupportedOperationException() +) : JavaFileObject { + override fun toString() = "${javaClass.simpleName}[$name]" override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?): Boolean { if (simpleName == null || kind == null) return false @@ -44,7 +39,7 @@ class KaptJavaFileObject( override fun getKind() = JavaFileObject.Kind.SOURCE override fun getName(): String { - val packageName = compilationUnit.packageName + val packageName = compilationUnit.getPackageNameJava9Aware() if (packageName == null || packageName.toString() == "") { return clazz.name.toString() + ".java" } diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index a6429a844dc..31eaf32b89a 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -120,8 +120,9 @@ class ClassFileToSourceStubConverter( JavacList.nil(), JavacList.nil()) - val topLevel = treeMaker.TopLevel(JavacList.nil(), treeMaker.SimpleName("error"), JavacList.of(nonExistentClass)) - topLevel.sourcefile = KaptJavaFileObject(topLevel, nonExistentClass, fileManager) + val topLevel = treeMaker.TopLevelJava9Aware(treeMaker.SimpleName("error"), JavacList.of(nonExistentClass)) + + topLevel.sourcefile = KaptJavaFileObject(topLevel, nonExistentClass) // We basically don't need to add binding for NonExistentClass return topLevel @@ -135,7 +136,6 @@ class ClassFileToSourceStubConverter( // Nested classes will be processed during the outer classes conversion if ((descriptor as? ClassDescriptor)?.isNested ?: false) return null - val packageAnnotations = JavacList.nil() val packageName = ktFile.packageFqName.asString() 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 classes = JavacList.of(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 _bindings[clazz.name] = this } diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/util/java9Utils.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/util/java9Utils.kt new file mode 100644 index 00000000000..2aa3d708eef --- /dev/null +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/util/java9Utils.kt @@ -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.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(), 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 + } +} \ No newline at end of file