summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/test.sh12
-rw-r--r--src/main/java/org/javacs/JavaCompilerService.java64
-rw-r--r--src/main/java/org/javacs/JavaTextDocumentService.java2
-rw-r--r--src/main/java/org/javacs/README.md1
-rw-r--r--src/test/java/org/javacs/JavaCompilerServiceTest.java73
5 files changed, 70 insertions, 82 deletions
diff --git a/scripts/test.sh b/scripts/test.sh
deleted file mode 100755
index c80ccdb..0000000
--- a/scripts/test.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# Set java version 11
-JAVA_HOME=$(/usr/libexec/java_home -v 11)
-
-# Figure out test classpath
-mvn dependency:build-classpath -DincludeScope=test -Dmdep.outputFile=cp.txt
-
-# Run all tests directly
-./.circleci/test.sh
diff --git a/src/main/java/org/javacs/JavaCompilerService.java b/src/main/java/org/javacs/JavaCompilerService.java
index 8855c5c..6b31e3b 100644
--- a/src/main/java/org/javacs/JavaCompilerService.java
+++ b/src/main/java/org/javacs/JavaCompilerService.java
@@ -25,6 +25,7 @@ import javax.tools.*;
// TODO eliminate uses of URI in favor of Path
public class JavaCompilerService {
+ public static final int MAX_COMPLETION_ITEMS = 50;
private static final Logger LOG = Logger.getLogger("main");
// Not modifiable! If you want to edit these, you need to create a new instance
private final Set<Path> sourcePath, classPath, docPath;
@@ -362,8 +363,18 @@ public class JavaCompilerService {
return result;
}
+ static boolean matchesPartialName(CharSequence candidate, CharSequence partialName) {
+ if (candidate.length() < partialName.length())
+ return false;
+ for (int i = 0; i < partialName.length(); i++) {
+ if (candidate.charAt(i) != partialName.charAt(i))
+ return false;
+ }
+ return true;
+ }
+
/** Find all identifiers in scope at line:character */
- public List<Element> scopeMembers(URI file, String contents, int line, int character) {
+ public List<Element> scopeMembers(URI file, String contents, int line, int character, String partialName) {
recompile(file, contents, line, character);
var trees = Trees.instance(cache.task);
@@ -385,8 +396,8 @@ public class JavaCompilerService {
return e.getModifiers().contains(Modifier.STATIC);
}
- boolean isThisOrSuper(VariableElement ve) {
- var name = ve.getSimpleName();
+ boolean isThisOrSuper(Element e) {
+ var name = e.getSimpleName();
return name.contentEquals("this") || name.contentEquals("super");
}
@@ -403,6 +414,7 @@ public class JavaCompilerService {
for (var thisMember : thisElement.getEnclosedElements()) {
if (isStatic(start) && !isStatic(thisMember)) continue;
if (thisMember.getSimpleName().contentEquals("<init>")) continue;
+ if (!matchesPartialName(thisMember.getSimpleName(), partialName)) continue;
// Check if member is accessible from original scope
if (trees.isAccessible(start, thisMember, thisDeclaredType)) {
@@ -415,20 +427,20 @@ public class JavaCompilerService {
void walkLocals(Scope s) {
try {
for (var e : s.getLocalElements()) {
- if (e instanceof TypeElement) {
- var te = (TypeElement) e;
- if (trees.isAccessible(start, te)) result.add(te);
- } else if (e instanceof VariableElement) {
- var ve = (VariableElement) e;
- if (isThisOrSuper(ve)) {
- unwrapThisSuper(ve);
- if (!isStatic(s)) result.add(ve);
+ if (matchesPartialName(e.getSimpleName(), partialName)) {
+ if (e instanceof TypeElement) {
+ var te = (TypeElement) e;
+ if (trees.isAccessible(start, te)) result.add(te);
+ } else if (isThisOrSuper(e)) {
+ if (!isStatic(s)) result.add(e);
} else {
- result.add(ve);
+ result.add(e);
}
- } else {
- result.add(e);
}
+ if (isThisOrSuper(e)) {
+ unwrapThisSuper((VariableElement) e);
+ }
+ if (result.size() >= MAX_COMPLETION_ITEMS) return;
}
} catch (Exception e) {
LOG.log(Level.WARNING, "error walking locals in scope", e);
@@ -437,8 +449,10 @@ public class JavaCompilerService {
// Walk each enclosing scope, placing its members into `results`
List<Element> walkScopes() {
+ // TODO consider limiting how many ancestors we go through, and rely on sourcepath/classpath completions
for (var s = start; s != null; s = s.getEnclosingScope()) {
walkLocals(s);
+ if (result.size() >= MAX_COMPLETION_ITEMS) return result;
}
return result;
@@ -692,7 +706,7 @@ public class JavaCompilerService {
* Complete members or identifiers at the cursor. Delegates to `members` or `scopeMembers`, depending on whether the
* expression before the cursor looks like `foo.bar` or `foo`
*/
- public CompletionResult completions(URI file, String contents, int line, int character, int limitHint) {
+ public CompletionResult completions(URI file, String contents, int line, int character) {
var started = Instant.now();
LOG.info(String.format("Completing at %s[%d,%d]...", file.getPath(), line, character));
@@ -861,7 +875,7 @@ public class JavaCompilerService {
private void addKeywords(String[] keywords, String partialName) {
for (var k : keywords) {
- if (k.startsWith(partialName)) {
+ if (matchesPartialName(k, partialName)) {
result.add(Completion.ofKeyword(k));
}
}
@@ -871,21 +885,19 @@ public class JavaCompilerService {
var startsWithUpperCase = partialName.length() > 0 && Character.isUpperCase(partialName.charAt(0));
var alreadyImported = new HashSet<String>();
// Add names that have already been imported
- for (var m : scopeMembers(file, contents, line, character)) {
- if (m.getSimpleName().toString().startsWith(partialName)) {
- result.add(Completion.ofElement(m));
+ for (var m : scopeMembers(file, contents, line, character, partialName)) {
+ result.add(Completion.ofElement(m));
- if (m instanceof TypeElement && startsWithUpperCase) {
- var t = (TypeElement) m;
- alreadyImported.add(t.getQualifiedName().toString());
- }
+ if (m instanceof TypeElement && startsWithUpperCase) {
+ var t = (TypeElement) m;
+ alreadyImported.add(t.getQualifiedName().toString());
}
}
// Add names of classes that haven't been imported
if (startsWithUpperCase) {
var packageName = Objects.toString(parse.getPackageName(), "");
BooleanSupplier full = () -> {
- if (result.size() >= limitHint) {
+ if (result.size() >= MAX_COMPLETION_ITEMS) {
isIncomplete = true;
return true;
}
@@ -894,7 +906,7 @@ public class JavaCompilerService {
Predicate<String> matchesPartialName =
qualifiedName -> {
var className = Parser.lastName(qualifiedName);
- return className.startsWith(partialName);
+ return matchesPartialName(className, partialName);
};
Predicate<String> notAlreadyImported = className -> !alreadyImported.contains(className);
for (var c : jdkClasses.classes()) {
@@ -910,7 +922,7 @@ public class JavaCompilerService {
}
}
Predicate<Path> matchesFileName =
- file -> file.getFileName().toString().startsWith(partialName);
+ file -> matchesPartialName(file.getFileName().toString(), partialName);
Predicate<Path> isPublic =
file -> {
var fileName = file.getFileName().toString();
diff --git a/src/main/java/org/javacs/JavaTextDocumentService.java b/src/main/java/org/javacs/JavaTextDocumentService.java
index e051aea..d24d959 100644
--- a/src/main/java/org/javacs/JavaTextDocumentService.java
+++ b/src/main/java/org/javacs/JavaTextDocumentService.java
@@ -81,7 +81,7 @@ class JavaTextDocumentService implements TextDocumentService {
var column = position.getPosition().getCharacter() + 1;
var result = new ArrayList<CompletionItem>();
lastCompletions.clear();
- var completions = server.compiler.completions(uri, content, line, column, 50);
+ var completions = server.compiler.completions(uri, content, line, column);
for (var c : completions.items) {
var i = new CompletionItem();
var id = UUID.randomUUID().toString();
diff --git a/src/main/java/org/javacs/README.md b/src/main/java/org/javacs/README.md
new file mode 100644
index 0000000..0453716
--- /dev/null
+++ b/src/main/java/org/javacs/README.md
@@ -0,0 +1 @@
+All classes in this directory need to be added to the list in .circleci/test.sh \ No newline at end of file
diff --git a/src/test/java/org/javacs/JavaCompilerServiceTest.java b/src/test/java/org/javacs/JavaCompilerServiceTest.java
index 43547d5..d5cf119 100644
--- a/src/test/java/org/javacs/JavaCompilerServiceTest.java
+++ b/src/test/java/org/javacs/JavaCompilerServiceTest.java
@@ -85,7 +85,11 @@ public class JavaCompilerServiceTest {
public void identifiers() {
var found =
compiler.scopeMembers(
- URI.create("/CompleteIdentifiers.java"), contents("/CompleteIdentifiers.java"), 13, 21);
+ URI.create("/CompleteIdentifiers.java"),
+ contents("/CompleteIdentifiers.java"),
+ 13,
+ 21,
+ "complete");
var names = elementNames(found);
assertThat(names, hasItem("completeLocal"));
assertThat(names, hasItem("completeParam"));
@@ -95,13 +99,14 @@ public class JavaCompilerServiceTest {
assertThat(names, hasItem("completeInnerField"));
assertThat(names, hasItem("completeOuterField"));
assertThat(names, hasItem("completeOuterStatic"));
- assertThat(names, hasItem("CompleteIdentifiers"));
+ // assertThat(names, hasItem("CompleteIdentifiers"));
}
@Test
public void identifiersInMiddle() {
var found =
- compiler.scopeMembers(URI.create("/CompleteInMiddle.java"), contents("/CompleteInMiddle.java"), 13, 21);
+ compiler.scopeMembers(
+ URI.create("/CompleteInMiddle.java"), contents("/CompleteInMiddle.java"), 13, 21, "complete");
var names = elementNames(found);
assertThat(names, hasItem("completeLocal"));
assertThat(names, hasItem("completeParam"));
@@ -111,18 +116,14 @@ public class JavaCompilerServiceTest {
assertThat(names, hasItem("completeInnerField"));
assertThat(names, hasItem("completeOuterField"));
assertThat(names, hasItem("completeOuterStatic"));
- assertThat(names, hasItem("CompleteInMiddle"));
+ // assertThat(names, hasItem("CompleteInMiddle"));
}
@Test
public void completeIdentifiers() {
var found =
compiler.completions(
- URI.create("/CompleteIdentifiers.java"),
- contents("/CompleteIdentifiers.java"),
- 13,
- 21,
- Integer.MAX_VALUE)
+ URI.create("/CompleteIdentifiers.java"), contents("/CompleteIdentifiers.java"), 13, 21)
.items;
var names = completionNames(found);
assertThat(names, hasItem("completeLocal"));
@@ -149,12 +150,7 @@ public class JavaCompilerServiceTest {
@Test
public void completeMembers() {
var found =
- compiler.completions(
- URI.create("/CompleteMembers.java"),
- contents("/CompleteMembers.java"),
- 3,
- 15,
- Integer.MAX_VALUE)
+ compiler.completions(URI.create("/CompleteMembers.java"), contents("/CompleteMembers.java"), 3, 15)
.items;
var names = completionNames(found);
assertThat(names, hasItem("subMethod"));
@@ -166,11 +162,7 @@ public class JavaCompilerServiceTest {
public void completeExpression() {
var found =
compiler.completions(
- URI.create("/CompleteExpression.java"),
- contents("/CompleteExpression.java"),
- 3,
- 37,
- Integer.MAX_VALUE)
+ URI.create("/CompleteExpression.java"), contents("/CompleteExpression.java"), 3, 37)
.items;
var names = completionNames(found);
assertThat(names, hasItem("instanceMethod"));
@@ -181,13 +173,7 @@ public class JavaCompilerServiceTest {
@Test
public void completeClass() {
var found =
- compiler.completions(
- URI.create("/CompleteClass.java"),
- contents("/CompleteClass.java"),
- 3,
- 23,
- Integer.MAX_VALUE)
- .items;
+ compiler.completions(URI.create("/CompleteClass.java"), contents("/CompleteClass.java"), 3, 23).items;
var names = completionNames(found);
assertThat(names, hasItems("staticMethod", "staticField"));
assertThat(names, hasItems("class"));
@@ -198,12 +184,7 @@ public class JavaCompilerServiceTest {
@Test
public void completeImports() {
var found =
- compiler.completions(
- URI.create("/CompleteImports.java"),
- contents("/CompleteImports.java"),
- 1,
- 18,
- Integer.MAX_VALUE)
+ compiler.completions(URI.create("/CompleteImports.java"), contents("/CompleteImports.java"), 1, 18)
.items;
var names = completionNames(found);
assertThat(names, hasItem("List"));
@@ -232,16 +213,16 @@ public class JavaCompilerServiceTest {
@Test
public void references() {
- ReportReferencesProgress rrp = new ReportReferencesProgress() {
- @Override
- public void scanForPotentialReferences(int nScanned, int nFiles) {}
-
- @Override
- public void checkPotentialReferences(int nCompiled, int nPotential) {}
- };
- var refs =
- compiler.references(
- URI.create("/GotoDefinition.java"), contents("/GotoDefinition.java"), 6, 13, rrp);
+ ReportReferencesProgress rrp =
+ new ReportReferencesProgress() {
+ @Override
+ public void scanForPotentialReferences(int nScanned, int nFiles) {}
+
+ @Override
+ public void checkPotentialReferences(int nCompiled, int nPotential) {}
+ };
+ var refs =
+ compiler.references(URI.create("/GotoDefinition.java"), contents("/GotoDefinition.java"), 6, 13, rrp);
boolean found = false;
for (var t : refs) {
var unit = t.getCompilationUnit();
@@ -291,4 +272,10 @@ public class JavaCompilerServiceTest {
compiler.fixImports(resourceUri("/MissingImport.java"), contents("/MissingImport.java")).fixedImports;
assertThat(qualifiedNames, hasItem("java.util.List"));
}
+
+ @Test
+ public void matchesPartialName() {
+ assertTrue(JavaCompilerService.matchesPartialName("foobar", "foo"));
+ assertFalse(JavaCompilerService.matchesPartialName("foo", "foobar"));
+ }
}