Skip to content

Commit

Permalink
Merge annotation processing data on subsequent compilations
Browse files Browse the repository at this point in the history
Otherwise generated files from old compilations would be forgotten.

Signed-off-by: Stefan Oehme <st.oehme@gmail.com>
  • Loading branch information
oehme committed Nov 22, 2021
1 parent fdb1e20 commit b2ba8ea
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 27 deletions.
Expand Up @@ -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 {}"
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(),
generatedResourcesByOrigin,
newData.getGeneratedResourcesDependingOnAllOthers(),
newData.getFullRebuildCause()
);
}

}

0 comments on commit b2ba8ea

Please sign in to comment.