From f0b667b544be8bafa906dbe46ecd420f58fcbae4 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 28 Aug 2026 18:36:05 +0200 Subject: [PATCH] Fixing support for --patch-module= --- .../parsing/PatchModuleFileManager.java | 6 +- .../java/source/parsing/ProxyFileManager.java | 2 +- .../api/java/source/CompilationInfoTest.java | 85 ++++++++++++++++++- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/parsing/PatchModuleFileManager.java b/java/java.source.base/src/org/netbeans/modules/java/source/parsing/PatchModuleFileManager.java index 8f2a89d11452..5464292a4f95 100644 --- a/java/java.source.base/src/org/netbeans/modules/java/source/parsing/PatchModuleFileManager.java +++ b/java/java.source.base/src/org/netbeans/modules/java/source/parsing/PatchModuleFileManager.java @@ -159,7 +159,11 @@ public int isSupportedOption(String option) { @Override public boolean handleOption(String head, Iterator tail) { - if (JavacParser.OPTION_PATCH_MODULE.equals(head)) { + if (head.startsWith(JavacParser.OPTION_PATCH_MODULE)) { + if (head.length() > JavacParser.OPTION_PATCH_MODULE.length() && + head.charAt(JavacParser.OPTION_PATCH_MODULE.length()) == '=') { + tail = List.of(head.substring(JavacParser.OPTION_PATCH_MODULE.length() + 1)).iterator(); + } final Pair> modulePatches = FileObjects.parseModulePatches(tail); if (modulePatches != null) { addModulePatches(modulePatches.first(), modulePatches.second()); diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/parsing/ProxyFileManager.java b/java/java.source.base/src/org/netbeans/modules/java/source/parsing/ProxyFileManager.java index fffcf8061d50..4dbc7469670e 100644 --- a/java/java.source.base/src/org/netbeans/modules/java/source/parsing/ProxyFileManager.java +++ b/java/java.source.base/src/org/netbeans/modules/java/source/parsing/ProxyFileManager.java @@ -750,7 +750,7 @@ JavaFileManager[] getFileManagers(@NonNull Location location, @NullAllowed Strin if (TreeLoaderOutputFileManager.OUTPUT_ROOT.equals(hint)) { createTreeLoaderFileManager(); } - if (JavacParser.OPTION_PATCH_MODULE.equals(hint) || (hint != null && hint.startsWith(JavacParser.NB_X_MODULE))) { + if (hint != null && (hint.startsWith(JavacParser.OPTION_PATCH_MODULE) || hint.startsWith(JavacParser.NB_X_MODULE))) { createPatchFileManager(); createModuleSrcFileManager(); } diff --git a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java index 0933d86b17f6..206e5e63a1e5 100644 --- a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java +++ b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java @@ -22,17 +22,23 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.net.URL; import java.text.MessageFormat; +import java.util.Collection; +import java.util.List; import javax.lang.model.SourceVersion; -import javax.swing.text.BadLocationException; import javax.swing.text.Document; +import javax.tools.Diagnostic; import org.junit.Test; +import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.lexer.JavaTokenId; import org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy; import org.netbeans.api.java.source.JavaSource.Phase; import org.netbeans.api.lexer.Language; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.java.source.indexing.TransactionContext; +import org.netbeans.modules.java.source.usages.ClassIndexManager; import org.openide.cookies.EditorCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -160,4 +166,81 @@ public void run(CompilationController parameter) throws Exception { } }, true); } + + public void testPatchModule() throws Exception { + clearWorkDir(); + + FileObject wd = FileUtil.toFileObject(getWorkDir()); + + FileObject patchDir = FileUtil.createFolder(wd, "patch"); + FileObject patch = FileUtil.createData(patchDir, "java/lang/Patched.java"); + TestUtilities.copyStringToFile(patch, """ + package java.lang; + public class Patched { + } + """); + + FileObject srcDir = FileUtil.createFolder(wd, "src"); + FileObject source = FileUtil.createData(srcDir, "Test.java"); + String code = """ + public class Test { + private Patched p; + } + """; + + FileObject classesDir = FileUtil.createFolder(wd, "classes"); + FileObject cacheDir = FileUtil.createFolder(wd, "cache"); + + SourceUtilsTestUtil.prepareTest(srcDir, + classesDir, + cacheDir, + new FileObject[0]); + + initSourceQuery(List.of(patchDir.toURL())); //force creation of usages query + + SourceUtilsTestUtil.setSourceLevel(srcDir, "17"); + JavaSource js = JavaSource.forFileObject(source); + + for (List options : List.of(List.of("--patch-module", "java.base=" + FileUtil.toFile(patchDir).getAbsolutePath()), + List.of("--patch-module=java.base=" + FileUtil.toFile(patchDir).getAbsolutePath()))) { + TestUtilities.copyStringToFile(source, code); //force reparse + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + parameter.toPhase(Phase.RESOLVED); + assertEquals(List.of("compiler.err.cant.resolve.location"), + parameter.getDiagnostics().stream().filter(d -> d.getKind() == Diagnostic.Kind.ERROR).map(d -> d.getCode()).toList()); + } + }, true); + + SourceUtilsTestUtil.setCompilerOptions(srcDir, options); + TestUtilities.copyStringToFile(source, code); //force reparse + + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + parameter.toPhase(Phase.RESOLVED); + assertEquals(List.of(), + parameter.getDiagnostics().stream().filter(d -> d.getKind() == Diagnostic.Kind.ERROR).map(d -> d.getCode()).toList()); + } + }, true); + SourceUtilsTestUtil.setCompilerOptions(srcDir, List.of()); + } + } + + private static final void initSourceQuery(final Collection urls) throws IOException { + final ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY, ClassPath.EMPTY); + final ClassIndexManager mgr = ClassIndexManager.getDefault(); + final JavaSource js = JavaSource.create(cpInfo); + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + for (final URL url : urls) { + TransactionContext ctx = TransactionContext.beginStandardTransaction(url, false, ()->true, false); + try { + mgr.createUsagesQuery(url, true); + } finally { + ctx.commit(); + } + } + } + }, true); + } }