diff --git a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java
index 302f0e0524e..488f9598d08 100644
--- a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java
+++ b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java
@@ -249,7 +249,7 @@ public String[] getGeneratedSourcePaths(IJavaProject project, boolean isTest) {
}
IFolder folder = generatedSourceFolderManager.getFolder();
- return folder == null ? null : new String[] { folder.getLocation().toOSString() };
+ return folder == null || folder.getLocation() == null ? null : new String[] { folder.getLocation().toOSString() };
}
@Override
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.classpath b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.classpath
new file mode 100644
index 00000000000..e90d2ab51b7
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.factorypath b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.factorypath
new file mode 100644
index 00000000000..cf12c6aae49
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.factorypath
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.project b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.project
new file mode 100644
index 00000000000..7f251d1870a
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.project
@@ -0,0 +1,19 @@
+
+
+ autoValueSnippet
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
+
+
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.apt.core.prefs b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.apt.core.prefs
new file mode 100644
index 00000000000..74a3c0a0761
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.apt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.apt.aptEnabled=true
+org.eclipse.jdt.apt.genSrcDir=.apt_generated
+org.eclipse.jdt.apt.genTestSrcDir=.apt_generated_tests
+org.eclipse.jdt.apt.reconcileEnabled=true
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..13bd0e37f06
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,16 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.processAnnotations=enabled
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-1.6.5.jar b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-1.6.5.jar
new file mode 100644
index 00000000000..be17cd17333
Binary files /dev/null and b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-1.6.5.jar differ
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-annotations-1.6.5.jar b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-annotations-1.6.5.jar
new file mode 100644
index 00000000000..f68a0136753
Binary files /dev/null and b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-annotations-1.6.5.jar differ
diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/src/Outer.java b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/src/Outer.java
new file mode 100644
index 00000000000..335144144a0
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/src/Outer.java
@@ -0,0 +1,23 @@
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class Outer {
+
+ public static Outer create(Inner value) {
+ return new AutoValue_Outer(value);
+ }
+
+ public abstract Inner inner();
+
+ @AutoValue
+ public abstract static class Inner {
+
+ public static Inner create(String value) {
+ return new AutoValue_Outer_Inner(value);
+ }
+
+ public abstract String value();
+
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java
index 3ae4de016ed..3afe0c31dd4 100644
--- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java
@@ -15,13 +15,35 @@
*******************************************************************************/
package org.eclipse.jdt.core.tests.builder;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
import junit.framework.*;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.core.IJavaProject;
@@ -29,11 +51,15 @@
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.tests.util.Util;
import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.CompilerConfiguration;
+import org.eclipse.jdt.internal.compiler.ICompilerFactory;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.core.JavaModelManager;
@@ -697,11 +723,10 @@ public void testBug549942() throws JavaModelException {
}
}
- public void testCustomCompiler() throws JavaModelException {
- final String CUSTOM_COMPILER_KEY = AbstractImageBuilder.class.getSimpleName() + ".compiler";
- final String CUSTOM_COMPILER_VALUE = MockCompiler.class.getName();
+ public void testCustomCompilerFactory() throws JavaModelException {
+ final String CUSTOM_COMPILER_VALUE = MockCompilerFactory.class.getName();
try {
- System.setProperty(CUSTOM_COMPILER_KEY, CUSTOM_COMPILER_VALUE);
+ System.setProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY, CUSTOM_COMPILER_VALUE);
IPath projectPath = env.addProject("Project"); //$NON-NLS-1$
env.addExternalJars(projectPath, Util.getJavaClassLibs());
@@ -712,12 +737,14 @@ public void testCustomCompiler() throws JavaModelException {
env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$
IPath path = env.addClass(root, "p1", "Hello", //$NON-NLS-1$ //$NON-NLS-2$
- "package p1;\n"+ //$NON-NLS-1$
- "public class Hello {\n"+ //$NON-NLS-1$
- " public static void main(String args[]) {\n"+ //$NON-NLS-1$
- " System.out.println(\"Hello world\");\n"+ //$NON-NLS-1$
- " }\n"+ //$NON-NLS-1$
- "}\n" //$NON-NLS-1$
+ """
+ package p1;
+ public class Hello {
+ public static void main(String args[]) {
+ System.out.println(\"Hello world\");
+ }
+ }
+ """
);
fullBuild(projectPath);
@@ -727,15 +754,139 @@ public void testCustomCompiler() throws JavaModelException {
"Problem : Compilation error from MockCompiler [ resource : range : <0,1> category : <60> severity : <2>]"
);
} finally {
- System.clearProperty(CUSTOM_COMPILER_KEY);
+ System.clearProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY);
}
}
- public void testFallbackForProblematicCompiler() throws JavaModelException {
- final String CUSTOM_COMPILER_KEY = AbstractImageBuilder.class.getSimpleName() + ".compiler";
- final String CUSTOM_COMPILER_VALUE = "x.y.NotFoundCompiler";
+ public void testCustomerCompilerFactoryWithAP() throws Exception {
+ final String CUSTOM_COMPILER_VALUE = MockCompilerFactory.class.getName();
+ List configs = new ArrayList<>();
+ Consumer listener = (compiler) -> {
+ if (compiler instanceof MockCompiler mockCompiler) {
+ configs.add(mockCompiler.compilerConfig);
+ }
+ };
+ try {
+ MockCompilerFactory.addListener(listener);
+ System.setProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY, CUSTOM_COMPILER_VALUE);
+ File projectRoot = copyFiles("autoValueSnippet", true);
+ IPath dotProjectPath = new org.eclipse.core.runtime.Path(new File(projectRoot, IProjectDescription.DESCRIPTION_FILE_NAME).getAbsolutePath());
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IProjectDescription descriptor = workspace.loadProjectDescription(dotProjectPath);
+ String projectName = descriptor.getName();
+ IProject project = workspace.getRoot().getProject(projectName);
+ project.create(descriptor, new NullProgressMonitor());
+ project.open(IResource.NONE, new NullProgressMonitor());
+
+ // full build
+ project.build(IncrementalProjectBuilder.FULL_BUILD, null);
+
+ // It creates compiler 4 times (MAIN full build, TEST full build, MAIN incremental build, TEST incremental build)
+ assertEquals(4, configs.size());
+ CompilerConfiguration config = configs.get(0);
+ List processorPaths = config.annotationProcessorPaths();
+ assertEquals(2, processorPaths.size());
+ assertTrue(processorPaths.get(0).endsWith("auto-value-1.6.5.jar"));
+ assertTrue(processorPaths.get(1).endsWith("auto-value-annotations-1.6.5.jar"));
+
+ List generatedSourcePaths = config.generatedSourcePaths();
+ assertEquals(1, generatedSourcePaths.size());
+ assertTrue(generatedSourcePaths.get(0).endsWith(".apt_generated"));
+
+ List sourcePaths = config.sourcepaths();
+ assertEquals(2, sourcePaths.size());
+ assertTrue(sourcePaths.get(0).endsWith("src"));
+ assertTrue(sourcePaths.get(1).endsWith(".apt_generated"));
+
+ List classPaths = config.classpaths();
+ assertEquals(2, classPaths.size());
+ assertTrue(classPaths.get(0).endsWith("bin"));
+ assertTrue(classPaths.get(1).endsWith("auto-value-annotations-1.6.5.jar"));
+
+ List moduleSourcePaths = config.moduleSourcepaths();
+ assertEquals(0, moduleSourcePaths.size());
+
+ List modulePaths = config.modulepaths();
+ assertEquals(0, modulePaths.size());
+
+ Map sourceOutputMapping = config.sourceOutputMapping();
+ assertEquals(2, sourceOutputMapping.size());
+
+ IFile aptGeneratedFile = project.getFile(".apt_generated/AutoValue_Outer.java");
+ assertFalse("The default APT generation should be disabled for custom compiler", aptGeneratedFile.exists());
+ } finally {
+ MockCompilerFactory.removeListener(listener);
+ System.clearProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY);
+ }
+ }
+
+ private File copyFiles(String path, boolean reimportIfExists) throws IOException {
+ File from = new File(getSourceProjectDirectory(), path);
+ File to = new File(getWorkingProjectDirectory(), path);
+ if (to.exists()) {
+ if (!reimportIfExists) {
+ return to;
+ }
+ if (to.isFile()) {
+ Files.delete(to.toPath());
+ } else {
+ deleteDirectory(to.toPath());
+ }
+ }
+
+ if (from.isDirectory()) {
+ copyDirectory(from.toPath(), to.toPath());
+ } else {
+ Files.copy(from.toPath(), to.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ return to;
+ }
+
+ private File getSourceProjectDirectory() {
+ return new File("resources");
+ }
+
+ private File getWorkingProjectDirectory() throws IOException {
+ File dir = new File("target", "workingProjects");
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ return dir;
+ }
+
+ private static void deleteDirectory(Path path) throws IOException {
+ Files.walkFileTree(path, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ private static void copyDirectory(Path sourceDirectory, Path targetDirectory) throws IOException {
+ Files.walk(sourceDirectory)
+ .forEach(sourcePath -> {
+ Path targetPath = targetDirectory.resolve(sourceDirectory.relativize(sourcePath));
+ try {
+ Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ // ignore
+ }
+ });
+ }
+
+ public void testFallbackForProblematicCompilerFactory() throws JavaModelException {
+ final String CUSTOM_COMPILER_VALUE = "x.y.NotFoundCompilerFactory";
try {
- System.setProperty(CUSTOM_COMPILER_KEY, CUSTOM_COMPILER_VALUE);
+ System.setProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY, CUSTOM_COMPILER_VALUE);
IPath projectPath = env.addProject("Project"); //$NON-NLS-1$
env.addExternalJars(projectPath, Util.getJavaClassLibs());
@@ -746,12 +897,14 @@ public void testFallbackForProblematicCompiler() throws JavaModelException {
env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$
IPath path = env.addClass(root, "p1", "Hello", //$NON-NLS-1$ //$NON-NLS-2$
- "package p1;\n"+ //$NON-NLS-1$
- "public class Hello {\n"+ //$NON-NLS-1$
- " public static void main(String args[]) {\n"+ //$NON-NLS-1$
- " int unUsedVarable;\n"+ //$NON-NLS-1$
- " }\n"+ //$NON-NLS-1$
- "}\n" //$NON-NLS-1$
+ """
+ package p1;
+ public class Hello {
+ public static void main(String args[]) {
+ int unUsedVarable;
+ }
+ }
+ """
);
fullBuild(projectPath);
@@ -762,16 +915,39 @@ public void testFallbackForProblematicCompiler() throws JavaModelException {
"Problem : The value of the local variable unUsedVarable is not used [ resource : range : <87,100> category : <120> severity : <1>]"
);
} finally {
- System.clearProperty(CUSTOM_COMPILER_KEY);
+ System.clearProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY);
+ }
+ }
+
+ public static class MockCompilerFactory implements ICompilerFactory {
+ static Set> listeners = new HashSet<>();
+
+ @Override
+ public Compiler newCompiler(INameEnvironment environment, IErrorHandlingPolicy policy,
+ CompilerConfiguration compilerConfig, ICompilerRequestor requestor, IProblemFactory problemFactory) {
+ Compiler compiler = new MockCompiler(environment, policy, compilerConfig, requestor, problemFactory);
+ for (Consumer listener : listeners) {
+ listener.accept(compiler);
+ }
+
+ return compiler;
+ }
+
+ static void addListener(Consumer listener) {
+ listeners.add(listener);
+ }
+
+ static void removeListener(Consumer listener) {
+ listeners.remove(listener);
}
}
- public static class MockCompiler extends org.eclipse.jdt.internal.compiler.Compiler {
- private CompilerConfiguration compilerConfig;
+ static class MockCompiler extends org.eclipse.jdt.internal.compiler.Compiler {
+ CompilerConfiguration compilerConfig;
public MockCompiler(INameEnvironment environment, IErrorHandlingPolicy policy, CompilerConfiguration compilerConfig,
ICompilerRequestor requestor, IProblemFactory problemFactory) {
- super(environment, policy, compilerConfig.getOptions(), requestor, problemFactory);
+ super(environment, policy, new CompilerOptions(compilerConfig.compilerOptions()), requestor, problemFactory);
this.compilerConfig = compilerConfig;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilerConfiguration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilerConfiguration.java
deleted file mode 100644
index 358c8d7df59..00000000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilerConfiguration.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*******************************************************************************
-* Copyright (c) 2024 Microsoft Corporation and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License 2.0
-* which accompanies this distribution, and is available at
-* https://www.eclipse.org/legal/epl-2.0/
-*
-* SPDX-License-Identifier: EPL-2.0
-*
-* Contributors:
-* Microsoft Corporation - initial API and implementation
-*******************************************************************************/
-
-package org.eclipse.jdt.core.compiler;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
-
-/**
- * This class encapsulates the standard compiler options that can be
- * used to compile Java files. It provides methods to set and retrieve
- * various compiler options, including source paths, class paths,
- * output directories, annotation processing options, and other compiler
- * arguments.
- *
- * Clients typically use this class when opting for an alternative compiler
- * like Javac to compile Java files.
- *
- * @since 3.38
- * @noextend This class is not intended to be subclassed by clients.
- */
-public class CompilerConfiguration {
- List sourcepaths;
- List moduleSourcepaths;
- List classpaths;
- List modulepaths;
- Map sourceOutputMapping;
- CompilerOptions options;
- // Location to search for annotation processors.
- List annotationProcessorPaths;
- // Locations to place generated source files.
- List generatedSourcePaths;
-
- /**
- * Returns where to find user class files and annotation processors.
- */
- public List getClasspaths() {
- return this.classpaths;
- }
-
- /**
- * Sets where to find user class files and annotation processors.
- * @param classpaths the list of class paths
- */
- public void setClasspaths(List classpaths) {
- this.classpaths = classpaths;
- }
-
- /**
- * Returns where to find modules.
- */
- public List getModulepaths() {
- return this.modulepaths;
- }
-
- /**
- * Sets where to find modules.
- * @param modulepaths the list of module paths
- */
- public void setModulepaths(List modulepaths) {
- this.modulepaths = modulepaths;
- }
-
- /**
- * Returns the source code path to search for class or interface definitions.
- */
- public List getSourcepaths() {
- return this.sourcepaths;
- }
-
- /**
- * Sets the source code path to search for class or interface definitions.
- * @param sourcepaths the list of source paths
- */
- public void setSourcepaths(List sourcepaths) {
- this.sourcepaths = sourcepaths;
- }
-
- /**
- * Returns where to find source files when compiling modules.
- */
- public List getModuleSourcepaths() {
- return this.moduleSourcepaths;
- }
-
- /**
- * Sets where to find source files when compiling modules.
- * @param moduleSourcepaths the list of module source paths
- */
- public void setModuleSourcepaths(List moduleSourcepaths) {
- this.moduleSourcepaths = moduleSourcepaths;
- }
-
- /**
- * Returns the mapping of source files to output directories.
- */
- public Map getSourceOutputMapping() {
- return this.sourceOutputMapping;
- }
-
- /**
- * Sets the mapping of source files to output directories.
- * @param sourceOutputMapping the source output mapping
- */
- public void setSourceOutputMapping(Map sourceOutputMapping) {
- this.sourceOutputMapping = sourceOutputMapping;
- }
-
- /**
- * Returns the compiler options to be used for compilation.
- *
- * @see {@link org.eclipse.jdt.internal.compiler.impl.CompilerOptions} for a list of available options.
- */
- public CompilerOptions getOptions() {
- return this.options;
- }
-
- /**
- * Sets the compiler options to be used for compilation.
- * @param options the compiler options
- * @see {@link org.eclipse.jdt.internal.compiler.impl.CompilerOptions} for a list of available options.
- */
- public void setOptions(CompilerOptions options) {
- this.options = options;
- }
-
- /**
- * Returns the locations to search for annotation processors.
- */
- public List getAnnotationProcessorPaths() {
- return this.annotationProcessorPaths;
- }
-
- /**
- * Sets the locations to search for annotation processors.
- * @param annotationProcessorPaths the list of annotation processor paths
- */
- public void setAnnotationProcessorPaths(List annotationProcessorPaths) {
- this.annotationProcessorPaths = annotationProcessorPaths;
- }
-
- /**
- * Returns the locations to place generated source files.
- */
- public List getGeneratedSourcePaths() {
- return this.generatedSourcePaths;
- }
-
- /**
- * Sets the locations to place generated source files.
- * @param generatedSourcePaths the list of generated source paths
- */
- public void setGeneratedSourcePaths(List generatedSourcePaths) {
- this.generatedSourcePaths = generatedSourcePaths;
- }
-}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/CompilerConfiguration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/CompilerConfiguration.java
new file mode 100644
index 00000000000..ec2b4f3c5fa
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/CompilerConfiguration.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+* Copyright (c) 2024 Microsoft Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License 2.0
+* which accompanies this distribution, and is available at
+* https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Microsoft Corporation - initial API and implementation
+*******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class encapsulates the standard compiler options that can be
+ * used to compile Java files. It provides methods to set and retrieve
+ * various compiler options, including source paths, class paths,
+ * output directories, annotation processing options, and other compiler
+ * arguments.
+ *
+ * Clients typically use this class when opting for an alternative compiler
+ * like Javac to compile Java files.
+ *
+ * @since 3.38
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public record CompilerConfiguration(
+ /**
+ * List of file paths where the compiler can find source files.
+ */
+ List sourcepaths,
+ /**
+ * List of file paths where the compiler can find source files for modules.
+ */
+ List moduleSourcepaths,
+ /**
+ * List of file paths where the compiler can find user class files and annotation processors.
+ */
+ List classpaths,
+ /**
+ * List of file paths where the compiler can find modules.
+ */
+ List modulepaths,
+ /**
+ * Location to search for annotation processors.
+ */
+ List annotationProcessorPaths,
+ /**
+ * Locations to place generated source files.
+ */
+ List generatedSourcePaths,
+ /**
+ * The mapping of source files to output directories.
+ */
+ Map sourceOutputMapping,
+ /**
+ * The compiler options used to control the compilation behavior.
+ * See {@link org.eclipse.jdt.internal.compiler.impl.CompilerOptions} for a list of available options.
+ */
+ Map compilerOptions) {
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DefaultCompilerFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DefaultCompilerFactory.java
new file mode 100644
index 00000000000..4f32dea736d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DefaultCompilerFactory.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+* Copyright (c) 2024 Microsoft Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License 2.0
+* which accompanies this distribution, and is available at
+* https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Microsoft Corporation - initial API and implementation
+*******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler;
+
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+
+public class DefaultCompilerFactory implements ICompilerFactory {
+
+ @Override
+ public Compiler newCompiler(INameEnvironment environment, IErrorHandlingPolicy policy,
+ CompilerConfiguration compilerConfig, ICompilerRequestor requestor, IProblemFactory problemFactory) {
+ return new Compiler(environment, policy, new CompilerOptions(compilerConfig.compilerOptions()),
+ requestor, problemFactory);
+ }
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ICompilerFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ICompilerFactory.java
new file mode 100644
index 00000000000..96ad2a9e281
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ICompilerFactory.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+* Copyright (c) 2024 Microsoft Corporation and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License 2.0
+* which accompanies this distribution, and is available at
+* https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Microsoft Corporation - initial API and implementation
+*******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler;
+
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+
+/**
+ * A factory used to produce a compiler to compile the Java files.
+ */
+public interface ICompilerFactory {
+
+ /**
+ * Create a new compiler using the given name environment and compiler options.
+ *
+ * @param environment - the type system environment used for resolving types and packages
+ * @param policy - the error handling policy
+ * @param compilerConfig - the configuration to control the compiler behavior
+ * @param requestor - the requestor to receive and persist compilation results
+ * @param problemFactory - the factory to create problem descriptors
+ * @return the new compiler instance
+ */
+ public Compiler newCompiler(final INameEnvironment environment,
+ final IErrorHandlingPolicy policy,
+ final CompilerConfiguration compilerConfig,
+ final ICompilerRequestor requestor,
+ final IProblemFactory problemFactory);
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
index 09c66ece56f..bc6703ca78b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
@@ -23,7 +23,6 @@
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
@@ -64,7 +63,6 @@ public abstract class AbstractImageBuilder implements ICompilerRequestor, ICompi
protected boolean compiledAllAtOnce;
private boolean inCompiler;
-private boolean useDefaultCompiler = true;
protected boolean keepStoringProblemMarkers;
protected Map filesWithAnnotations = null;
@@ -88,6 +86,7 @@ public abstract class AbstractImageBuilder implements ICompilerRequestor, ICompi
public final static Integer P_HIGH = Integer.valueOf(IMarker.PRIORITY_HIGH);
public final static Integer P_NORMAL = Integer.valueOf(IMarker.PRIORITY_NORMAL);
public final static Integer P_LOW = Integer.valueOf(IMarker.PRIORITY_LOW);
+public final static String COMPILER_FACTORY_KEY = "AbstractImageBuilder.compilerFactory"; //$NON-NLS-1$
private final CompilationGroup compilationGroup;
protected AbstractImageBuilder(JavaBuilder javaBuilder, boolean buildStarting, State newState, CompilationGroup compilationGroup) {
@@ -576,39 +575,34 @@ protected Compiler newCompiler() {
CompilerOptions compilerOptions = new CompilerOptions(projectOptions);
compilerOptions.performMethodsFullRecovery = true;
compilerOptions.performStatementsRecovery = true;
- Compiler newCompiler = null;
- String compilerClassName = System.getProperty(AbstractImageBuilder.class.getSimpleName() + ".compiler"); //$NON-NLS-1$
- if (compilerClassName != null) {
+
+ ICompilerFactory compilerFactory = null;
+ String compilerFactoryClassName = System.getProperty(COMPILER_FACTORY_KEY);
+ if (compilerFactoryClassName != null) {
try {
- Class extends Compiler> compilerClass = (Class extends Compiler>) Class.forName(compilerClassName);
- Constructor extends Compiler> constructor = compilerClass.getDeclaredConstructor(
- INameEnvironment.class,
- IErrorHandlingPolicy.class,
- CompilerConfiguration.class,
- ICompilerRequestor.class,
- IProblemFactory.class);
- newCompiler = constructor.newInstance(this.nameEnvironment,
- DefaultErrorHandlingPolicies.proceedWithAllProblems(),
- prepareCompilerConfiguration(compilerOptions),
- this,
- ProblemFactory.getProblemFactory(Locale.getDefault()));
- this.useDefaultCompiler = false;
+ Class extends ICompilerFactory> compilerFactoryClass = (Class extends ICompilerFactory>) Class.forName(compilerFactoryClassName);
+ Constructor extends ICompilerFactory> constructor = compilerFactoryClass.getDeclaredConstructor();
+ compilerFactory = constructor.newInstance();
} catch (ClassNotFoundException e) {
- ILog.get().error("Could not load class " + compilerClassName, e); //$NON-NLS-1$
+ ILog.get().error("Could not load class " + compilerFactoryClassName, e); //$NON-NLS-1$
} catch (NoSuchMethodException e) {
- ILog.get().error("Couldn't find compatible constructor " + compilerClassName); //$NON-NLS-1$
+ ILog.get().error("Couldn't find compatible constructor " + compilerFactoryClassName); //$NON-NLS-1$
} catch (IllegalAccessException | IllegalArgumentException | InstantiationException | InvocationTargetException e) {
- ILog.get().error("Failed invoking constructor " + compilerClassName); //$NON-NLS-1$
+ ILog.get().error("Failed invoking constructor " + compilerFactoryClassName); //$NON-NLS-1$
}
}
- if (newCompiler == null) {
- newCompiler = new Compiler(
+
+ if (compilerFactory == null) {
+ compilerFactory = new DefaultCompilerFactory();
+ }
+
+ Compiler newCompiler = compilerFactory.newCompiler(
this.nameEnvironment,
DefaultErrorHandlingPolicies.proceedWithAllProblems(),
- compilerOptions,
+ prepareCompilerConfiguration(compilerOptions),
this,
ProblemFactory.getProblemFactory(Locale.getDefault()));
- }
+
CompilerOptions options = newCompiler.options;
// temporary code to allow the compiler to revert to a single thread
String setting = System.getProperty("jdt.compiler.useSingleThread"); //$NON-NLS-1$
@@ -627,69 +621,90 @@ protected Compiler newCompiler() {
}
private CompilerConfiguration prepareCompilerConfiguration(CompilerOptions options) {
- CompilerConfiguration configuration = new CompilerConfiguration();
- configuration.setOptions(options);
- List annotationProcessorPaths = new ArrayList<>();
- List generatedSourcePaths = new ArrayList<>();
- boolean isTest = this.compilationGroup == CompilationGroup.TEST;
- if (this.javaBuilder.participants != null) {
- for (CompilationParticipant participant : this.javaBuilder.participants) {
- if (participant.isAnnotationProcessor()) {
- String[] paths = participant.getAnnotationProcessorPaths(this.javaBuilder.javaProject, isTest);
- if (paths != null) {
- annotationProcessorPaths.addAll(Arrays.asList(paths));
+ try {
+ List annotationProcessorPaths = new ArrayList<>();
+ List generatedSourcePaths = new ArrayList<>();
+ boolean isTest = this.compilationGroup == CompilationGroup.TEST;
+ if (this.javaBuilder.participants != null) {
+ for (CompilationParticipant participant : this.javaBuilder.participants) {
+ if (participant.isAnnotationProcessor()) {
+ String[] paths = participant.getAnnotationProcessorPaths(this.javaBuilder.javaProject, isTest);
+ if (paths != null) {
+ annotationProcessorPaths.addAll(Arrays.asList(paths));
+ }
+ String[] generatedSrc = participant.getGeneratedSourcePaths(this.javaBuilder.javaProject, isTest);
+ if (generatedSrc != null) {
+ generatedSourcePaths.addAll(Arrays.asList(generatedSrc));
+ }
+ }
+ }
+ }
+
+ ClasspathLocation[] classpathLocations = this.nameEnvironment.binaryLocations;
+ Set classpaths = new LinkedHashSet<>();
+ Set modulepaths = new LinkedHashSet<>();
+ for (ClasspathLocation location : classpathLocations) {
+ if (location instanceof ClasspathDirectory cpDirectory) {
+ IPath binaryLocation = cpDirectory.binaryFolder.getLocation();
+ if (binaryLocation == null) {
+ continue;
}
- String[] generatedSrc = participant.getGeneratedSourcePaths(this.javaBuilder.javaProject, isTest);
- if (generatedSrc != null) {
- generatedSourcePaths.addAll(Arrays.asList(generatedSrc));
+
+ String filepath = binaryLocation.toFile().getAbsolutePath();
+ if (cpDirectory.isOnModulePath) {
+ modulepaths.add(filepath);
+ } else {
+ classpaths.add(filepath);
+ }
+ } else if (location instanceof ClasspathJar cpJar) {
+ String filepath = cpJar.zipFilename;
+ if (cpJar.isOnModulePath) {
+ modulepaths.add(filepath);
+ } else {
+ classpaths.add(filepath);
}
}
}
- }
- configuration.setAnnotationProcessorPaths(annotationProcessorPaths);
- configuration.setGeneratedSourcePaths(generatedSourcePaths);
- ClasspathLocation[] classpathLocations = this.nameEnvironment.binaryLocations;
- List classpaths = new ArrayList<>();
- List modulepaths = new ArrayList<>();
- for (ClasspathLocation location : classpathLocations) {
- if (location instanceof ClasspathDirectory cpDirectory) {
- String filepath = cpDirectory.binaryFolder.getLocation().toFile().getAbsolutePath();
- if (cpDirectory.isOnModulePath && !modulepaths.contains(filepath)) {
- modulepaths.add(filepath);
- } else if (!cpDirectory.isOnModulePath && !classpaths.contains(filepath)) {
- classpaths.add(filepath);
+
+ Map sourceOutputMapping = new HashMap<>();
+ Set sourcepaths = new LinkedHashSet<>();
+ Set moduleSourcepaths = new LinkedHashSet<>();
+ ClasspathMultiDirectory[] srcLocations = this.nameEnvironment.sourceLocations;
+ for (ClasspathMultiDirectory sourceLocation : srcLocations) {
+ IPath sourcepath = sourceLocation.sourceFolder.getLocation();
+ if (sourcepath == null) {
+ continue;
}
- } else if (location instanceof ClasspathJar cpJar) {
- String filepath = cpJar.zipFilename;
- if (cpJar.isOnModulePath && !modulepaths.contains(filepath)) {
- modulepaths.add(filepath);
- } else if (!cpJar.isOnModulePath && !classpaths.contains(filepath)) {
- classpaths.add(filepath);
+
+ File sourceFolder = sourcepath.toFile();
+ IPath binarypath = sourceLocation.binaryFolder.getLocation();
+ if (binarypath != null) {
+ File outputFolder = binarypath.toFile();
+ sourceOutputMapping.put(sourceFolder, outputFolder);
+ }
+
+ String absoluteSourcepath = sourceFolder.getAbsolutePath();
+ if (sourceLocation.isOnModulePath) {
+ moduleSourcepaths.add(absoluteSourcepath);
+ } else {
+ sourcepaths.add(absoluteSourcepath);
}
}
+
+ return new CompilerConfiguration(
+ new ArrayList<>(sourcepaths),
+ new ArrayList<>(moduleSourcepaths),
+ new ArrayList<>(classpaths),
+ new ArrayList<>(modulepaths),
+ annotationProcessorPaths,
+ generatedSourcePaths,
+ sourceOutputMapping,
+ options.getMap());
+ } catch (Exception e) {
+ ILog.get().error("Failed computing compiler configuration " + e); //$NON-NLS-1$
+ return new CompilerConfiguration(
+ null, null, null, null, null, null, null, options.getMap());
}
- configuration.setClasspaths(classpaths);
- configuration.setModulepaths(modulepaths);
-
- Map sourceOutputMapping = new HashMap<>();
- List sourcepaths = new ArrayList<>();
- List moduleSourcepaths = new ArrayList<>();
- ClasspathMultiDirectory[] srcLocations = this.nameEnvironment.sourceLocations;
- for (ClasspathMultiDirectory sourceLocation : srcLocations) {
- File sourceFolder = sourceLocation.sourceFolder.getLocation().toFile();
- File outputFolder = sourceLocation.binaryFolder.getLocation().toFile();
- sourceOutputMapping.put(sourceFolder, outputFolder);
- String sourcepath = sourceFolder.getAbsolutePath();
- if (sourceLocation.isOnModulePath && !moduleSourcepaths.contains(sourcepath)) {
- moduleSourcepaths.add(sourcepath);
- } else if (!sourceLocation.isOnModulePath && !sourcepaths.contains(sourcepath)) {
- sourcepaths.add(sourcepath);
- }
- }
- configuration.setSourceOutputMapping(sourceOutputMapping);
- configuration.setSourcepaths(sourcepaths);
- configuration.setModuleSourcepaths(moduleSourcepaths);
- return configuration;
}
protected CompilationParticipantResult[] notifyParticipants(SourceFile[] unitsAboutToCompile) {
@@ -762,9 +777,10 @@ protected void processAnnotations(CompilationParticipantResult[] results) {
results[i].reset(foundAnnotations ? this.filesWithAnnotations.get(results[i].sourceFile) : null);
}
+ boolean isEcjUsed = Compiler.class.equals(this.compiler.getClass());
// even if no files have annotations, must still tell every annotation processor in case the file used to have them
for (CompilationParticipant participant : this.javaBuilder.participants)
- if (this.useDefaultCompiler && participant.isAnnotationProcessor())
+ if (isEcjUsed && participant.isAnnotationProcessor())
participant.processAnnotations(results);
processAnnotationResults(results);
}