From fdb1e2051fa6478b826d22a20a7bfbc4082d0362 Mon Sep 17 00:00:00 2001 From: Stefan Oehme Date: Fri, 19 Nov 2021 19:42:36 +0100 Subject: [PATCH 1/3] Don't reprocess aggregated types when there's nothing to compile Fixes https://github.com/micronaut-projects/micronaut-core/issues/6536 Signed-off-by: Stefan Oehme --- ...alAnnotationProcessingIntegrationTest.groovy | 6 +++++- ...alAnnotationProcessingIntegrationTest.groovy | 17 +++++++++++++++++ .../incremental/deps/ClassSetAnalysis.java | 3 +++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AbstractIncrementalAnnotationProcessingIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AbstractIncrementalAnnotationProcessingIntegrationTest.groovy index f0f309cf0006..1703b9772c43 100644 --- a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AbstractIncrementalAnnotationProcessingIntegrationTest.groovy +++ b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AbstractIncrementalAnnotationProcessingIntegrationTest.groovy @@ -21,6 +21,7 @@ import org.gradle.integtests.fixtures.CompilationOutputsFixture import org.gradle.language.fixtures.AnnotationProcessorFixture import org.gradle.language.fixtures.CompileJavaBuildOperationsFixture import org.gradle.test.fixtures.file.TestFile +import org.intellij.lang.annotations.Language abstract class AbstractIncrementalAnnotationProcessingIntegrationTest extends AbstractIntegrationSpec { @@ -53,6 +54,9 @@ abstract class AbstractIncrementalAnnotationProcessingIntegrationTest extends Ab dependencies { compileOnly project(":annotation") annotationProcessor project(":processor") + + testCompileOnly project(":annotation") + testAnnotationProcessor project(":processor") } """ @@ -70,7 +74,7 @@ abstract class AbstractIncrementalAnnotationProcessingIntegrationTest extends Ab processor.writeAnnotationProcessorTo(processorProjectDir) } - protected final File java(String... classBodies) { + protected final File java(@Language("java") String... classBodies) { javaInPackage('', classBodies) } diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy index f35b4bdce7ec..f6558187f78e 100644 --- a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy +++ b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy @@ -436,6 +436,23 @@ class AggregatingIncrementalAnnotationProcessingIntegrationTest extends Abstract succeeds "compileJava" } + @Issue("https://https://github.com/micronaut-projects/micronaut-core/issues/6536") + def "does not reprocess if nothing in the current sourceSet changed"() { + given: + withProcessor(new AnnotatedGeneratedClassProcessorFixture()) + javaTestSourceFile "@Bean class Test {}" + outputs.snapshot { succeeds "compileTestJava" } + + when: + java "class Unrelated {}" + + then: + succeeds "compileTestJava" + + and: + outputs.recompiledClasses("Unrelated") + } + private boolean serviceRegistryReferences(String... services) { def registry = file("build/classes/java/main/ServiceRegistryResource.txt").text services.every() { diff --git a/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/deps/ClassSetAnalysis.java b/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/deps/ClassSetAnalysis.java index 96bd0434c401..d16862dccc4a 100644 --- a/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/deps/ClassSetAnalysis.java +++ b/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/deps/ClassSetAnalysis.java @@ -157,6 +157,9 @@ private DependentsSet findDirectDependents(String className) { * - the originating types of generated classes that need to be recompiled, since they wouldn't exist if the originating type is not reprocessed */ public Set getTypesToReprocess(Set compiledClasses) { + if (compiledClasses.isEmpty()) { + return Collections.emptySet(); + } Set typesToReprocess = new HashSet<>(annotationProcessingData.getAggregatedTypes()); for (Map.Entry> entry : annotationProcessingData.getGeneratedTypesByOrigin().entrySet()) { if (entry.getValue().stream().anyMatch(compiledClasses::contains)) { From b2ba8ea725eea4386eea8094ed2b1de98c6e53ba Mon Sep 17 00:00:00 2001 From: Stefan Oehme Date: Mon, 22 Nov 2021 12:57:12 +0100 Subject: [PATCH 2/3] Merge annotation processing data on subsequent compilations Otherwise generated files from old compilations would be forgotten. Signed-off-by: Stefan Oehme --- ...AnnotationProcessingIntegrationTest.groovy | 19 ++++ .../IncrementalResultStoringCompiler.java | 87 +++++++++++++------ 2 files changed, 79 insertions(+), 27 deletions(-) diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy index 94d410667753..edf9a236ce64 100644 --- a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy +++ b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy @@ -61,6 +61,25 @@ class IsolatingIncrementalAnnotationProcessingIntegrationTest extends AbstractIn outputs.recompiledFiles("A", "AHelper", "AHelperResource.txt") } + @Issue("https://https://github.com/micronaut-projects/micronaut-core/issues/6536") + def "remembers generated files across multiple compilations"() { + given: + def a = java "@Helper class A {}" + def b = java "@Helper class B {}" + java "class Unrelated {}" + run "compileJava" + a.text = "@Helper class A { public void foo() {} }" + outputs.snapshot { run "compileJava" } + + when: + b.text = " class B { }" + run "compileJava" + + then: + outputs.deletedFiles("BHelper", "BHelperResource") + outputs.recompiledFiles("B") + } + def "generated files are recompiled when annotated file is affected by a change"() { given: def util = java "class Util {}" diff --git a/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/IncrementalResultStoringCompiler.java b/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/IncrementalResultStoringCompiler.java index 3a84da9c2182..494ff722f46f 100644 --- a/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/IncrementalResultStoringCompiler.java +++ b/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/IncrementalResultStoringCompiler.java @@ -25,6 +25,7 @@ import org.gradle.api.internal.tasks.compile.incremental.compilerapi.CompilerApiData; import org.gradle.api.internal.tasks.compile.incremental.compilerapi.constants.ConstantToDependentsMapping; import org.gradle.api.internal.tasks.compile.incremental.compilerapi.constants.ConstantToDependentsMappingMerger; +import org.gradle.api.internal.tasks.compile.incremental.compilerapi.deps.GeneratedResource; import org.gradle.api.internal.tasks.compile.incremental.deps.ClassSetAnalysisData; import org.gradle.api.internal.tasks.compile.incremental.processing.AnnotationProcessingData; import org.gradle.api.internal.tasks.compile.incremental.processing.AnnotationProcessingResult; @@ -73,7 +74,7 @@ public WorkResult execute(T spec) { private void storeResult(JavaCompileSpec spec, WorkResult result) { ClassSetAnalysisData outputSnapshot = classpathSnapshotter.analyzeOutputFolder(spec.getDestinationDir()); ClassSetAnalysisData classpathSnapshot = classpathSnapshotter.getClasspathSnapshot(Iterables.concat(spec.getCompileClasspath(), spec.getModulePath())); - AnnotationProcessingData annotationProcessingData = getAnnotationProcessingResult(spec, result); + AnnotationProcessingData annotationProcessingData = getAnnotationProcessingData(spec, result); CompilerApiData compilerApiData = getCompilerApiData(spec, result); ClassSetAnalysisData minimizedClasspathSnapshot = classpathSnapshot.reduceToTypesAffecting(outputSnapshot, compilerApiData); PreviousCompilationData data = new PreviousCompilationData(outputSnapshot, annotationProcessingData, minimizedClasspathSnapshot, compilerApiData); @@ -81,32 +82,6 @@ private void storeResult(JavaCompileSpec spec, WorkResult result) { previousCompilationAccess.writePreviousCompilationData(data, previousCompilationDataFile); } - private AnnotationProcessingData getAnnotationProcessingResult(JavaCompileSpec spec, WorkResult result) { - Set processors = spec.getEffectiveAnnotationProcessors(); - if (processors.isEmpty()) { - return new AnnotationProcessingData(); - } - if (result instanceof IncrementalCompilationResult) { - result = ((IncrementalCompilationResult) result).getCompilerResult(); - } - if (result instanceof ApiCompilerResult) { - AnnotationProcessingResult processingResult = ((ApiCompilerResult) result).getAnnotationProcessingResult(); - return convertProcessingResult(processingResult); - } - return new AnnotationProcessingData(ImmutableMap.of(), ImmutableSet.of(), ImmutableSet.of(), ImmutableMap.of(), ImmutableSet.of(), "the chosen compiler did not support incremental annotation processing"); - } - - private AnnotationProcessingData convertProcessingResult(AnnotationProcessingResult processingResult) { - return new AnnotationProcessingData( - processingResult.getGeneratedTypesWithIsolatedOrigin(), - processingResult.getAggregatedTypes(), - processingResult.getGeneratedAggregatingTypes(), - processingResult.getGeneratedResourcesWithIsolatedOrigin(), - processingResult.getGeneratedAggregatingResources(), - processingResult.getFullRebuildCause() - ); - } - private CompilerApiData getCompilerApiData(JavaCompileSpec spec, WorkResult result) { if (spec.getCompileOptions().supportsCompilerApi()) { CompilerApiData previousCompilerApiData = null; @@ -152,4 +127,62 @@ private Map> mergeSourceClassesMappings(Map processors = spec.getEffectiveAnnotationProcessors(); + if (processors.isEmpty()) { + return new AnnotationProcessingData(); + } + AnnotationProcessingData previousAnnotationProcessingData = null; + RecompilationSpec recompilationSpec = null; + if (result instanceof IncrementalCompilationResult) { + previousAnnotationProcessingData = ((IncrementalCompilationResult) result).getPreviousCompilationData().getAnnotationProcessingData(); + recompilationSpec = ((IncrementalCompilationResult) result).getRecompilationSpec(); + result = ((IncrementalCompilationResult) result).getCompilerResult(); + } + Set changedClasses = recompilationSpec == null ? Collections.emptySet() : recompilationSpec.getClassesToCompile(); + + if (result instanceof ApiCompilerResult) { + AnnotationProcessingResult processingResult = ((ApiCompilerResult) result).getAnnotationProcessingResult(); + AnnotationProcessingData newAnnotationProcessingData = new AnnotationProcessingData( + processingResult.getGeneratedTypesWithIsolatedOrigin(), + processingResult.getAggregatedTypes(), + processingResult.getGeneratedAggregatingTypes(), + processingResult.getGeneratedResourcesWithIsolatedOrigin(), + processingResult.getGeneratedAggregatingResources(), + processingResult.getFullRebuildCause() + ); + if (previousAnnotationProcessingData == null) { + return newAnnotationProcessingData; + } + return mergeAnnotationProcessingData(previousAnnotationProcessingData, newAnnotationProcessingData, changedClasses); + } + return new AnnotationProcessingData( + ImmutableMap.of(), + ImmutableSet.of(), + ImmutableSet.of(), + ImmutableMap.of(), + ImmutableSet.of(), + "the chosen compiler did not support incremental annotation processing" + ); + + } + + private AnnotationProcessingData mergeAnnotationProcessingData(AnnotationProcessingData oldData, AnnotationProcessingData newData, Set changedClasses) { + Map> generatedTypesByOrigin = new HashMap<>(oldData.getGeneratedTypesByOrigin()); + changedClasses.forEach(generatedTypesByOrigin::remove); + generatedTypesByOrigin.putAll(newData.getGeneratedTypesByOrigin()); + Map> generatedResourcesByOrigin = new HashMap<>(oldData.getGeneratedResourcesByOrigin()); + changedClasses.forEach(generatedResourcesByOrigin::remove); + generatedResourcesByOrigin.putAll(newData.getGeneratedResourcesByOrigin()); + + return new AnnotationProcessingData( + generatedTypesByOrigin, + newData.getAggregatedTypes(), + newData.getGeneratedTypesDependingOnAllOthers(), + generatedResourcesByOrigin, + newData.getGeneratedResourcesDependingOnAllOthers(), + newData.getFullRebuildCause() + ); + } + } From 7a897d382993a7989517e97c521ba30d7388da1d Mon Sep 17 00:00:00 2001 From: Stefan Oehme Date: Wed, 24 Nov 2021 16:14:22 +0100 Subject: [PATCH 3/3] Fix links Signed-off-by: Stefan Oehme --- ...egatingIncrementalAnnotationProcessingIntegrationTest.groovy | 2 +- ...olatingIncrementalAnnotationProcessingIntegrationTest.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy index f6558187f78e..d78b30e035b7 100644 --- a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy +++ b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/AggregatingIncrementalAnnotationProcessingIntegrationTest.groovy @@ -436,7 +436,7 @@ class AggregatingIncrementalAnnotationProcessingIntegrationTest extends Abstract succeeds "compileJava" } - @Issue("https://https://github.com/micronaut-projects/micronaut-core/issues/6536") + @Issue("https://github.com/micronaut-projects/micronaut-core/issues/6536") def "does not reprocess if nothing in the current sourceSet changed"() { given: withProcessor(new AnnotatedGeneratedClassProcessorFixture()) diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy index edf9a236ce64..a0a813006e7e 100644 --- a/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy +++ b/subprojects/language-java/src/integTest/groovy/org/gradle/api/tasks/compile/IsolatingIncrementalAnnotationProcessingIntegrationTest.groovy @@ -61,7 +61,7 @@ class IsolatingIncrementalAnnotationProcessingIntegrationTest extends AbstractIn outputs.recompiledFiles("A", "AHelper", "AHelperResource.txt") } - @Issue("https://https://github.com/micronaut-projects/micronaut-core/issues/6536") + @Issue("https://github.com/micronaut-projects/micronaut-core/issues/6536") def "remembers generated files across multiple compilations"() { given: def a = java "@Helper class A {}"