From de490a08a82ecc63aa7e25ed4b13b5b7f75eeeb4 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Tue, 24 Dec 2024 18:01:02 +0100 Subject: [PATCH] [BUG] [JSR-199] ECJ cannot resolve JPMS modules if using a user-provided file manager + make ClasspathJsr199 capable of handling sources + consistently extract module and pass it into CUs and class readers + implement module extraction from JavaFileObject (src & class) + implement ClasspathJsr199.listPackages() using JavaFileObjects + detect initial / duplicate source files by JavaFileObject, not path + fix arg passing in ProblemReporter.invalidPackageReference() + implement package matching in InMemoryJavaFileManager.list() (test) TODO: + exception handling + encoding? (currently hardcodes UTF-8) Fixes https://github.com/eclipse-jdt/eclipse.jdt.core/issues/958 --- .../tool/tests/CompilerToolJava9Tests.java | 2 +- .../tool/tests/InMemoryCompilationTest.java | 13 +- .../compiler/apt/dispatch/BatchFilerImpl.java | 38 ++++- .../apt/dispatch/BatchProcessingEnvImpl.java | 4 +- .../apt/dispatch/HookedJavaFileObject.java | 22 ++- .../compiler/batch/ClasspathJsr199.java | 133 +++++++++++++++--- .../jdt/internal/compiler/batch/Main.java | 18 ++- .../internal/compiler/batch/ModuleFinder.java | 2 +- .../compiler/problem/ProblemReporter.java | 5 +- .../compiler/tool/EclipseCompiler.java | 36 ++--- .../compiler/tool/EclipseCompilerImpl.java | 66 +++++---- .../compiler/tool/EclipseFileManager.java | 3 +- 12 files changed, 251 insertions(+), 91 deletions(-) diff --git a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java index 945cb40ec70..6b9f04fcea3 100644 --- a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java +++ b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2021 IBM Corporation and others. + * Copyright (c) 2017, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 diff --git a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/InMemoryCompilationTest.java b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/InMemoryCompilationTest.java index 2c8d7407e29..bf27441f4a7 100644 --- a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/InMemoryCompilationTest.java +++ b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/InMemoryCompilationTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021 IBM Corporation and others. + * Copyright (c) 2021, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -191,7 +191,16 @@ public Iterable list(Location location, String packageName, Set< throws IOException { List result = new ArrayList<>(); if (location == StandardLocation.SOURCE_PATH && kinds.contains(Kind.SOURCE)) { - result.addAll(sources); + for (InMemoryJavaSourceFileObject sourceFileObject : sources) { + String name = sourceFileObject.getAbsClassName(); + int lastDot = name.lastIndexOf('.'); + if (lastDot == -1) + continue; + String packName = name.substring(0, lastDot-1); + boolean match = recurse ? packName.startsWith(packageName) : packName.equals(packageName); + if (match) + result.add(sourceFileObject); + } } if (super.hasLocation(location)) { Iterable superResult = super.list(location, packageName, kinds, recurse); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java index ad4924a85b2..05c95235574 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2018 BEA Systems, Inc. + * Copyright (c) 2006, 2024 BEA Systems, Inc. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -19,6 +19,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; +import java.util.Collections; import java.util.HashSet; import javax.annotation.processing.Filer; import javax.annotation.processing.FilerException; @@ -28,8 +29,12 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; import javax.tools.StandardLocation; +import org.eclipse.jdt.internal.compiler.batch.ClasspathJsr199; +import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; /** @@ -43,13 +48,30 @@ public class BatchFilerImpl implements Filer { protected final BatchProcessingEnvImpl _env; protected final JavaFileManager _fileManager; protected final HashSet _createdFiles; + protected String _moduleName; - public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env) + public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env, Main main) { this._dispatchManager = dispatchManager; this._fileManager = env._fileManager; this._env = env; this._createdFiles = new HashSet<>(); + if (this._fileManager.hasLocation(StandardLocation.SOURCE_PATH)) { + try { + for (JavaFileObject javaFileObject : this._fileManager.list(StandardLocation.SOURCE_PATH, "", //$NON-NLS-1$ + Collections.singleton(Kind.SOURCE), false)) { + if (javaFileObject.getName().equals(IModule.MODULE_INFO_JAVA)) { + IModule module = ClasspathJsr199.extractModuleFromFileObject(javaFileObject, main::getNewParser, null); + if (module != null) + this._moduleName = String.valueOf(module.name()); + break; + } + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } } public void addNewUnit(ICompilationUnit unit) { @@ -74,7 +96,7 @@ public JavaFileObject createClassFile(CharSequence name, } this._createdFiles.add(uri); - return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this); + return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this, this._moduleName); } /* (non-Javadoc) @@ -146,7 +168,13 @@ public JavaFileObject createSourceFile(CharSequence name, if (typeElement != null) { throw new FilerException("Source file already exists : " + moduleAndPkgString); //$NON-NLS-1$ } - Location location = mod == null ? StandardLocation.SOURCE_OUTPUT : this._fileManager.getLocationForModule(StandardLocation.SOURCE_OUTPUT, mod); + Location location; + if (mod == null) { + location = StandardLocation.SOURCE_OUTPUT; + mod = this._moduleName; + } else { + location = this._fileManager.getLocationForModule(StandardLocation.SOURCE_OUTPUT, mod); + } JavaFileObject jfo = this._fileManager.getJavaFileForOutput(location, name.toString(), JavaFileObject.Kind.SOURCE, null); URI uri = jfo.toUri(); if (this._createdFiles.contains(uri)) { @@ -155,7 +183,7 @@ public JavaFileObject createSourceFile(CharSequence name, this._createdFiles.add(uri); // hook the file object's writers to create compilation unit and add to addedUnits() - return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this); + return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this, mod); } /* (non-Javadoc) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java index df97cb6e407..b0f56b9ce37 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. + * Copyright (c) 2006, 2024 BEA Systems, Inc. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -89,7 +89,7 @@ public BatchProcessingEnvImpl(BaseAnnotationProcessorManager dispatchManager, Ma this._fileManager = manager; } this._processorOptions = Collections.unmodifiableMap(parseProcessorOptions(commandLineArguments)); - this._filer = new BatchFilerImpl(this._dispatchManager, this); + this._filer = new BatchFilerImpl(this._dispatchManager, this, this._compilerOwner); this._messager = new BatchMessagerImpl(this, this._compilerOwner); } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java index d55d8d39cd6..d7f3276a83e 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. and others + * Copyright (c) 2006, 2024 BEA Systems, Inc. and others * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -200,11 +200,14 @@ public String toString() { private final String _typeName; - public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer) { + private final String _moduleName; + + public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer, String module) { super(fileObject); this._filer = filer; this._fileName = fileName; this._typeName = typeName; + this._moduleName = module; } @SuppressWarnings("resource") // ForwardingOutputStream forwards close() too @@ -225,8 +228,19 @@ protected void closed() { //TODO: support encoding switch(this.getKind()) { case SOURCE : - CompilationUnit unit = new CompilationUnit(null, this._fileName, null /* encoding */, null, this._filer._env.shouldIgnoreOptionalProblems(this._fileName.toCharArray()), null); - this._filer.addNewUnit(unit); + try { + CompilationUnit unit = new CompilationUnit( + getCharContent(false).toString().toCharArray(), + this._fileName, + null /* encoding */, + null /* destination path */, + this._filer._env.shouldIgnoreOptionalProblems(this._fileName.toCharArray()), + this._moduleName); + this._filer.addNewUnit(unit); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } break; case CLASS : IBinaryType binaryType = null; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java index 29380861496..4ee0ac4967c 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2018 IBM Corporation and others. + * Copyright (c) 2015, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -26,48 +26,68 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardLocation; import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.tool.ModuleLocationHandler.LocationWrapper; +import org.eclipse.jdt.internal.compiler.util.JRTUtil; @SuppressWarnings({ "rawtypes", "unchecked" }) public class ClasspathJsr199 extends ClasspathLocation { - private static final Set fileTypes = new HashSet<>(); - static { - fileTypes.add(JavaFileObject.Kind.CLASS); - } + public static final String ENCODING_UTF_8 = "UTF-8"; //$NON-NLS-1$ + private final static String NO_PATH = ""; //$NON-NLS-1$ + private final Set fileTypes; private final JavaFileManager fileManager; private final JavaFileManager.Location location; private Classpath jrt; + private Supplier parserSupplier; + + /** + * FileSystem.internalFindClass() detects request for initial files by filename, + * which is not suitable for JavaFileObjects with custom URI format. + * Thus we need to compare JavaFileObjects, too. + */ + private Set initialJavaFileObjects; public ClasspathJsr199(JavaFileManager file, JavaFileManager.Location location) { super(null, null); this.fileManager = file; this.location = location; + this.fileTypes = location == StandardLocation.SOURCE_PATH + ? Collections.singleton(JavaFileObject.Kind.SOURCE) + : Collections.singleton(JavaFileObject.Kind.CLASS); } public ClasspathJsr199(Classpath jrt, JavaFileManager file, JavaFileManager.Location location) { - super(null, null); - this.fileManager = file; + this(file, location); this.jrt = jrt; - this.location = location; } /* * Maintain two separate constructors to avoid this being constructed with any other kind of classpath * (other than ClasspathJrt and ClasspathJep249 */ public ClasspathJsr199(ClasspathJep247 older, JavaFileManager file, JavaFileManager.Location location) { - super(null, null); - this.fileManager = file; + this(file, location); this.jrt = older; - this.location = location; + } + + /** Constructor for mapping SOURCE_PATH to ClasspathLocation. */ + public ClasspathJsr199(JavaFileManager fileManager, JavaFileManager.Location location, Set initialJavaFileObjects, Supplier parserSupplier) { + this(fileManager, location); + this.initialJavaFileObjects = initialJavaFileObjects; + this.parserSupplier = parserSupplier; } @Override @@ -91,7 +111,7 @@ public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageN String className = lastDot < 0 ? qualifiedBinaryFileName : qualifiedBinaryFileName.substring(0, lastDot); JavaFileObject jfo = null; try { - jfo = this.fileManager.getJavaFileForInput(this.location, className, JavaFileObject.Kind.CLASS); + jfo = this.fileManager.getJavaFileForInput(this.location, className, this.fileTypes.iterator().next()); } catch (IOException e) { // treat as if class file is missing } @@ -99,12 +119,18 @@ public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageN if (jfo == null) return null; // most common case - try (InputStream inputStream = jfo.openInputStream()) { - ClassFileReader reader = ClassFileReader.read(inputStream.readAllBytes(), qualifiedBinaryFileName); + char[] answerModule = this.module != null ? this.module.name() : null; + if (jfo.getKind() == Kind.CLASS) { + ClassFileReader reader = readJavaClass(jfo, qualifiedBinaryFileName); if (reader != null) { - char[] answerModule = this.module != null ? this.module.name() : null; return new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), answerModule); } + } else { + if (this.initialJavaFileObjects != null && this.initialJavaFileObjects.contains(jfo)) + return null; // refuse to re-add an initial file (possibly via a wrong module?) + CompilationUnit cu = readCompilationUnit(jfo); + cu.module = answerModule; + return new NameEnvironmentAnswer(cu, fetchAccessRestriction(qualifiedBinaryFileName), answerModule); } } catch (ClassFormatException e) { // treat as if class file is missing @@ -124,7 +150,7 @@ public char[][][] findTypeNames(String aQualifiedPackageName, String moduleName) Iterable files = null; try { - files = this.fileManager.list(this.location, qualifiedPackageName, fileTypes, false); + files = this.fileManager.list(this.location, qualifiedPackageName, this.fileTypes, false); } catch (IOException e) { // treat as if empty } @@ -166,6 +192,22 @@ public void initialize() throws IOException { if (mod != null) return; } + } else { + if (this.location == StandardLocation.SOURCE_PATH) { + for (JavaFileObject javaFileObject : this.fileManager.list(this.location, NO_PATH, Collections.singleton(JavaFileObject.Kind.SOURCE), false)) { + if (javaFileObject.getName().equals(IModule.MODULE_INFO_JAVA)) { + this.module = ClasspathJsr199.extractModuleFromFileObject(javaFileObject, this.parserSupplier, this); + return; + } + } + } else { + for (JavaFileObject javaFileObject : this.fileManager.list(this.location, NO_PATH, Collections.singleton(JavaFileObject.Kind.CLASS), false)) { + if (javaFileObject.getName().equals(IModule.MODULE_INFO_CLASS)) { + this.module = ClasspathJsr199.extractModuleFromFileObject(javaFileObject, null, this); + return; + } + } + } } } @@ -186,7 +228,7 @@ public char[][] getModulesDeclaringPackage(String aQualifiedPackageName, String boolean result = false; try { - Iterable files = this.fileManager.list(this.location, qualifiedPackageName, fileTypes, false); + Iterable files = this.fileManager.list(this.location, qualifiedPackageName, this.fileTypes, false); Iterator f = files.iterator(); // if there is any content, assume a package if (f.hasNext()) { @@ -194,7 +236,7 @@ public char[][] getModulesDeclaringPackage(String aQualifiedPackageName, String } else { // I hate to do this since it is expensive and will throw off garbage // but can't think of an alternative now - files = this.fileManager.list(this.location, qualifiedPackageName, fileTypes, true); + files = this.fileManager.list(this.location, qualifiedPackageName, this.fileTypes, true); f = files.iterator(); // if there is any content, assume a package if (f.hasNext()) { @@ -211,7 +253,7 @@ public char[][] getModulesDeclaringPackage(String aQualifiedPackageName, String public char[][] listPackages() { Set packageNames = new HashSet<>(); try { - for (JavaFileObject fileObject : this.fileManager.list(this.location, "", fileTypes, true)) { //$NON-NLS-1$ + for (JavaFileObject fileObject : this.fileManager.list(this.location, NO_PATH, this.fileTypes, true)) { String name = fileObject.getName(); int lastSlash = name.lastIndexOf('/'); if (lastSlash != -1) { @@ -318,4 +360,57 @@ public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageN // return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); } + + public static ClassFileReader readJavaClass(JavaFileObject jfo, String name) throws ClassFormatException, IOException { + try (InputStream inputStream = jfo.openInputStream()) { + return ClassFileReader.read(inputStream.readAllBytes(), name); + } + } + + public static CompilationUnit readCompilationUnit(JavaFileObject jfo) throws IOException { + return new CompilationUnit(jfo.getCharContent(false).toString().toCharArray(), jfo.getName(), ENCODING_UTF_8); + } + + public static IModule extractModuleFromFileObject(JavaFileObject javaFileObject, Supplier parserSupplier, Classpath pathEntry) { + try { + switch (javaFileObject.getKind()) { + case SOURCE: + return extractModuleFromSource(javaFileObject, parserSupplier.get(), pathEntry); + case CLASS: + return extractModuleFromClass(javaFileObject, pathEntry); + default: + throw new IllegalArgumentException("Unexpected kind "+javaFileObject.getKind()); //$NON-NLS-1$ + } + } catch (IOException e) { + String error = "Failed to read module from " + pathEntry; //$NON-NLS-1$ + if (JRTUtil.PROPAGATE_IO_ERRORS) { + throw new IllegalStateException(error, e); + } else { + System.err.println(error); + e.printStackTrace(); + } + } catch (ClassFormatException e) { + e.printStackTrace(); + } + return null; + } + static IModule extractModuleFromSource(JavaFileObject javaFileObject, Parser parser, Classpath pathEntry) throws IOException { + CompilationUnit cu = readCompilationUnit(javaFileObject); + CompilationResult compilationResult = new CompilationResult(cu, 0, 1, 10); + CompilationUnitDeclaration unit = parser.parse(cu, compilationResult); + if (unit.isModuleInfo() && unit.moduleDeclaration != null) { + cu.module = unit.moduleDeclaration.moduleName; + return new BasicModule(unit.moduleDeclaration, pathEntry); + } + return null; + } + static IModule extractModuleFromClass(JavaFileObject javaFileObject, Classpath pathEntry) throws ClassFormatException, IOException{ + ClassFileReader reader = readJavaClass(javaFileObject, IModule.MODULE_INFO_CLASS); + if (reader != null) { + IModule module = reader.getModuleDeclaration(); + if (module != null) + return reader.getModuleDeclaration(); + } + return null; + } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/Main.java index 1f413ea4892..34fbc68cc84 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -45,6 +45,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.IntStream; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; @@ -3086,11 +3087,11 @@ private String validateModuleVersion(String versionString) { return versionString; } -private Parser getNewParser() { +public Parser getNewParser() { return new Parser(new ProblemReporter(getHandlingPolicy(), new CompilerOptions(this.options), getProblemFactory()), false); } -private IModule extractModuleDesc(String fileName) { +private IModule extractModuleDesc(String fileName, Supplier cuSupplier) { IModule mod = null; if (fileName.toLowerCase().endsWith(IModule.MODULE_INFO_JAVA)) { // this.options may not be completely populated yet, and definitely not @@ -3100,7 +3101,7 @@ private IModule extractModuleDesc(String fileName) { Parser parser = new Parser(new ProblemReporter(getHandlingPolicy(), new CompilerOptions(opts), getProblemFactory()), false); - ICompilationUnit cu = new CompilationUnit(null, fileName, null); + ICompilationUnit cu = cuSupplier.get(); CompilationResult compilationResult = new CompilationResult(cu, 0, 1, 10); CompilationUnitDeclaration unit = parser.parse(cu, compilationResult); if (unit.isModuleInfo() && unit.moduleDeclaration != null) { @@ -3557,8 +3558,11 @@ private void handleSingleModuleCompilation() { return; } IModule singleMod = null; - for (String filename : this.filenames) { - IModule mod = extractModuleDesc(filename); + String[] names = this.filenames; + for (int i = 0; i < names.length; i++) { + String filename = names[i]; + int idx = i; // idx is used in EclipseCompilerImpl.createCompilationUnit() + IModule mod = extractModuleDesc(filename, () -> createCompilationUnit(idx, filename)); if (mod != null) { if (singleMod == null) { singleMod = mod; @@ -3575,6 +3579,10 @@ private void handleSingleModuleCompilation() { this.module = singleMod; } } +// overridable hook +protected CompilationUnit createCompilationUnit(int idx, String filename) { + return new CompilationUnit(null, filename, null); +} /* * External API */ diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java index 68a286bbd53..ff875714692 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2020 IBM Corporation. + * Copyright (c) 2016, 2024 IBM Corporation. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 50a50eb0cd9..50ee30d6e68 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -11584,9 +11584,10 @@ public void invalidOpensStatement(OpensStatement statement, ModuleDeclaration mo statement.declarationSourceStart, statement.declarationSourceEnd); } public void invalidPackageReference(int problem, PackageVisibilityStatement ref) { + String[] arguments = new String[] { CharOperation.charToString(ref.pkgName) }; this.handle(problem, - NoArgument, - new String[] { CharOperation.charToString(ref.pkgName) }, + arguments, + arguments, ref.computeSeverity(problem), ref.pkgRef.sourceStart, ref.pkgRef.sourceEnd); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java index 31037a2bbfe..d574ea0719b 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2018 IBM Corporation and others. + * Copyright (c) 2006, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -111,7 +111,11 @@ public CompilationTask getTask(Writer out, JavaFileManager fileManager, Diagnost eclipseCompiler.initialize(writerOut, writerErr, false, null/*options*/, null/*progress*/); } final EclipseCompilerImpl eclipseCompiler2 = new EclipseCompilerImpl(writerOut, writerErr, false); - eclipseCompiler2.compilationUnits = compilationUnits; + eclipseCompiler2.compilationUnits = new ArrayList<>(); + if (compilationUnits != null) { + for (JavaFileObject javaFileObject : compilationUnits) + eclipseCompiler2.compilationUnits.add(javaFileObject); + } eclipseCompiler2.diagnosticListener = someDiagnosticListener; if (fileManager != null) { eclipseCompiler2.fileManager = fileManager; @@ -134,21 +138,19 @@ public CompilationTask getTask(Writer out, JavaFileManager fileManager, Diagnost } } - if (compilationUnits != null) { - for (JavaFileObject javaFileObject : compilationUnits) { - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6419926 - // compells us to check that the returned URIs are absolute, - // which they happen not to be for the default compiler on some - // unices - URI uri = javaFileObject.toUri(); - if (!uri.isAbsolute()) { - uri = URI.create("file://" + uri.toString()); //$NON-NLS-1$ - } - if (uri.getScheme().equals("file")) { //$NON-NLS-1$ - allOptions.add(new File(uri).getAbsolutePath()); - } else { - allOptions.add(uri.toString()); - } + for (JavaFileObject javaFileObject : eclipseCompiler2.compilationUnits) { + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6419926 + // compells us to check that the returned URIs are absolute, + // which they happen not to be for the default compiler on some + // unices + URI uri = javaFileObject.toUri(); + if (!uri.isAbsolute()) { + uri = URI.create("file://" + uri.toString()); //$NON-NLS-1$ + } + if (uri.getScheme().equals("file")) { //$NON-NLS-1$ + allOptions.add(new File(uri).getAbsolutePath()); + } else { + allOptions.add(uri.toString()); } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java index 90389871bd0..3f77a86d522 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2021 IBM Corporation and others. + * Copyright (c) 2007, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -28,15 +28,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Stream; import javax.annotation.processing.Processor; import javax.tools.Diagnostic; @@ -77,7 +69,8 @@ public class EclipseCompilerImpl extends Main { private static final String RELEASE_FILE = "release"; //$NON-NLS-1$ private static final String JAVA_VERSION = "JAVA_VERSION"; //$NON-NLS-1$ private HashMap javaFileObjectMap; - Iterable compilationUnits; + /** Corresponds to filenames in plain batch compilation, indices are synced also with modNames. */ + List compilationUnits; public JavaFileManager fileManager; protected Processor[] processors; public DiagnosticListener diagnosticListener; @@ -172,24 +165,19 @@ public CompilationUnit[] getCompilationUnits() { throw new IllegalArgumentException(this.bind("unit.missing", name)); //$NON-NLS-1$ } - CompilationUnit cu = new CompilationUnit(null, + try { + CompilationUnit cu = new CompilationUnit(javaFileObject.getCharContent(false).toString().toCharArray(), name, null, this.destinationPaths[i], - shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, name.toCharArray()), this.modNames[i]) { - - @Override - public char[] getContents() { - try { - return javaFileObject.getCharContent(true).toString().toCharArray(); - } catch(IOException e) { - e.printStackTrace(); - throw new AbortCompilationUnit(null, e, null); - } - } - }; + shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, name.toCharArray()), + this.modNames[i]); units.add(cu); this.javaFileObjectMap.put(cu, javaFileObject); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } i++; } @@ -716,7 +704,7 @@ protected void handleLocations() { } else if (javaFileManager != null) { Classpath classpath = null; if (this.fileManager.hasLocation(StandardLocation.SOURCE_PATH)) { - classpath = new ClasspathJsr199(this.fileManager, StandardLocation.SOURCE_PATH); + classpath = new ClasspathJsr199(this.fileManager, StandardLocation.SOURCE_PATH, new HashSet<>(this.compilationUnits), this::getNewParser); fileSystemClasspaths.add(classpath); } // Add the locations to search for in specific order @@ -728,12 +716,10 @@ protected void handleLocations() { fileSystemClasspaths.add(classpath); } if (this.fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH)) { - // FIXME: ClasspathJsr199 doesn't really support source files try { - Iterable> locationsForModules = this.fileManager.listLocationsForModules(StandardLocation.MODULE_SOURCE_PATH); - for (Set locs: locationsForModules) { + for (Set locs: this.fileManager.listLocationsForModules(StandardLocation.MODULE_SOURCE_PATH)) { for (Location loc : locs) { - classpath = new ClasspathJsr199(this.fileManager, loc); + classpath = new ClasspathJsr199(this.fileManager, loc, new HashSet<>(this.compilationUnits), this::getNewParser); fileSystemClasspaths.add(classpath); } } @@ -743,8 +729,7 @@ protected void handleLocations() { } if (this.fileManager.hasLocation(StandardLocation.MODULE_PATH)) { try { - Iterable> locationsForModules = this.fileManager.listLocationsForModules(StandardLocation.MODULE_PATH); - for (Set locs: locationsForModules) { + for (Set locs: this.fileManager.listLocationsForModules(StandardLocation.MODULE_PATH)) { for (Location loc : locs) { classpath = new ClasspathJsr199(this.fileManager, loc); fileSystemClasspaths.add(classpath); @@ -993,4 +978,23 @@ public String getMarkerType() { } } + + @Override + protected CompilationUnit createCompilationUnit(int idx, String filename) { + // NOTE: use of idx relies on same order in these members: + // + from Main: filenames, modNames + // + here: compilationUnits (see comment at declaration) + // I.e., instead of using filenames[idx] we use compilationUnits.get(idx): + if (this.compilationUnits != null && idx < this.compilationUnits.size()) { + JavaFileObject javaFileObject = this.compilationUnits.get(idx); + if (filename.endsWith(javaFileObject.getName())) { + try { + return ClasspathJsr199.readCompilationUnit(javaFileObject); + } catch (IOException e) { + // nop + } + } + } + return null; + } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java index 196c35d1a4d..746eeee06c4 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2022 IBM Corporation and others. + * Copyright (c) 2006, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -1417,7 +1417,6 @@ public void setLocationFromPaths(Location location, Collection p } private

void initModules(Location location, Iterable paths, Function toFile) throws IOException { if (location == StandardLocation.MODULE_PATH || location == StandardLocation.MODULE_SOURCE_PATH) { - // FIXME: same for module source path? Map options = new HashMap<>(); // FIXME: Find a way to get the options from the EclipseCompiler and pass it to the parser. String latest = CompilerOptions.getLatestVersion();