KT-33617: Handle non-hierarchical URIs for incremental annotation processing

JDK9 may decide to load .java files from jar when resolving a type, even
when .class file exists in the same jar. Further on, these files will be
parsed and analyzed, which triggers the listener used by incremental
annotation processing. This commit avoids analyzing those files, and
makes sure URI passed from the compiler are such that a File instance
can be created.

Test: KaptIncrementalWithIsolatingApt.testSourcesInCompileClasspathJars
This commit is contained in:
Ivan Gavrilovic
2019-10-15 13:56:16 +01:00
committed by Yan Zhulanow
parent 941980c154
commit 8f94a71de7
3 changed files with 69 additions and 1 deletions
@@ -0,0 +1,9 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package test.kt33617;
public class MyClass {
}
@@ -8,7 +8,9 @@ package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessor
import org.jetbrains.kotlin.gradle.util.modify
import org.junit.Assert.assertEquals
import org.junit.Assume
import org.junit.Test
import test.kt33617.MyClass
import java.io.File
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@@ -113,6 +115,46 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() {
assertContains("Incremental annotation processing (apt mode): false")
}
}
/** Regression test for https://youtrack.jetbrains.com/issue/KT-33617. */
@Test
fun testSourcesInCompileClasspathJars() {
val javaHome = File(System.getProperty("jdk9Home")!!)
Assume.assumeTrue("JDK 9 isn't available", javaHome.isDirectory)
val options = defaultBuildOptions().copy(javaHome = javaHome)
val project = getProject()
// create jar with .class and .java file for the same type
ZipOutputStream(project.projectDir.resolve("lib-with-sources.jar").outputStream()).use {
it.putNextEntry(ZipEntry("test/kt33617/MyClass.class"))
MyClass::class.java.classLoader.getResourceAsStream("test/kt33617/MyClass.class").use { input ->
it.write(input!!.readBytes())
}
it.closeEntry()
it.putNextEntry(ZipEntry("test/kt33617/MyClass.java"))
it.write(
"""
package test.kt33617;
public class MyClass {}
""".trimIndent().toByteArray(Charsets.UTF_8)
)
it.closeEntry()
}
project.gradleBuildScript().appendText(
"""
dependencies {
implementation files('lib-with-sources.jar')
}
""".trimIndent()
)
project.projectFile("useB.kt").modify { current -> "$current\nfun otherFunction(param: test.kt33617.MyClass) {}" }
project.build("clean", "kaptKotlin", options = options) {
assertSuccessful()
}
}
}
private const val patternApt = "Processing java sources with annotation processors:"
@@ -9,6 +9,7 @@ import java.io.File
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable
import java.lang.IllegalArgumentException
import java.net.URI
import java.util.regex.Pattern
@@ -73,7 +74,23 @@ class JavaClassCache() : Serializable {
output.writeObject(generatedTypes)
}
fun isAlreadyProcessed(sourceFile: URI) = sourceCache.containsKey(sourceFile) || generatedTypes.containsKey(File(sourceFile))
fun isAlreadyProcessed(sourceFile: URI): Boolean {
if (!sourceFile.isAbsolute) {
// we never want to process non-absolute URIs, see https://youtrack.jetbrains.com/issue/KT-33617
return true
}
if (sourceFile.isOpaque) {
// we never want to process non-hierarchical URIs, https://youtrack.jetbrains.com/issue/KT-33617
return true
}
return try {
val fileFromUri = File(sourceFile)
sourceCache.containsKey(sourceFile) || generatedTypes.containsKey(fileFromUri)
} catch (e: IllegalArgumentException) {
// unable to create File instance, avoid processing these files
true
}
}
/** Used for testing only. */
internal fun getStructure(sourceFile: File) = sourceCache[sourceFile.toURI()]