From 74fe0ea285891eed47c58eb1771b9454f8747451 Mon Sep 17 00:00:00 2001 From: Christopher Ng Date: Mon, 18 Nov 2024 22:31:29 +0000 Subject: [PATCH] Fix classes being 'lost' when earlier rounds of annotation processing succeed before a later round fails Specifically, when a later round of annotation processing fails with a `SourceTypeCollisionException` (i.e. generated type referenced before it has been created). --- .../jdt/internal/compiler/Compiler.java | 22 ++++++++++++++----- .../lookup/SourceTypeCollisionException.java | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/Compiler.java index 5b624bd5048..4a7ce652ea4 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/Compiler.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/Compiler.java @@ -17,9 +17,11 @@ package org.eclipse.jdt.internal.compiler; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; @@ -480,13 +482,14 @@ private void compile(ICompilationUnit[] sourceUnits, boolean lastRound) { // a generated type was referenced before it was created // the compiler either created a MissingType or found a BinaryType for it // so add the processor's generated files & start over, - // but remember to only pass the generated files to the annotation processor + // but remember to only pass the failing files to the annotation processor int originalLength = originalUnits.length; int newProcessedLength = e.newAnnotationProcessorUnits.length; ICompilationUnit[] combinedUnits = new ICompilationUnit[originalLength + newProcessedLength]; System.arraycopy(originalUnits, 0, combinedUnits, 0, originalLength); System.arraycopy(e.newAnnotationProcessorUnits, 0, combinedUnits, originalLength, newProcessedLength); - this.annotationProcessorStartIndex = originalLength; + // need to offset by originalLength + this.annotationProcessorStartIndex = originalLength + e.annotationProcessorStartIndex; compile(combinedUnits, e.isLastRound); return; } @@ -982,6 +985,9 @@ protected void processAnnotations() { ReferenceBinding[] binaryTypeBindingsTemp = this.referenceBindings; if (top == 0 && binaryTypeBindingsTemp == null) return; this.referenceBindings = null; + // we can go through multiple rounds that each add newUnits - can't assume that the only units + // added were in the current round + List allNewUnits = new ArrayList<>(); do { // extract units to process int length = top - bottom; @@ -1008,16 +1014,18 @@ protected void processAnnotations() { this.annotationProcessorStartIndex = top; ICompilationUnit[] newUnits = this.annotationProcessorManager.getNewUnits(); newUnitSize = newUnits.length; + allNewUnits.addAll(Arrays.asList(newUnits)); ReferenceBinding[] newClassFiles = this.annotationProcessorManager.getNewClassFiles(); binaryTypeBindingsTemp = newClassFiles; newClassFilesSize = newClassFiles.length; if (newUnitSize != 0) { - ICompilationUnit[] newProcessedUnits = newUnits.clone(); // remember new units in case a source type collision occurs try { this.lookupEnvironment.isProcessingAnnotations = true; internalBeginToCompile(newUnits, newUnitSize); } catch (SourceTypeCollisionException e) { - e.newAnnotationProcessorUnits = newProcessedUnits; + e.newAnnotationProcessorUnits = allNewUnits.toArray(new ICompilationUnit[0]); + // need to restart again from where the *current* round failed, not all new units + e.annotationProcessorStartIndex = allNewUnits.size() - newUnitSize; throw e; } finally { this.lookupEnvironment.isProcessingAnnotations = false; @@ -1036,15 +1044,17 @@ protected void processAnnotations() { // process potential units added in the final round see 329156 ICompilationUnit[] newUnits = this.annotationProcessorManager.getNewUnits(); newUnitSize = newUnits.length; + allNewUnits.addAll(Arrays.asList(newUnits)); try { if (newUnitSize != 0) { - ICompilationUnit[] newProcessedUnits = newUnits.clone(); // remember new units in case a source type collision occurs try { this.lookupEnvironment.isProcessingAnnotations = true; internalBeginToCompile(newUnits, newUnitSize); } catch (SourceTypeCollisionException e) { e.isLastRound = true; - e.newAnnotationProcessorUnits = newProcessedUnits; + e.newAnnotationProcessorUnits = allNewUnits.toArray(new ICompilationUnit[0]); + // need to restart again from where the *current* round failed, not all new units + e.annotationProcessorStartIndex = allNewUnits.size() - newUnitSize; throw e; } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java index 65565a40ad1..aa252f6b4e5 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeCollisionException.java @@ -19,4 +19,9 @@ public class SourceTypeCollisionException extends RuntimeException { private static final long serialVersionUID = 4798247636899127380L; public boolean isLastRound = false; public ICompilationUnit[] newAnnotationProcessorUnits; + /** + * The index within {@link #newAnnotationProcessorUnits} where annotation processing should + * resume. + */ + public int annotationProcessorStartIndex; }