Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multiple annotation processing issues discovered by Micronaut #19067

Merged
merged 3 commits into from Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -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 {

Expand Down Expand Up @@ -53,6 +54,9 @@ abstract class AbstractIncrementalAnnotationProcessingIntegrationTest extends Ab
dependencies {
compileOnly project(":annotation")
annotationProcessor project(":processor")

testCompileOnly project(":annotation")
testAnnotationProcessor project(":processor")
}
"""

Expand All @@ -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)
}

Expand Down
Expand Up @@ -436,6 +436,23 @@ class AggregatingIncrementalAnnotationProcessingIntegrationTest extends Abstract
succeeds "compileJava"
}

@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())
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() {
Expand Down
Expand Up @@ -61,6 +61,25 @@ class IsolatingIncrementalAnnotationProcessingIntegrationTest extends AbstractIn
outputs.recompiledFiles("A", "AHelper", "AHelperResource.txt")
}

@Issue("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 {}"
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -73,40 +74,14 @@ 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);
File previousCompilationDataFile = Objects.requireNonNull(spec.getCompileOptions().getPreviousCompilationDataFile());
previousCompilationAccess.writePreviousCompilationData(data, previousCompilationDataFile);
}

private AnnotationProcessingData getAnnotationProcessingResult(JavaCompileSpec spec, WorkResult result) {
Set<AnnotationProcessorDeclaration> 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;
Expand Down Expand Up @@ -152,4 +127,62 @@ private Map<String, Set<String>> mergeSourceClassesMappings(Map<String, Set<Stri
return merged;
}

private AnnotationProcessingData getAnnotationProcessingData(JavaCompileSpec spec, WorkResult result) {
Set<AnnotationProcessorDeclaration> 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<String> 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<String> changedClasses) {
Map<String, Set<String>> generatedTypesByOrigin = new HashMap<>(oldData.getGeneratedTypesByOrigin());
changedClasses.forEach(generatedTypesByOrigin::remove);
generatedTypesByOrigin.putAll(newData.getGeneratedTypesByOrigin());
Map<String, Set<GeneratedResource>> generatedResourcesByOrigin = new HashMap<>(oldData.getGeneratedResourcesByOrigin());
changedClasses.forEach(generatedResourcesByOrigin::remove);
generatedResourcesByOrigin.putAll(newData.getGeneratedResourcesByOrigin());

return new AnnotationProcessingData(
generatedTypesByOrigin,
newData.getAggregatedTypes(),
newData.getGeneratedTypesDependingOnAllOthers(),
asodja marked this conversation as resolved.
Show resolved Hide resolved
generatedResourcesByOrigin,
newData.getGeneratedResourcesDependingOnAllOthers(),
newData.getFullRebuildCause()
);
}

}
Expand Up @@ -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<String> getTypesToReprocess(Set<String> compiledClasses) {
if (compiledClasses.isEmpty()) {
asodja marked this conversation as resolved.
Show resolved Hide resolved
return Collections.emptySet();
}
Set<String> typesToReprocess = new HashSet<>(annotationProcessingData.getAggregatedTypes());
for (Map.Entry<String, Set<String>> entry : annotationProcessingData.getGeneratedTypesByOrigin().entrySet()) {
if (entry.getValue().stream().anyMatch(compiledClasses::contains)) {
Expand Down