Use types are origins for incremental KAPT and track generated source
This change introduces tracking of generated sources structure in order to e.g track classpath changes impacting generated sources. This fixes KT-42182. Also, origin tracking for isolating processors is now using types, allowing for origin elements from classpath. This fixes KT-34340. However, classpath origin is used only to invalidate generated files when the type changes and processing will not be requested for that type. This is in line with the incap spec.
This commit is contained in:
committed by
Mikhael Bogdanov
parent
d512158c25
commit
c7e5beece5
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 org.jetbrains.kotlin.gradle.incapt;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/** Simple processor that generates a class for every annotated element (class, field, method). */
|
||||
public class IncrementalProcessorReferencingClasspath extends AbstractProcessor {
|
||||
|
||||
// Type that all generated sources will extend.
|
||||
public static final String CLASSPATH_TYPE = "com.example.FromClasspath";
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedAnnotationTypes() {
|
||||
return Collections.singleton("example.ExampleAnnotation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (annotations.isEmpty()) return true;
|
||||
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(annotations.iterator().next())) {
|
||||
if (element instanceof TypeElement || element instanceof ExecutableElement || element instanceof VariableElement) {
|
||||
String name = element.getSimpleName().toString();
|
||||
name = name.substring(0, 1).toUpperCase() + name.substring(1) + "Generated";
|
||||
|
||||
String packageName;
|
||||
if (element instanceof TypeElement) {
|
||||
packageName = element.getEnclosingElement().getSimpleName().toString();
|
||||
}
|
||||
else {
|
||||
packageName = element.getEnclosingElement().getEnclosingElement().getSimpleName().toString();
|
||||
}
|
||||
|
||||
try (Writer writer = processingEnv.getFiler().createSourceFile(packageName + "." + name, element).openWriter()) {
|
||||
writer.append("package ").append(packageName).append(";");
|
||||
writer.append("\npublic class ").append(name).append(" extends ").append(CLASSPATH_TYPE).append(" {}");
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+35
-11
@@ -27,6 +27,7 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() {
|
||||
override fun defaultBuildOptions(): BuildOptions =
|
||||
super.defaultBuildOptions().copy(
|
||||
incremental = true,
|
||||
debug=false,
|
||||
kaptOptions = KaptOptions(
|
||||
verbose = true,
|
||||
useWorkers = true,
|
||||
@@ -171,7 +172,7 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() {
|
||||
}
|
||||
project.build("build") {
|
||||
assertSuccessful()
|
||||
assertTrue(getProcessedSources(output).isEmpty())
|
||||
assertTrue(output.contains("Skipping annotation processing as all sources are up-to-date."))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,8 +276,9 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() {
|
||||
assertEquals(
|
||||
setOf(
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/NoAnnotationsKt.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath
|
||||
), getProcessedSources(output)
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary },
|
||||
).filterNotNull().toSet(), getProcessedSources(output)
|
||||
)
|
||||
|
||||
checkAggregatingResource { lines ->
|
||||
@@ -302,9 +304,9 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() {
|
||||
assertEquals(
|
||||
setOf(
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/baz/BazClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath
|
||||
),
|
||||
getProcessedSources(output)
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary },
|
||||
).filterNotNull().toSet(), getProcessedSources(output)
|
||||
)
|
||||
|
||||
checkAggregatingResource { lines ->
|
||||
@@ -330,9 +332,9 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() {
|
||||
assertEquals(
|
||||
setOf(
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/baz/BazClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath
|
||||
),
|
||||
getProcessedSources(output)
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary },
|
||||
).filterNotNull().toSet(), getProcessedSources(output)
|
||||
)
|
||||
|
||||
checkAggregatingResource { lines ->
|
||||
@@ -351,8 +353,30 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() {
|
||||
assertEquals(
|
||||
setOf(
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/NoAnnotationsKt.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath
|
||||
), getProcessedSources(output)
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary },
|
||||
fileInWorkingDir("build/generated/source/kapt/main/BazClass/BazNestedGenerated.java").canonicalPath.takeUnless { isBinary },
|
||||
).filterNotNull().toSet(), getProcessedSources(output)
|
||||
)
|
||||
|
||||
checkAggregatingResource { lines ->
|
||||
assertEquals(2, lines.size)
|
||||
assertTrue(lines.contains("WithAnnotationGenerated"))
|
||||
assertTrue(lines.contains("BazNestedGenerated"))
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that changing the origin of isolating that produced
|
||||
project.projectFile("withAnnotation.kt").modify { current -> current.substringBeforeLast("}") + "\nfun otherFunction() {} }" }
|
||||
project.build("build", options = buildOptions) {
|
||||
assertSuccessful()
|
||||
|
||||
assertEquals(
|
||||
setOf(
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/WithAnnotation.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath,
|
||||
fileInWorkingDir("build/generated/source/kapt/main/BazClass/BazNestedGenerated.java").canonicalPath.takeUnless { isBinary },
|
||||
).filterNotNull().toSet(), getProcessedSources(output)
|
||||
)
|
||||
|
||||
checkAggregatingResource { lines ->
|
||||
|
||||
+57
@@ -6,10 +6,14 @@
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessor
|
||||
import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessorReferencingClasspath
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assume
|
||||
import org.junit.Test
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.Type
|
||||
import test.kt33617.MyClass
|
||||
import java.io.File
|
||||
import java.util.zip.ZipEntry
|
||||
@@ -192,6 +196,59 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
|
||||
/** Regression test for https://youtrack.jetbrains.com/issue/KT-42182. */
|
||||
@Test
|
||||
fun testGeneratedSourcesImpactedByClasspathChanges() {
|
||||
val project = Project(
|
||||
"kaptIncrementalCompilationProject",
|
||||
GradleVersionRequired.None
|
||||
).apply {
|
||||
setupIncrementalAptProject("ISOLATING", procClass = IncrementalProcessorReferencingClasspath::class.java)
|
||||
}
|
||||
project.gradleSettingsScript().writeText("include ':', ':lib'")
|
||||
val classpathTypeSource = project.projectDir.resolve("lib").run {
|
||||
mkdirs()
|
||||
resolve("build.gradle").writeText("apply plugin: 'java'")
|
||||
val source = resolve("src/main/java/" + IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.replace(".", "/") + ".java")
|
||||
source.parentFile.mkdirs()
|
||||
|
||||
source.writeText(
|
||||
"""
|
||||
package ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringBeforeLast(".")};
|
||||
public class ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringAfterLast(".")} {}
|
||||
""".trimIndent()
|
||||
)
|
||||
return@run source
|
||||
}
|
||||
project.gradleBuildScript().appendText(
|
||||
"""
|
||||
|
||||
dependencies {
|
||||
implementation project(':lib')
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
project.build("clean", "kaptKotlin") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
// change type that all generated sources reference
|
||||
classpathTypeSource.writeText(classpathTypeSource.readText().replace("}", "int i = 10;\n}"))
|
||||
project.build("build") {
|
||||
assertSuccessful()
|
||||
assertEquals(
|
||||
setOf(
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/foo/A.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/B.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/UseBKt.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/baz/UtilKt.java").canonicalPath,
|
||||
fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath
|
||||
),
|
||||
getProcessedSources(output)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val patternApt = "Processing java sources with annotation processors:"
|
||||
|
||||
Reference in New Issue
Block a user