diff options
author | George Fraser <george@fivetran.com> | 2018-12-27 13:02:36 -0800 |
---|---|---|
committer | George Fraser <george@fivetran.com> | 2018-12-27 13:02:36 -0800 |
commit | cbcbbd22afdd867f4f43817dc53df3800814b0ba (patch) | |
tree | edd829d47706136c40025afe222f9ef10094e7e5 /src | |
parent | 8321c9206bffe676c7794f2404aa69a451e3749b (diff) | |
download | java-language-server-cbcbbd22afdd867f4f43817dc53df3800814b0ba.zip |
Fix completion when many static imports are present
Diffstat (limited to 'src')
6 files changed, 59 insertions, 18 deletions
diff --git a/src/main/java/org/javacs/CompileFocus.java b/src/main/java/org/javacs/CompileFocus.java index c90e99b..e8a9a27 100644 --- a/src/main/java/org/javacs/CompileFocus.java +++ b/src/main/java/org/javacs/CompileFocus.java @@ -132,7 +132,8 @@ public class CompileFocus { } public List<Completion> completeIdentifiers(boolean insideClass, boolean insideMethod, String partialName) { - LOG.info("...completing identifiers"); + LOG.info(String.format("Completing identifiers starting with `%s`...", partialName)); + var result = new ArrayList<Completion>(); // Add snippets @@ -581,7 +582,7 @@ public class CompileFocus { if (isThisOrSuper(e)) { unwrapThisSuper((VariableElement) e); } - if (result.size() >= MAX_COMPLETION_ITEMS) return; + if (tooManyItems(result.size())) return; } } catch (Exception e) { LOG.log(Level.WARNING, "error walking locals in scope", e); @@ -621,7 +622,7 @@ public class CompileFocus { walkLocals(s); profileEnd(s); // Return early? - if (result.size() >= MAX_COMPLETION_ITEMS) { + if (tooManyItems(result.size())) { printProfile(); return result; } @@ -634,6 +635,12 @@ public class CompileFocus { return new Walk().walkScopes(); } + private boolean tooManyItems(int count) { + var test = count >= MAX_COMPLETION_ITEMS; + if (test) LOG.warning(String.format("...# of items %d reached max %s", count, MAX_COMPLETION_ITEMS)); + return test; + } + private Set<String> subPackages(String parentPackage) { var result = new HashSet<String>(); Consumer<String> checkClassName = @@ -661,16 +668,22 @@ public class CompileFocus { } private void completeScopeIdentifiers(String partialName, List<Completion> result) { - var startsWithUpperCase = partialName.length() > 0 && Character.isUpperCase(partialName.charAt(0)); // Add locals - for (var m : scopeMembers(partialName)) { + var locals = scopeMembers(partialName); + for (var m : locals) { result.add(Completion.ofElement(m)); } + LOG.info(String.format("...found %d locals", locals.size())); + // Add static imports - for (var m : staticImports(file, contents, partialName)) { + var staticImports = staticImports(file, contents, partialName); + for (var m : staticImports) { result.add(Completion.ofElement(m)); } + LOG.info(String.format("...found %d static imports", staticImports.size())); + // Add classes + var startsWithUpperCase = partialName.length() > 0 && Character.isUpperCase(partialName.charAt(0)); if (startsWithUpperCase) { var packageName = Objects.toString(root.getPackageName(), ""); Predicate<String> matchesPartialName = @@ -678,18 +691,27 @@ public class CompileFocus { var className = Parser.lastName(qualifiedName); return matchesPartialName(className, partialName); }; + + // Check JDK + LOG.info("...checking JDK"); for (var c : parent.jdkClasses.classes()) { - if (result.size() >= MAX_COMPLETION_ITEMS) return; + if (tooManyItems(result.size())) return; if (matchesPartialName.test(c) && parent.jdkClasses.isAccessibleFromPackage(c, packageName)) { result.add(Completion.ofClassName(c, isImported(c))); } } + + // Check classpath + LOG.info("...checking classpath"); for (var c : parent.classPathClasses.classes()) { - if (result.size() >= MAX_COMPLETION_ITEMS) return; + if (tooManyItems(result.size())) return; if (matchesPartialName.test(c) && parent.classPathClasses.isAccessibleFromPackage(c, packageName)) { result.add(Completion.ofClassName(c, isImported(c))); } } + + // Check sourcepath + LOG.info("...checking source path"); Predicate<Path> matchesFileName = file -> matchesPartialName(file.getFileName().toString(), partialName); Predicate<Path> isPublic = file -> { @@ -712,7 +734,7 @@ public class CompileFocus { return relative.substring(0, relative.length() - ".java".length()); }; for (var file : JavaCompilerService.javaSourcesInDir(dir)) { - if (result.size() >= MAX_COMPLETION_ITEMS) return; + if (tooManyItems(result.size())) return; // Fast check, file name only if (matchesFileName.test(file)) { var c = qualifiedName.apply(file); @@ -735,12 +757,19 @@ public class CompileFocus { var el = (TypeElement) trees.getElement(path); if (id.getIdentifier().contentEquals("*")) { for (var member : el.getEnclosedElements()) { - if (member.getModifiers().contains(Modifier.STATIC)) result.add(member); + if (matchesPartialName(member.getSimpleName(), partialName) + && member.getModifiers().contains(Modifier.STATIC)) { + result.add(member); + if (tooManyItems(result.size())) return result; + } } } else { for (var member : el.getEnclosedElements()) { if (matchesPartialName(member.getSimpleName(), partialName) - && member.getModifiers().contains(Modifier.STATIC)) result.add(member); + && member.getModifiers().contains(Modifier.STATIC)) { + result.add(member); + if (tooManyItems(result.size())) return result; + } } } } diff --git a/src/main/java/org/javacs/JavaTextDocumentService.java b/src/main/java/org/javacs/JavaTextDocumentService.java index 672a288..c23244b 100644 --- a/src/main/java/org/javacs/JavaTextDocumentService.java +++ b/src/main/java/org/javacs/JavaTextDocumentService.java @@ -10,6 +10,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; +import java.lang.annotation.Annotation; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths; @@ -80,7 +81,8 @@ class JavaTextDocumentService implements TextDocumentService { var line = position.getPosition().getLine() + 1; var column = position.getPosition().getCharacter() + 1; lastCompletions.clear(); - var maybeCtx = server.compiler.parseFile(uri, content).completionPosition(line, column); + // Figure out what kind of completion we want to do + var maybeCtx = server.compiler.parseFile(uri, content).completionContext(line, column); if (!maybeCtx.isPresent()) { var items = new ArrayList<CompletionItem>(); for (var name : CompileFocus.TOP_LEVEL_KEYWORDS) { @@ -93,8 +95,10 @@ class JavaTextDocumentService implements TextDocumentService { var list = new CompletionList(true, items); return CompletableFuture.completedFuture(Either.forRight(list)); } + // Compile again, focusing on a region that depends on what type of completion we want to do var ctx = maybeCtx.get(); var focus = server.compiler.compileFocus(uri, content, ctx.line, ctx.character); + // Do a specific type of completion List<Completion> cs; boolean isIncomplete; switch (ctx.kind) { @@ -121,6 +125,7 @@ class JavaTextDocumentService implements TextDocumentService { default: throw new RuntimeException("Unexpected completion context " + ctx.kind); } + // Convert to CompletionItem var result = new ArrayList<CompletionItem>(); for (var c : cs) { var i = new CompletionItem(); diff --git a/src/main/java/org/javacs/ParseFile.java b/src/main/java/org/javacs/ParseFile.java index 7455f5e..55c7111 100644 --- a/src/main/java/org/javacs/ParseFile.java +++ b/src/main/java/org/javacs/ParseFile.java @@ -89,8 +89,9 @@ public class ParseFile { } // TODO maybe this should return TreePath? - public Optional<CompletionContext> completionPosition(int line, int character) { + public Optional<CompletionContext> completionContext(int line, int character) { LOG.info(String.format("Finding completion position near %s(%d,%d)...", file, line, character)); + var pos = trees.getSourcePositions(); var lines = root.getLineMap(); var cursor = lines.getPosition(line, character); diff --git a/src/test/java/org/javacs/CompletionsTest.java b/src/test/java/org/javacs/CompletionsTest.java index 343a2b8..569a620 100644 --- a/src/test/java/org/javacs/CompletionsTest.java +++ b/src/test/java/org/javacs/CompletionsTest.java @@ -452,6 +452,11 @@ public class CompletionsTest extends CompletionsBase { suggestions = insertText(file, 6, 13); assertThat(suggestions, hasItems("SomeInnerClass")); + + // List? + suggestions = insertText(file, 7, 12); + + assertThat(suggestions, hasItems("List")); } @Test diff --git a/src/test/java/org/javacs/JavaCompilerServiceTest.java b/src/test/java/org/javacs/JavaCompilerServiceTest.java index a05cf84..ffcbc26 100644 --- a/src/test/java/org/javacs/JavaCompilerServiceTest.java +++ b/src/test/java/org/javacs/JavaCompilerServiceTest.java @@ -128,7 +128,7 @@ public class JavaCompilerServiceTest { public void completeIdentifiers() { var uri = resourceUri("/CompleteIdentifiers.java"); var contents = contents("/CompleteIdentifiers.java"); - var ctx = compiler.parseFile(uri, contents).completionPosition(13, 21).get(); + var ctx = compiler.parseFile(uri, contents).completionContext(13, 21).get(); var focus = compiler.compileFocus(uri, contents, ctx.line, ctx.character); var found = focus.completeIdentifiers(ctx.inClass, ctx.inMethod, ctx.partialName); var names = completionNames(found); @@ -159,7 +159,7 @@ public class JavaCompilerServiceTest { public void completeMembers() { var uri = resourceUri("/CompleteMembers.java"); var contents = contents("/CompleteMembers.java"); - var ctx = compiler.parseFile(uri, contents).completionPosition(3, 15).get(); + var ctx = compiler.parseFile(uri, contents).completionContext(3, 15).get(); var focus = compiler.compileFocus(uri, contents, ctx.line, ctx.character); var found = focus.completeMembers(false); var names = completionNames(found); @@ -172,7 +172,7 @@ public class JavaCompilerServiceTest { public void completeExpression() { var uri = resourceUri("/CompleteExpression.java"); var contents = contents("/CompleteExpression.java"); - var ctx = compiler.parseFile(uri, contents).completionPosition(3, 37).get(); + var ctx = compiler.parseFile(uri, contents).completionContext(3, 37).get(); var focus = compiler.compileFocus(uri, contents, ctx.line, ctx.character); var found = focus.completeMembers(false); var names = completionNames(found); @@ -185,7 +185,7 @@ public class JavaCompilerServiceTest { public void completeClass() { var uri = resourceUri("/CompleteClass.java"); var contents = contents("/CompleteClass.java"); - var ctx = compiler.parseFile(uri, contents).completionPosition(3, 23).get(); + var ctx = compiler.parseFile(uri, contents).completionContext(3, 23).get(); var focus = compiler.compileFocus(uri, contents, ctx.line, ctx.character); var found = focus.completeMembers(false); var names = completionNames(found); @@ -199,7 +199,7 @@ public class JavaCompilerServiceTest { public void completeImports() { var uri = resourceUri("/CompleteImports.java"); var contents = contents("/CompleteImports.java"); - var ctx = compiler.parseFile(uri, contents).completionPosition(1, 18).get(); + var ctx = compiler.parseFile(uri, contents).completionContext(1, 18).get(); var focus = compiler.compileFocus(uri, contents, ctx.line, ctx.character); var found = focus.completeMembers(false); var names = completionNames(found); diff --git a/src/test/test-project/workspace/src/org/javacs/example/AutocompleteClasses.java b/src/test/test-project/workspace/src/org/javacs/example/AutocompleteClasses.java index bddf9f4..beb8bfc 100644 --- a/src/test/test-project/workspace/src/org/javacs/example/AutocompleteClasses.java +++ b/src/test/test-project/workspace/src/org/javacs/example/AutocompleteClasses.java @@ -4,6 +4,7 @@ public class AutocompleteClasses { public static void test() { Fix; Some; + Lis; } public static class SomeInnerClass { |