diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
index 0a247a25dd1..2c6102d1a8c 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
@@ -33,7 +33,6 @@
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
@@ -221,6 +220,8 @@ public static ASTParser newParser(int level) {
*/
private int bits;
+ private final ICompilationUnitResolver unitResolver;
+
/**
* Creates a new AST parser for the given API level.
*
@@ -233,6 +234,7 @@ public static ASTParser newParser(int level) {
ASTParser(int level) {
DOMASTUtil.checkASTLevel(level);
this.apiLevel = level;
+ this.unitResolver = CompilationUnitResolverDiscovery.getInstance();
initializeDefaults();
}
@@ -245,10 +247,13 @@ private List getClasspath() throws IllegalStateException {
}
if (this.sourcepaths != null) {
for (int i = 0, max = this.sourcepaths.length; i < max; i++) {
- String encoding = this.sourcepathsEncodings == null ? null : this.sourcepathsEncodings[i];
- main.processPathEntries(
- Main.DEFAULT_SIZE_CLASSPATH,
- allClasspaths, this.sourcepaths[i], encoding, true, false);
+ String sourcePath = this.sourcepaths[i];
+ if (sourcePath != null) {
+ String encoding = this.sourcepathsEncodings == null ? null : this.sourcepathsEncodings[i];
+ main.processPathEntries(
+ Main.DEFAULT_SIZE_CLASSPATH,
+ allClasspaths, sourcePath, encoding, true, false);
+ }
}
}
if (this.classpaths != null) {
@@ -957,9 +962,9 @@ public void createASTs(ICompilationUnit[] compilationUnits, String[] bindingKeys
if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) {
flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
}
- CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor);
+ this.unitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor);
} else {
- CompilationUnitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, flags, monitor);
+ this.unitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, flags, monitor);
}
} finally {
// reset to defaults to allow reuse (and avoid leaking)
@@ -1052,9 +1057,9 @@ public void createASTs(String[] sourceFilePaths, String[] encodings, String[] bi
if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) {
flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
}
- CompilationUnitResolver.resolve(sourceFilePaths, encodings, bindingKeys, requestor, this.apiLevel, this.compilerOptions, getClasspath(), flags, monitor);
+ this.unitResolver.resolve(sourceFilePaths, encodings, bindingKeys, requestor, this.apiLevel, this.compilerOptions, getClasspath(), flags, monitor);
} else {
- CompilationUnitResolver.parse(sourceFilePaths, encodings, requestor, this.apiLevel, this.compilerOptions, flags, monitor);
+ this.unitResolver.parse(sourceFilePaths, encodings, requestor, this.apiLevel, this.compilerOptions, flags, monitor);
}
} finally {
// reset to defaults to allow reuse (and avoid leaking)
@@ -1159,9 +1164,8 @@ private ASTNode internalCreateASTCached(IProgressMonitor monitor) {
}
break;
case K_COMPILATION_UNIT :
- CompilationUnitDeclaration compilationUnitDeclaration = null;
try {
- NodeSearcher searcher = null;
+ boolean useSearcher = false;
org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = null;
WorkingCopyOwner wcOwner = this.workingCopyOwner;
if (this.typeRoot instanceof ClassFileWorkingCopy) {
@@ -1229,68 +1233,28 @@ private ASTNode internalCreateASTCached(IProgressMonitor monitor) {
throw new IllegalStateException();
}
if ((this.bits & CompilationUnitResolver.PARTIAL) != 0) {
- searcher = new NodeSearcher(this.focalPointPosition);
+ useSearcher = true;
}
int flags = 0;
if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) {
flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
}
- if (searcher == null && ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0)) {
+ if (!useSearcher && ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0)) {
flags |= ICompilationUnit.IGNORE_METHOD_BODIES;
}
+
if (needToResolveBindings) {
if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) {
flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
}
- try {
- // parse and resolve
- compilationUnitDeclaration =
- CompilationUnitResolver.resolve(
- sourceUnit,
- this.project,
- getClasspath(),
- searcher,
- this.compilerOptions,
- this.workingCopyOwner,
- flags,
- monitor);
- } catch (JavaModelException e) {
- flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
- compilationUnitDeclaration = CompilationUnitResolver.parse(
- sourceUnit,
- searcher,
- this.compilerOptions,
- flags);
- needToResolveBindings = false;
- }
- } else {
- compilationUnitDeclaration = CompilationUnitResolver.parse(
- sourceUnit,
- searcher,
- this.compilerOptions,
- flags,
- this.project);
- needToResolveBindings = false;
}
- CompilationUnit result = CompilationUnitResolver.convert(
- compilationUnitDeclaration,
- sourceUnit.getContents(),
- this.apiLevel,
- this.compilerOptions,
- needToResolveBindings,
- wcOwner,
- needToResolveBindings ? new DefaultBindingResolver.BindingTables() : null,
- flags,
- monitor,
- this.project != null,
- this.project);
- result.setTypeRoot(this.typeRoot);
- return result;
+
+ CompilationUnit result2 = this.unitResolver.toCompilationUnit(sourceUnit, needToResolveBindings, this.project, getClasspath(), useSearcher ? this.focalPointPosition : -1, this.apiLevel, this.compilerOptions, this.workingCopyOwner, wcOwner, flags, monitor);
+ result2.setTypeRoot(this.typeRoot);
+ return result2;
} finally {
- if (compilationUnitDeclaration != null
- && ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0)) {
- compilationUnitDeclaration.cleanUp();
- }
+ // unitResolver should already handle this.
+ // Leaving this finally in place to avoid changing indentation
}
}
throw new IllegalStateException();
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index 1988de8c26b..dcca57b177e 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -82,6 +82,45 @@
@SuppressWarnings({ "rawtypes", "unchecked" })
class CompilationUnitResolver extends Compiler {
+
+ private static final class ECJCompilationUnitResolver implements ICompilationUnitResolver {
+
+ @Override
+ public void resolve(String[] sourceFilePaths, String[] encodings, String[] bindingKeys,
+ FileASTRequestor requestor, int apiLevel, Map compilerOptions, List classpath,
+ int flags, IProgressMonitor monitor) {
+ CompilationUnitResolver.resolve(sourceFilePaths, encodings, bindingKeys, requestor, apiLevel, compilerOptions, classpath, flags, monitor);
+ }
+
+ @Override
+ public void parse(ICompilationUnit[] compilationUnits, ASTRequestor requestor, int apiLevel,
+ Map compilerOptions, int flags, IProgressMonitor monitor) {
+ CompilationUnitResolver.parse(compilationUnits, requestor, apiLevel, compilerOptions, flags, monitor);
+ }
+
+ @Override
+ public void parse(String[] sourceFilePaths, String[] encodings, FileASTRequestor requestor, int apiLevel,
+ Map compilerOptions, int flags, IProgressMonitor monitor) {
+ CompilationUnitResolver.parse(sourceFilePaths, encodings, requestor, apiLevel, compilerOptions, flags, monitor);
+ }
+
+ @Override
+ public void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor,
+ int apiLevel, Map compilerOptions, IJavaProject project,
+ WorkingCopyOwner workingCopyOwner, int flags, IProgressMonitor monitor) {
+ CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, compilerOptions, project, workingCopyOwner, flags, monitor);
+ }
+
+ @Override
+ public CompilationUnit toCompilationUnit(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, final boolean initialNeedsToResolveBinding, IJavaProject project, List classpaths, int focalPosition,
+ int apiLevel, Map compilerOptions, WorkingCopyOwner parsedUnitWorkingCopyOwner, WorkingCopyOwner typeRootWorkingCopyOwner, int flags, IProgressMonitor monitor) {
+ return CompilationUnitResolver.toCompilationUnit(sourceUnit, initialNeedsToResolveBinding, project,
+ classpaths, focalPosition == -1 ? null : new NodeSearcher(focalPosition), apiLevel, compilerOptions, parsedUnitWorkingCopyOwner, typeRootWorkingCopyOwner, flags, monitor);
+ }
+ }
+
+ public static final ECJCompilationUnitResolver FACADE = new ECJCompilationUnitResolver();
+
public static final int RESOLVE_BINDING = 0x1;
public static final int PARTIAL = 0x2;
public static final int STATEMENT_RECOVERY = 0x4;
@@ -1408,6 +1447,62 @@ public CompilationUnitDeclaration resolve(
generateCode);
}
+ public static CompilationUnit toCompilationUnit(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, final boolean initialNeedsToResolveBinding, IJavaProject project, List classpaths, NodeSearcher nodeSearcher,
+ int apiLevel, Map compilerOptions, WorkingCopyOwner parsedUnitWorkingCopyOwner, WorkingCopyOwner typeRootWorkingCopyOwner, int flags, IProgressMonitor monitor) {
+ // this -> astParser, pass as args
+ CompilationUnitDeclaration compilationUnitDeclaration = null;
+ boolean needsToResolveBindingsState = initialNeedsToResolveBinding;
+ try {
+ if (initialNeedsToResolveBinding) {
+ try {
+ // parse and resolve
+ compilationUnitDeclaration =
+ CompilationUnitResolver.resolve(
+ sourceUnit,
+ project,
+ classpaths,
+ nodeSearcher,
+ compilerOptions,
+ parsedUnitWorkingCopyOwner,
+ flags,
+ monitor);
+ } catch (JavaModelException e) {
+ flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
+ compilationUnitDeclaration = CompilationUnitResolver.parse(
+ sourceUnit,
+ nodeSearcher,
+ compilerOptions,
+ flags);
+ needsToResolveBindingsState = false;
+ }
+ } else {
+ compilationUnitDeclaration = CompilationUnitResolver.parse(
+ sourceUnit,
+ nodeSearcher,
+ compilerOptions,
+ flags,
+ project);
+ needsToResolveBindingsState = false;
+ }
+ return CompilationUnitResolver.convert(
+ compilationUnitDeclaration,
+ sourceUnit.getContents(),
+ apiLevel,
+ compilerOptions,
+ needsToResolveBindingsState,
+ typeRootWorkingCopyOwner,
+ needsToResolveBindingsState ? new DefaultBindingResolver.BindingTables() : null,
+ flags,
+ monitor,
+ project != null,
+ project);
+ } finally {
+ if (compilationUnitDeclaration != null && initialNeedsToResolveBinding) {
+ compilationUnitDeclaration.cleanUp();
+ }
+ }
+ }
+
private void worked(int work) {
if (this.monitor != null) {
if (this.monitor.isCanceled())
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolverDiscovery.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolverDiscovery.java
new file mode 100644
index 00000000000..8038b0c0d87
--- /dev/null
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolverDiscovery.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Red Hat, Inc. and others.
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.jdt.core.dom;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jdt.core.JavaCore;
+
+class CompilationUnitResolverDiscovery {
+ private static final String COMPILATION_UNIT_RESOLVER_EXTPOINT_ID = "compilationUnitResolver" ; //$NON-NLS-1$
+ private static boolean ERROR_LOGGED = false;
+
+
+ @SuppressWarnings("unchecked")
+ static ICompilationUnitResolver getInstance() {
+ String compilationUnitResolverId = System.getProperty(ICompilationUnitResolver.class.getSimpleName());
+ IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, COMPILATION_UNIT_RESOLVER_EXTPOINT_ID);
+ if (extension != null && compilationUnitResolverId != null && !compilationUnitResolverId.isEmpty()) {
+ IExtension[] extensions = extension.getExtensions();
+ for (IExtension ext : extensions) {
+ IConfigurationElement[] configElements = ext.getConfigurationElements();
+ for (final IConfigurationElement configElement : configElements) {
+ String elementId = configElement.getAttribute("id");
+ if( compilationUnitResolverId.equals(elementId)) {
+ String elementName =configElement.getName();
+ if (!("resolver".equals(elementName))) { //$NON-NLS-1$
+ continue;
+ }
+ try {
+ Object executableExtension = configElement.createExecutableExtension("class");
+ if( executableExtension instanceof ICompilationUnitResolver icur) {
+ return icur;
+ }
+ } catch (CoreException e) {
+ e.printStackTrace();
+ if( !ERROR_LOGGED) {
+ ILog.get().error("Could not instantiate ICompilationUnitResolver: '" + elementId + "' with class: " + configElement.getAttribute("class"), e); //$NON-NLS-1$
+ ERROR_LOGGED = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return CompilationUnitResolver.FACADE;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ICompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ICompilationUnitResolver.java
new file mode 100644
index 00000000000..39b1bf52433
--- /dev/null
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ICompilationUnitResolver.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc. and others.
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.jdt.core.dom;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
+
+/**
+ * @since 3.38
+ */
+public interface ICompilationUnitResolver {
+ void resolve(String[] sourceFilePaths, String[] encodings, String[] bindingKeys, FileASTRequestor requestor,
+ int apiLevel, Map compilerOptions, List list, int flags,
+ IProgressMonitor monitor);
+
+ void parse(ICompilationUnit[] compilationUnits, ASTRequestor requestor, int apiLevel,
+ Map compilerOptions, int flags, IProgressMonitor monitor);
+
+ void parse(String[] sourceFilePaths, String[] encodings, FileASTRequestor requestor, int apiLevel,
+ Map compilerOptions, int flags, IProgressMonitor monitor);
+
+ void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor, int apiLevel,
+ Map compilerOptions, IJavaProject project, WorkingCopyOwner workingCopyOwner, int flags,
+ IProgressMonitor monitor);
+
+ /**
+ *
+ * @param sourceUnit
+ * @param initialNeedsToResolveBinding
+ * @param project
+ * @param classpaths
+ * @param focalPosition a position to focus on, or -1 if N/A
+ * @param apiLevel
+ * @param compilerOptions
+ * @param parsedUnitWorkingCopyOwner
+ * @param typeRootWorkingCopyOwner
+ * @param flags
+ * @param monitor
+ * @return
+ */
+ CompilationUnit toCompilationUnit(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, final boolean initialNeedsToResolveBinding, IJavaProject project, List classpaths, int focalPosition,
+ int apiLevel, Map compilerOptions, WorkingCopyOwner parsedUnitWorkingCopyOwner, WorkingCopyOwner typeRootWorkingCopyOwner, int flags, IProgressMonitor monitor);
+}
diff --git a/org.eclipse.jdt.core/plugin.properties b/org.eclipse.jdt.core/plugin.properties
index 7611e97e290..f901126dae0 100644
--- a/org.eclipse.jdt.core/plugin.properties
+++ b/org.eclipse.jdt.core/plugin.properties
@@ -23,6 +23,7 @@ classpathVariableInitializersName=Classpath Variable Initializers
classpathContainerInitializersName=Classpath Container Initializers
codeFormattersName=Source Code Formatters
compilationParticipantsName=Compilation Participants
+compilationUnitResolverName=Compilation Unit Resolver
annotationProcessorManagerName=Java 6 Annotation Processor Manager
javaTaskName=Java Task
javaPropertiesName=Java Properties File
diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml
index 0569dff3f86..1a5c84cb82e 100644
--- a/org.eclipse.jdt.core/plugin.xml
+++ b/org.eclipse.jdt.core/plugin.xml
@@ -63,6 +63,14 @@
id="compilationParticipant"
schema="schema/compilationParticipant.exsd"/>
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core/schema/compilationUnitResolver.exsd b/org.eclipse.jdt.core/schema/compilationUnitResolver.exsd
new file mode 100644
index 00000000000..c2391cccebd
--- /dev/null
+++ b/org.eclipse.jdt.core/schema/compilationUnitResolver.exsd
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+ This extension point provides the ability to override the default behavior of converting source files into the JDT DOM tree. Only one extension will be used, and only when the system property `ICompilationUnitResolver` is set to the id of that extension. This extension point is not intended to be implemented by clients.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Definition of a compilation unit resolver.
+
+
+
+
+
+
+ The class that implements this compilation unit resolver. This class must implement the <code>org.eclipse.jdt.core.dom.ICompilationUnitResolver</code> interface with a public 0-arg constructor.
+
+
+
+
+
+
+
+
+
+ A unique identifier for this resolver.
+
+
+
+
+
+
+
+
+
+
+
+ 3.38
+
+
+
+
+
+
+
+
+ Example of a declaration of a <code>compilationUnitResolver</code>: <pre>
+<extension
+ point="org.eclipse.jdt.core.compilationParticipant">
+ <resolver
+ class="org.eclipse.jdt.core.CompilationUnitResolver1"
+ id="org.eclipse.jdt.core.MyCustomResolver">
+ </resolver>
+</extension>
+</pre>
+
+
+
+
+
+
+
+
+
+
+ Copyright (c) 2024 Red Hat, Inc. and others.<br>
+
+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
+<a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-v20.html</a>/
+
+SPDX-License-Identifier: EPL-2.0
+
+
+
+