gnodet commented on code in PR #1144:
URL: 
https://github.com/apache/maven-compiler-plugin/pull/1144#discussion_r4130002910


##########
src/main/java/org/apache/maven/plugin/compiler/incremental/AbiIncrementalBuild.java:
##########
@@ -0,0 +1,511 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.compiler.incremental;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import com.sun.source.util.JavacTask;
+
+/**
+ * ABI-fingerprint-driven incremental build engine, designed for embedding
+ * in maven-compiler-plugin alongside the existing timestamp-based
+ * {@code IncrementalBuild}.
+ *
+ * <p>The plugin drives compilation; this class determines <em>what</em> to
+ * compile and collects analysis data during compilation. Typical usage:
+ *
+ * <pre>{@code
+ * var abi = new AbiIncrementalBuild(outputDir);
+ * abi.setClasspathEntries(classpath);
+ * abi.setReactorModulePaths(reactorModules);
+ *
+ * Set<Path> toCompile = abi.initialize(allSourceFiles);
+ *
+ * while (!toCompile.isEmpty()) {
+ *     JavacTask task = (JavacTask) compiler.getTask(..., toCompile, ...);
+ *     abi.attachTo(task);
+ *     if (!task.call()) break;
+ *     toCompile = abi.processRound();
+ * }
+ *
+ * abi.finish();
+ * }</pre>
+ *
+ * <p>The engine persists its state as {@code .incremental-state} and writes
+ * an {@link AbiManifest} ({@code .abi-fingerprints}) in the output directory
+ * for downstream reactor modules.
+ *
+ * @see CompilationAnalyzer
+ * @see IncrementalState
+ */
+public class AbiIncrementalBuild {
+
+    private final Path outputDir;
+    private final Path buildDir;
+    private final Path stateFile;
+    private List<Path> classpathEntries;
+    private Set<Path> reactorModulePaths;
+    private List<Path> processorPath;
+    private ProcessorClassification processorClassification;
+
+    private IncrementalState previousState;
+    private IncrementalState state;
+    private Map<String, String> sourceHashes;
+    private List<Path> allSourceFiles;
+    private Set<String> allCompiled;
+    private CompilationAnalyzer currentAnalyzer;
+    private boolean fullBuild;
+    private int totalSources;
+
+    public AbiIncrementalBuild(Path outputDir) {
+        this.outputDir = outputDir;
+        this.buildDir = outputDir.getParent() != null ? outputDir.getParent() 
: outputDir;
+        this.stateFile = buildDir.resolve(".incremental-state");
+    }
+
+    /**
+     * Sets classpath entries for cross-module ABI tracking. Directory entries
+     * are checked for {@link AbiManifest} files; JAR entries use bytecode
+     * analysis as fallback.
+     */
+    public void setClasspathEntries(List<Path> entries) {
+        this.classpathEntries = entries;
+    }
+
+    /**
+     * Marks specific classpath entries as reactor modules. These are always
+     * checked for ABI changes (via manifest or bytecode).
+     */
+    public void setReactorModulePaths(Set<Path> paths) {
+        this.reactorModulePaths = paths;
+    }
+
+    /**
+     * Sets the annotation processor classpath for processor classification.
+     * Entries are scanned for {@code 
META-INF/javaci/incremental.annotation.processors}
+     * and {@code META-INF/gradle/incremental.annotation.processors} to 
determine
+     * whether each processor is {@link ProcessorType#ISOLATING},
+     * {@link ProcessorType#AGGREGATING}, or {@link ProcessorType#UNKNOWN}.
+     */
+    public void setProcessorPath(List<Path> processorPath) {
+        this.processorPath = processorPath;
+        this.processorClassification = new 
ProcessorClassification(processorPath);
+    }
+
+    /**
+     * Initializes the incremental build by scanning source files and comparing
+     * against the previous build's state.
+     *
+     * @param allSourceFiles all source files in this module
+     * @return the set of files that need compilation (may be all files for a
+     *         full build, a subset for incremental, or empty if up-to-date)
+     */
+    public Set<Path> initialize(List<Path> allSourceFiles) throws IOException {
+        Files.createDirectories(outputDir);

Review Comment:
   Acknowledged. This is a valid optimization — mtime-first check before 
hashing would reduce I/O for the common no-change case. Tracking as a follow-up 
improvement, not blocking for this PR.



##########
src/main/java/org/apache/maven/plugin/compiler/incremental/CompilationAnalyzer.java:
##########
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.compiler.incremental;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeSet;
+
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.Trees;
+
+/**
+ * A {@link TaskListener} that intercepts javac's {@code ANALYZE} phase to 
extract
+ * per-type dependency and ABI information from a compilation.
+ *
+ * <p>For each type element analyzed, it runs a {@link DependencyScanner} over 
the
+ * compilation unit's AST to collect type references — classified as signature
+ * dependencies (appear in the public API surface) or implementation 
dependencies
+ * (body-only) — and uses {@link AbiExtractor} to compute an ABI fingerprint.
+ * Results are collected into {@link SourceFileAnalysis} records accessible
+ * via {@link #getResults()}.
+ *
+ * <p>JDK-internal types ({@code java.*}, {@code javax.*}, {@code jdk.*},
+ * {@code sun.*}) are filtered from the dependency sets since they never change
+ * across incremental builds.
+ */
+public class CompilationAnalyzer implements TaskListener {
+
+    private final Trees trees;
+    private final Map<String, SourceFileAnalysis> analyses = new 
LinkedHashMap<>();
+
+    public CompilationAnalyzer(JavacTask task) {
+        this.trees = Trees.instance(task);
+    }
+
+    @Override
+    public void finished(TaskEvent e) {
+        if (e.getKind() != TaskEvent.Kind.ANALYZE) {
+            return;
+        }
+
+        TypeElement typeElement = e.getTypeElement();

Review Comment:
   Acknowledged. The over-cascading for multi-type CUs is safe (false 
recompilations, not missed ones). Acceptable trade-off for the initial 
implementation — can be refined later if profiling shows it matters.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to