|
| 1 | +diff --git a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java |
| 2 | +index 7ac61fb4370f..31bc75e99a54 100644 |
| 3 | +--- a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java |
| 4 | ++++ b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java |
| 5 | +@@ -731,10 +731,21 @@ private void insideImport(Env env) throws IOException { |
| 6 | + ImportTree im = (ImportTree) env.getPath().getLeaf(); |
| 7 | + SourcePositions sourcePositions = env.getSourcePositions(); |
| 8 | + CompilationUnitTree root = env.getRoot(); |
| 9 | ++ if (im.isModule()) { |
| 10 | ++ if (offset >= sourcePositions.getStartPosition(root, im.getQualifiedIdentifier())) { |
| 11 | ++ addModuleNamesFromGraph(env, null); |
| 12 | ++ } |
| 13 | ++ } else { |
| 14 | + if (offset <= sourcePositions.getStartPosition(root, im.getQualifiedIdentifier())) { |
| 15 | + TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, im, offset); |
| 16 | +- if (last != null && last.token().id() == JavaTokenId.IMPORT && Utilities.startsWith(STATIC_KEYWORD, prefix)) { |
| 17 | +- addKeyword(env, STATIC_KEYWORD, SPACE, false); |
| 18 | ++ if (last != null && last.token().id() == JavaTokenId.IMPORT) { |
| 19 | ++ if (Utilities.startsWith(STATIC_KEYWORD, prefix)) { |
| 20 | ++ addKeyword(env, STATIC_KEYWORD, SPACE, false); |
| 21 | ++ } |
| 22 | ++ if (Utilities.startsWith(MODULE_KEYWORD, prefix) && |
| 23 | ++ env.getController().getSourceVersion().compareTo(SourceVersion.RELEASE_25) >= 0) { |
| 24 | ++ addKeyword(env, MODULE_KEYWORD, SPACE, false); |
| 25 | ++ } |
| 26 | + } |
| 27 | + if (options.contains(Options.ALL_COMPLETION) || options.contains(Options.COMBINED_COMPLETION)) { |
| 28 | + EnumSet<ElementKind> classKinds = EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE); |
| 29 | +@@ -746,6 +757,7 @@ private void insideImport(Env env) throws IOException { |
| 30 | + addPackages(env, null, false); |
| 31 | + } |
| 32 | + } |
| 33 | ++ } |
| 34 | + } |
| 35 | + |
| 36 | + private void insideClass(Env env) throws IOException { |
| 37 | +@@ -1635,7 +1647,13 @@ private void insideMemberSelect(Env env) throws IOException { |
| 38 | + } |
| 39 | + if (!afterDot) { |
| 40 | + if (expEndPos <= offset) { |
| 41 | +- insideExpression(env, new TreePath(path, fa.getExpression())); |
| 42 | ++ if (fa.getExpression().getKind() == Kind.IDENTIFIER && |
| 43 | ++ ((IdentifierTree) fa.getExpression()).getName().contentEquals(MODULE_KEYWORD)) { |
| 44 | ++ controller.toPhase(Phase.ELEMENTS_RESOLVED); |
| 45 | ++ addModuleNamesFromGraph(env, null); |
| 46 | ++ } else { |
| 47 | ++ insideExpression(env, new TreePath(path, fa.getExpression())); |
| 48 | ++ } |
| 49 | + } |
| 50 | + return; |
| 51 | + } |
| 52 | +@@ -1656,10 +1674,15 @@ private void insideMemberSelect(Env env) throws IOException { |
| 53 | + } |
| 54 | + } else if (lastNonWhitespaceTokenId != JavaTokenId.STAR) { |
| 55 | + controller.toPhase(Phase.RESOLVED); |
| 56 | +- if (withinModuleName(env)) { |
| 57 | ++ boolean inModuleNameInImport = false; |
| 58 | ++ if (withinModuleName(env) || (inModuleNameInImport = withinModuleNameInImport(env))) { |
| 59 | + String fqnPrefix = fa.getExpression().toString() + '.'; |
| 60 | + anchorOffset = (int) sourcePositions.getStartPosition(root, fa); |
| 61 | +- addModuleNames(env, fqnPrefix, true); |
| 62 | ++ if (inModuleNameInImport) { |
| 63 | ++ addModuleNamesFromGraph(env, fqnPrefix); |
| 64 | ++ } else { |
| 65 | ++ addModuleNames(env, fqnPrefix, true); |
| 66 | ++ } |
| 67 | + return; |
| 68 | + } |
| 69 | + TreePath parentPath = path.getParentPath(); |
| 70 | +@@ -4458,12 +4481,20 @@ private void addPackages(Env env, String fqnPrefix, boolean srcOnly) { |
| 71 | + } |
| 72 | + |
| 73 | + private void addModuleNames(Env env, String fqnPrefix, boolean srcOnly) { |
| 74 | ++ srcOnly = false; |
| 75 | ++ addModuleNames(env, fqnPrefix, SourceUtils.getModuleNames(env.getController(), srcOnly ? EnumSet.of(ClassIndex.SearchScope.SOURCE) : EnumSet.allOf(ClassIndex.SearchScope.class))); |
| 76 | ++ } |
| 77 | ++ |
| 78 | ++ private void addModuleNamesFromGraph(Env env, String fqnPrefix) { |
| 79 | ++ addModuleNames(env, fqnPrefix, env.getController().getElements().getAllModuleElements().stream().map(me -> me.getQualifiedName().toString()).toList()); |
| 80 | ++ } |
| 81 | ++ |
| 82 | ++ private void addModuleNames(Env env, String fqnPrefix, Iterable<? extends String> modulesNames) { |
| 83 | + if (fqnPrefix == null) { |
| 84 | + fqnPrefix = EMPTY; |
| 85 | + } |
| 86 | +- srcOnly = false; |
| 87 | + String prefix = env.getPrefix() != null ? fqnPrefix + env.getPrefix() : fqnPrefix; |
| 88 | +- for (String name : SourceUtils.getModuleNames(env.getController(), srcOnly ? EnumSet.of(ClassIndex.SearchScope.SOURCE) : EnumSet.allOf(ClassIndex.SearchScope.class))) { |
| 89 | ++ for (String name : modulesNames) { |
| 90 | + if (startsWith(env, name, prefix) && itemFactory instanceof ModuleItemFactory) { |
| 91 | + results.add(((ModuleItemFactory<T>)itemFactory).createModuleItem(name, anchorOffset)); |
| 92 | + } |
| 93 | +@@ -6657,6 +6688,21 @@ private boolean withinModuleName(Env env) { |
| 94 | + return false; |
| 95 | + } |
| 96 | + |
| 97 | ++ private boolean withinModuleNameInImport(Env env) { |
| 98 | ++ TreePath path = env.getPath(); |
| 99 | ++ Tree last = null; |
| 100 | ++ while (path != null) { |
| 101 | ++ Tree tree = path.getLeaf(); |
| 102 | ++ if (last != null |
| 103 | ++ && tree.getKind() == Tree.Kind.IMPORT && ((ImportTree) tree).isModule() && ((ImportTree) tree).getQualifiedIdentifier() == last) { |
| 104 | ++ return true; |
| 105 | ++ } |
| 106 | ++ path = path.getParentPath(); |
| 107 | ++ last = tree; |
| 108 | ++ } |
| 109 | ++ return false; |
| 110 | ++ } |
| 111 | ++ |
| 112 | + private boolean withinProvidesService(Env env) { |
| 113 | + TreePath path = env.getPath(); |
| 114 | + Tree last = null; |
| 115 | +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFull.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFull.pass |
| 116 | +new file mode 100644 |
| 117 | +index 000000000000..c7fb77ebcdb5 |
| 118 | +--- /dev/null |
| 119 | ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFull.pass |
| 120 | +@@ -0,0 +1,6 @@ |
| 121 | ++java.base |
| 122 | ++java.compiler |
| 123 | ++java.xml |
| 124 | ++jdk.compiler |
| 125 | ++jdk.jartool |
| 126 | ++jdk.javadoc |
| 127 | +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFullJDKJPrefix.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFullJDKJPrefix.pass |
| 128 | +new file mode 100644 |
| 129 | +index 000000000000..08f71672206c |
| 130 | +--- /dev/null |
| 131 | ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFullJDKJPrefix.pass |
| 132 | +@@ -0,0 +1,2 @@ |
| 133 | ++jdk.jartool |
| 134 | ++jdk.javadoc |
| 135 | +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFullJDKPrefix.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFullJDKPrefix.pass |
| 136 | +new file mode 100644 |
| 137 | +index 000000000000..5e15d03b7041 |
| 138 | +--- /dev/null |
| 139 | ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/importModuleListFullJDKPrefix.pass |
| 140 | +@@ -0,0 +1,3 @@ |
| 141 | ++jdk.compiler |
| 142 | ++jdk.jartool |
| 143 | ++jdk.javadoc |
| 144 | +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/staticAndModuleKeywordAndAllPackages.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/staticAndModuleKeywordAndAllPackages.pass |
| 145 | +new file mode 100644 |
| 146 | +index 000000000000..444f86a32452 |
| 147 | +--- /dev/null |
| 148 | ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/staticAndModuleKeywordAndAllPackages.pass |
| 149 | +@@ -0,0 +1,7 @@ |
| 150 | ++module |
| 151 | ++static |
| 152 | ++com |
| 153 | ++java |
| 154 | ++javax |
| 155 | ++org |
| 156 | ++sun |
| 157 | +diff --git a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask125FeaturesTest.java b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask125FeaturesTest.java |
| 158 | +index d019a4b018e6..18a1e371bd96 100644 |
| 159 | +--- a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask125FeaturesTest.java |
| 160 | ++++ b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask125FeaturesTest.java |
| 161 | +@@ -19,7 +19,13 @@ |
| 162 | + |
| 163 | + package org.netbeans.modules.java.completion; |
| 164 | + |
| 165 | ++import java.util.ArrayList; |
| 166 | ++import java.util.List; |
| 167 | ++import javax.swing.event.ChangeListener; |
| 168 | + import org.netbeans.modules.java.source.parsing.JavacParser; |
| 169 | ++import org.netbeans.spi.java.queries.CompilerOptionsQueryImplementation; |
| 170 | ++import org.openide.filesystems.FileObject; |
| 171 | ++import org.openide.util.lookup.ServiceProvider; |
| 172 | + |
| 173 | + public class JavaCompletionTask125FeaturesTest extends CompletionTestBase { |
| 174 | + |
| 175 | +@@ -41,7 +47,59 @@ public void testCompactSourceFilesEnd() throws Exception { |
| 176 | + performTest("CompactSourceFile", 883, null, "compactSourceFilesInsideClass.pass", SOURCE_LEVEL); |
| 177 | + } |
| 178 | + |
| 179 | ++ public void testImportModuleKeyword() throws Exception { |
| 180 | ++ performTest("Import", 823, "import ", "staticAndModuleKeywordAndAllPackages.pass", SOURCE_LEVEL); |
| 181 | ++ } |
| 182 | ++ |
| 183 | ++ public void testImportModuleNoModuleName() throws Exception { |
| 184 | ++ TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--limit-modules=java.base,jdk.compiler,jdk.javadoc,jdk.jartool"); |
| 185 | ++ performTest("Import", 823, "import module ", "importModuleListFull.pass", SOURCE_LEVEL); |
| 186 | ++ } |
| 187 | ++ |
| 188 | ++ public void testImportModulePrefix1() throws Exception { |
| 189 | ++ TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--limit-modules=java.base,jdk.compiler,jdk.javadoc,jdk.jartool"); |
| 190 | ++ performTest("Import", 823, "import module jd", "importModuleListFullJDKPrefix.pass", SOURCE_LEVEL); |
| 191 | ++ } |
| 192 | ++ |
| 193 | ++ public void testImportModulePrefix2() throws Exception { |
| 194 | ++ TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--limit-modules=java.base,jdk.compiler,jdk.javadoc,jdk.jartool"); |
| 195 | ++ performTest("Import", 823, "import module jdk.", "importModuleListFullJDKPrefix.pass", SOURCE_LEVEL); |
| 196 | ++ } |
| 197 | ++ |
| 198 | ++ public void testImportModulePrefix3() throws Exception { |
| 199 | ++ TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--limit-modules=java.base,jdk.compiler,jdk.javadoc,jdk.jartool"); |
| 200 | ++ performTest("Import", 823, "import module jdk.j", "importModuleListFullJDKJPrefix.pass", SOURCE_LEVEL); |
| 201 | ++ } |
| 202 | ++ |
| 203 | ++ @Override |
| 204 | ++ protected void tearDown() throws Exception { |
| 205 | ++ super.tearDown(); |
| 206 | ++ TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.clear(); |
| 207 | ++ } |
| 208 | ++ |
| 209 | + static { |
| 210 | + JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true; |
| 211 | + } |
| 212 | ++ |
| 213 | ++ @ServiceProvider(service = CompilerOptionsQueryImplementation.class, position = 100) |
| 214 | ++ public static class TestCompilerOptionsQueryImplementation implements CompilerOptionsQueryImplementation { |
| 215 | ++ |
| 216 | ++ private static final List<String> EXTRA_OPTIONS = new ArrayList<>(); |
| 217 | ++ |
| 218 | ++ @Override |
| 219 | ++ public CompilerOptionsQueryImplementation.Result getOptions(FileObject file) { |
| 220 | ++ return new CompilerOptionsQueryImplementation.Result() { |
| 221 | ++ @Override |
| 222 | ++ public List<? extends String> getArguments() { |
| 223 | ++ return EXTRA_OPTIONS; |
| 224 | ++ } |
| 225 | ++ |
| 226 | ++ @Override |
| 227 | ++ public void addChangeListener(ChangeListener listener) {} |
| 228 | ++ |
| 229 | ++ @Override |
| 230 | ++ public void removeChangeListener(ChangeListener listener) {} |
| 231 | ++ }; |
| 232 | ++ } |
| 233 | ++ } |
| 234 | + } |
| 235 | +diff --git a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskBasicTest.java b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskBasicTest.java |
| 236 | +index 02a163326ed6..1a57584e5e74 100644 |
| 237 | +--- a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskBasicTest.java |
| 238 | ++++ b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskBasicTest.java |
| 239 | +@@ -140,15 +140,15 @@ public void testAfterImportKeyword() throws Exception { |
| 240 | + } |
| 241 | + |
| 242 | + public void testEmptyFileBeforeTypingImportedPackage() throws Exception { |
| 243 | +- performTest("Empty", 808, "import ", "staticKeywordAndAllPackages.pass"); |
| 244 | ++ performTest("Empty", 808, "import ", "staticKeywordAndAllPackages.pass", "24"); //24 - without "import module" |
| 245 | + } |
| 246 | + |
| 247 | + public void testBeforeTypingImportedPackage() throws Exception { |
| 248 | +- performTest("Simple", 823, "import ", "staticKeywordAndAllPackages.pass"); |
| 249 | ++ performTest("Simple", 823, "import ", "staticKeywordAndAllPackages.pass", "24"); //24 - without "import module" |
| 250 | + } |
| 251 | + |
| 252 | + public void testBeforeImportedPackage() throws Exception { |
| 253 | +- performTest("Import", 831, null, "staticKeywordAndAllPackages.pass"); |
| 254 | ++ performTest("Import", 831, null, "staticKeywordAndAllPackages.pass", "24"); //24 - without "import module" |
| 255 | + } |
| 256 | + |
| 257 | + public void testEmptyFileTypingImportedPackage() throws Exception { |
| 258 | +@@ -264,7 +264,7 @@ public void testEmptyFileTypingImportedPackageAfterErrorInPackageDeclaration() t |
| 259 | + } |
| 260 | + |
| 261 | + public void testTypingStaticImportAfterErrorInPackageDeclaration() throws Exception { |
| 262 | +- performTest("SimpleNoPackage", 808, "package \nimport ", "staticKeywordAndAllPackages.pass"); |
| 263 | ++ performTest("SimpleNoPackage", 808, "package \nimport ", "staticKeywordAndAllPackages.pass", "24"); //24 - without "import module" |
| 264 | + } |
| 265 | + |
| 266 | + public void TODO_testTypingStaticImportAfterErrorInPreviousImportDeclaration() throws Exception { |
| 267 | +diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java |
| 268 | +index 83c9aa8bd5fe..99a60193cb78 100644 |
| 269 | +--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java |
| 270 | ++++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java |
| 271 | +@@ -373,6 +373,7 @@ public Completion createModuleItem(String moduleName, int substitutionOffset) { |
| 272 | + .kind(Completion.Kind.Folder) |
| 273 | + .sortText(String.format("%04d%s", 1950, moduleName)) |
| 274 | + .insertTextFormat(Completion.TextFormat.PlainText) |
| 275 | ++ .textEdit(new TextEdit(substitutionOffset, offset, moduleName)) |
| 276 | + .build(); |
| 277 | + } |
| 278 | + |
0 commit comments