Kapt: Fix remaining issues with Java 9 compatibility in converter, add Java 9 tests
This commit is contained in:
+25
-16
@@ -16,8 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3
|
||||
|
||||
import com.sun.tools.javac.comp.CompileStates
|
||||
import com.sun.tools.javac.file.JavacFileManager
|
||||
import com.sun.tools.javac.comp.CompileStates.*
|
||||
import com.sun.tools.javac.main.JavaCompiler
|
||||
import com.sun.tools.javac.main.Option
|
||||
import com.sun.tools.javac.processing.AnnotationProcessingError
|
||||
@@ -29,7 +28,6 @@ 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
|
||||
|
||||
@@ -71,23 +69,12 @@ fun KaptContext<*>.doAnnotationProcessing(
|
||||
compiler.initProcessAnnotations(processors)
|
||||
}
|
||||
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
var parsedJavaFiles = compiler.stopIfErrorOccurred(
|
||||
CompileStates.CompileState.PARSE, compiler.parseFiles(javaFileObjects))
|
||||
|
||||
if (isJava9OrLater) {
|
||||
val initModulesMethod = compiler.javaClass.getMethod("initModules", JavacList::class.java)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
parsedJavaFiles = compiler.stopIfErrorOccurred(
|
||||
CompileStates.CompileState.PARSE,
|
||||
initModulesMethod.invoke(compiler, parsedJavaFiles) as JavacList<JCTree.JCCompilationUnit>)
|
||||
}
|
||||
val parsedJavaFiles = parseJavaFiles(javaSourceFiles)
|
||||
|
||||
compilerAfterAP = try {
|
||||
javaLog.interceptorData.files = parsedJavaFiles.map { it.sourceFile to it }.toMap()
|
||||
val analyzedFiles = compiler.stopIfErrorOccurred(
|
||||
CompileStates.CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources))
|
||||
CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources))
|
||||
|
||||
if (isJava9OrLater) {
|
||||
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
|
||||
@@ -119,4 +106,26 @@ fun KaptContext<*>.doAnnotationProcessing(
|
||||
processingEnvironment.close()
|
||||
this@doAnnotationProcessing.close()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KaptContext<*>.parseJavaFiles(javaSourceFiles: List<File>): JavacList<JCTree.JCCompilationUnit> {
|
||||
val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
|
||||
|
||||
return compiler.stopIfErrorOccurred(CompileState.PARSE,
|
||||
initModulesIfNeeded(
|
||||
compiler.stopIfErrorOccurred(CompileState.PARSE,
|
||||
compiler.parseFiles(javaFileObjects))))
|
||||
}
|
||||
|
||||
private fun KaptContext<*>.initModulesIfNeeded(files: JavacList<JCTree.JCCompilationUnit>): JavacList<JCTree.JCCompilationUnit> {
|
||||
if (isJava9OrLater) {
|
||||
val initModulesMethod = compiler.javaClass.getMethod("initModules", JavacList::class.java)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return compiler.stopIfErrorOccurred(
|
||||
CompileState.PARSE,
|
||||
initModulesMethod.invoke(compiler, files) as JavacList<JCTree.JCCompilationUnit>)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.kapt3.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.stubs.KaptStubLineInformation
|
||||
import org.jetbrains.kotlin.kapt3.stubs.KotlinPosition
|
||||
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedWriter
|
||||
import org.jetbrains.kotlin.kapt3.util.isJava9OrLater
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import javax.tools.JavaFileObject
|
||||
@@ -74,6 +75,8 @@ class KaptJavaLog(
|
||||
}
|
||||
|
||||
override fun report(diagnostic: JCDiagnostic) {
|
||||
System.err.println("Diagnostic code: ${diagnostic.code}")
|
||||
|
||||
if (diagnostic.type == JCDiagnostic.DiagnosticType.ERROR && diagnostic.code in IGNORED_DIAGNOSTICS) {
|
||||
return
|
||||
}
|
||||
@@ -102,7 +105,7 @@ class KaptJavaLog(
|
||||
val kotlinFile = kotlinPosition?.let { getKotlinSourceFile(it) }
|
||||
if (kotlinPosition != null && kotlinFile != null) {
|
||||
val locationMessage = "$KOTLIN_LOCATION_PREFIX${kotlinFile.absolutePath}: (${kotlinPosition.line}, ${kotlinPosition.column})"
|
||||
val locationDiagnostic = diagnosticFactory.note("proc.messager", locationMessage)
|
||||
val locationDiagnostic = diagnosticFactory.note(null as DiagnosticSource?, null, "proc.messager", locationMessage)
|
||||
val wrappedDiagnostic = JCDiagnostic.MultilineDiagnostic(diagnostic, JavacList.of(locationDiagnostic))
|
||||
|
||||
super.report(wrappedDiagnostic)
|
||||
@@ -126,9 +129,9 @@ class KaptJavaLog(
|
||||
|
||||
val writer = when (diagnostic.type) {
|
||||
DiagnosticType.FRAGMENT, null -> kotlin.error("Invalid root diagnostic type: ${diagnostic.type}")
|
||||
DiagnosticType.NOTE -> super.noticeWriter
|
||||
DiagnosticType.WARNING -> super.warnWriter
|
||||
DiagnosticType.ERROR -> super.errWriter
|
||||
DiagnosticType.NOTE -> super.getWriter(WriterKind.NOTICE)
|
||||
DiagnosticType.WARNING -> super.getWriter(WriterKind.WARNING)
|
||||
DiagnosticType.ERROR -> super.getWriter(WriterKind.ERROR)
|
||||
}
|
||||
|
||||
val formattedMessage = diagnosticFormatter.format(diagnostic, javacMessages.currentLocale)
|
||||
@@ -211,10 +214,32 @@ class KaptJavaLog(
|
||||
}
|
||||
|
||||
fun KaptContext<*>.kaptError(text: String): JCDiagnostic {
|
||||
return JCDiagnostic.Factory.instance(context).error(null, null, "proc.messager", text)
|
||||
return JCDiagnostic.Factory.instance(context).errorJava9Aware(null, null, "proc.messager", text)
|
||||
}
|
||||
|
||||
fun KaptContext<*>.kaptError(text: String, target: PsiElement): JCDiagnostic {
|
||||
//TODO provide source binding
|
||||
return JCDiagnostic.Factory.instance(context).error(null, null, "proc.messager", text)
|
||||
return JCDiagnostic.Factory.instance(context).errorJava9Aware(null, null, "proc.messager", text)
|
||||
}
|
||||
|
||||
private fun JCDiagnostic.Factory.errorJava9Aware(
|
||||
source: DiagnosticSource?,
|
||||
pos: JCDiagnostic.DiagnosticPosition?,
|
||||
key: String,
|
||||
vararg args: String
|
||||
): JCDiagnostic {
|
||||
return if (isJava9OrLater) {
|
||||
val errorMethod = this::class.java.getDeclaredMethod(
|
||||
"error",
|
||||
JCDiagnostic.DiagnosticFlag::class.java,
|
||||
DiagnosticSource::class.java,
|
||||
JCDiagnostic.DiagnosticPosition::class.java,
|
||||
String::class.java,
|
||||
Array<Any>::class.java)
|
||||
|
||||
errorMethod.invoke(this, JCDiagnostic.DiagnosticFlag.MANDATORY, source, pos, key, args) as JCDiagnostic
|
||||
}
|
||||
else {
|
||||
this.error(source, pos, key, *args)
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.kapt3.stubs
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import com.sun.tools.javac.tree.TreeScanner
|
||||
import org.jetbrains.kotlin.kapt3.stubs.KaptLineMappingCollector.Companion.KAPT_SIGNATURE_ANNOTATION_FQNAME
|
||||
import org.jetbrains.kotlin.kapt3.util.getPackageNameJava9Aware
|
||||
|
||||
class KaptStubLineInformation {
|
||||
private val offsets = mutableMapOf<JCTree.JCCompilationUnit, KaptLineMappingCollector.LineInfo>()
|
||||
@@ -84,7 +85,7 @@ class KaptStubLineInformation {
|
||||
// Unfortunately, we have to do this the hard way, as symbols may be not available yet
|
||||
// (for instance, if this code is called inside the "enterTrees()")
|
||||
val simpleDescriptor = getFqName(declaration, file, "")
|
||||
val packageName = file.packageName?.toString()?.replace('.', '/')
|
||||
val packageName = file.getPackageNameJava9Aware()?.toString()?.replace('.', '/')
|
||||
return if (packageName == null) simpleDescriptor else "$packageName/$simpleDescriptor"
|
||||
}
|
||||
|
||||
|
||||
+64
-4
@@ -34,8 +34,10 @@ import org.jetbrains.kotlin.kapt3.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.doAnnotationProcessing
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
|
||||
import org.jetbrains.kotlin.kapt3.javac.KaptJavaLog
|
||||
import org.jetbrains.kotlin.kapt3.parseJavaFiles
|
||||
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
|
||||
import org.jetbrains.kotlin.kapt3.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.util.isJava9OrLater
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
@@ -44,8 +46,11 @@ import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Files
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import com.sun.tools.javac.util.List as JavacList
|
||||
|
||||
abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
@@ -88,6 +93,8 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
|
||||
try {
|
||||
check(kaptContext, javaFiles, txtFile, wholeFile)
|
||||
} catch (e: Throwable) {
|
||||
throw RuntimeException(e)
|
||||
} finally {
|
||||
javaFiles.forEach { it.delete() }
|
||||
tempFiles.forEach { it.delete() }
|
||||
@@ -115,7 +122,8 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
kaptContext.compiler.log.nerrors = 0
|
||||
|
||||
try {
|
||||
val parsedJavaFiles = kaptContext.compiler.parseFiles(kaptContext.fileManager.getJavaFileObjectsFromFiles(allJavaFiles))
|
||||
val parsedJavaFiles = kaptContext.parseJavaFiles(allJavaFiles)
|
||||
|
||||
for (file in parsedJavaFiles) {
|
||||
// By default, JavaFileObject.getName() returns the absolute path to the file.
|
||||
// In our test, such a path will be temporary, so the comparision against it will lead to flaky tests.
|
||||
@@ -135,18 +143,70 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
|
||||
wholeFile: File)
|
||||
}
|
||||
|
||||
abstract class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test() {
|
||||
internal companion object {
|
||||
open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test() {
|
||||
companion object {
|
||||
private val KOTLIN_METADATA_GROUP = "[a-z0-9]+ = (\\{.+?\\}|[0-9]+)"
|
||||
private val KOTLIN_METADATA_REGEX = "@kotlin\\.Metadata\\(($KOTLIN_METADATA_GROUP)(, $KOTLIN_METADATA_GROUP)*\\)".toRegex()
|
||||
private val KAPT_METADATA_REGEX = "@kapt\\.internal\\.KaptMetadata\\((value = )?\"[^(].*?\"\\)".toRegex()
|
||||
|
||||
private val EXPECTED_ERROR = "EXPECTED_ERROR"
|
||||
|
||||
fun removeMetadataAnnotationContents(s: String): String {
|
||||
internal fun removeMetadataAnnotationContents(s: String): String {
|
||||
return s.replace(KOTLIN_METADATA_REGEX, "@kotlin.Metadata()")
|
||||
.replace(KAPT_METADATA_REGEX, "@kapt.internal.KaptMetadata()")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
if (args.isEmpty()) error("1 argument expected, 0 passed")
|
||||
AbstractClassFileToSourceStubConverterTest().doTest(args[0])
|
||||
}
|
||||
}
|
||||
|
||||
// This is to suppress "AssertionFailedError: No tests found"
|
||||
fun testSuppressWarning() {}
|
||||
|
||||
override fun doTest(filePath: String) {
|
||||
super.doTest(filePath)
|
||||
|
||||
if (!isJava9OrLater) {
|
||||
doTestWithJdk9(filePath)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doTestWithJdk9(filePath: String) {
|
||||
val jdk9Home = KotlinTestUtils.getJdk9HomeIfPossible() ?: run {
|
||||
println("JDK9 not found, the test was skipped")
|
||||
return
|
||||
}
|
||||
|
||||
val javaExe = File(jdk9Home, "bin/java.exe").takeIf { it.exists() } ?: File(jdk9Home, "bin/java")
|
||||
assert(javaExe.exists()) { "Can't find 'java' executable in $jdk9Home" }
|
||||
|
||||
val currentJavaHome = System.getProperty("java.home")
|
||||
val classpath = collectClasspath(AbstractClassFileToSourceStubConverterTest::class.java.classLoader)
|
||||
.filter { !it.path.startsWith(currentJavaHome) }
|
||||
|
||||
val process = ProcessBuilder(
|
||||
javaExe.absolutePath,
|
||||
"--illegal-access=warn",
|
||||
"-ea",
|
||||
"-classpath",
|
||||
classpath.joinToString(File.pathSeparator),
|
||||
AbstractClassFileToSourceStubConverterTest::class.java.name,
|
||||
filePath
|
||||
).inheritIO().start()
|
||||
|
||||
process.waitFor(3, TimeUnit.MINUTES)
|
||||
if (process.exitValue() != 0) {
|
||||
throw AssertionError("Java 9 test process exited with exit code ${process.exitValue()} \n")
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectClasspath(classLoader: ClassLoader?): List<URL> = when (classLoader) {
|
||||
is URLClassLoader -> classLoader.urLs.asList() + collectClasspath(classLoader.parent)
|
||||
is ClassLoader -> collectClasspath(classLoader.parent)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
override fun check(kaptContext: KaptContext<GenerationState>, javaFiles: List<File>, txtFile: File, wholeFile: File) {
|
||||
|
||||
Reference in New Issue
Block a user