From 8f94a71de7a70764e9ebbd272fb9a41321fa18e9 Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Tue, 15 Oct 2019 13:56:16 +0100 Subject: [PATCH] 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 --- .../src/test/java/test/kt33617/MyClass.java | 9 ++++ .../gradle/KaptIncrementalWithIsolatingApt.kt | 42 +++++++++++++++++++ .../base/incremental/classStructureCache.kt | 19 ++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/test/kt33617/MyClass.java diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/test/kt33617/MyClass.java b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/test/kt33617/MyClass.java new file mode 100644 index 00000000000..9c79ca3a1fe --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/test/kt33617/MyClass.java @@ -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 { +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt index 359ec0d47a7..54c3c753957 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt @@ -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:" diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt index ae89a466d28..374db2302af 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt @@ -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()]