diff options
author | George Fraser <george@fivetran.com> | 2018-12-31 16:05:09 -0800 |
---|---|---|
committer | George Fraser <george@fivetran.com> | 2018-12-31 16:05:09 -0800 |
commit | 25c67bb8f300f8af13b7312933dec157e67e678c (patch) | |
tree | 4eb2076b4da8571fe59338c7185b6aa63963e467 | |
parent | 8f63f14f980f44af2c5747747320703819ebc402 (diff) | |
download | java-language-server-25c67bb8f300f8af13b7312933dec157e67e678c.zip |
Add @Override
-rw-r--r-- | TODOS.md | 5 | ||||
-rw-r--r-- | src/main/java/org/javacs/CompileFile.java | 56 | ||||
-rw-r--r-- | src/main/java/org/javacs/JavaCompilerService.java | 3 | ||||
-rw-r--r-- | src/main/java/org/javacs/JavaLanguageServer.java | 28 | ||||
-rw-r--r-- | src/test/java/org/javacs/FormattingTest.java | 28 | ||||
-rw-r--r-- | src/test/test-project/workspace/src/org/javacs/example/AddOverride.java | 7 |
6 files changed, 123 insertions, 4 deletions
@@ -29,7 +29,4 @@ # Coloring - new Foo< shouldn't make everything green - void f() shouldn't mess up next line as you type it -- { on next line breaks coloring - -# Formatter -- Automatically add @Override annotations
\ No newline at end of file +- { on next line breaks coloring
\ No newline at end of file diff --git a/src/main/java/org/javacs/CompileFile.java b/src/main/java/org/javacs/CompileFile.java index c26337d..9ed833c 100644 --- a/src/main/java/org/javacs/CompileFile.java +++ b/src/main/java/org/javacs/CompileFile.java @@ -122,6 +122,62 @@ public class CompileFile { return ParseFile.range(task, contents, path); } + private List<Element> overrides(ExecutableElement method) { + var elements = task.getElements(); + var types = task.getTypes(); + var results = new ArrayList<Element>(); + var enclosingClass = (TypeElement) method.getEnclosingElement(); + var enclosingType = enclosingClass.asType(); + for (var superClass : types.directSupertypes(enclosingType)) { + var e = (TypeElement) types.asElement(superClass); + for (var other : e.getEnclosedElements()) { + if (!(other instanceof ExecutableElement)) continue; + if (elements.overrides(method, (ExecutableElement) other, enclosingClass)) { + results.add(other); + } + } + } + return results; + } + + private boolean hasOverrideAnnotation(ExecutableElement method) { + for (var ann : method.getAnnotationMirrors()) { + var type = ann.getAnnotationType(); + var el = type.asElement(); + var name = el.toString(); + if (name.equals("java.lang.Override")) { + return true; + } + } + return false; + } + + /** Find methods that override a method from a superclass but don't have an @Override annotation. */ + public List<TreePath> needsOverrideAnnotation() { + LOG.info(String.format("Looking for methods that need an @Override annotation in %s ...", file.getPath())); + + var results = new ArrayList<TreePath>(); + class FindMissingOverride extends TreePathScanner<Void, Void> { + @Override + public Void visitMethod(MethodTree t, Void __) { + var method = (ExecutableElement) trees.getElement(getCurrentPath()); + var supers = overrides(method); + if (!supers.isEmpty() && !hasOverrideAnnotation(method)) { + var overridesMethod = supers.get(0); + var overridesClass = overridesMethod.getEnclosingElement(); + LOG.info( + String.format( + "...`%s` has no @Override annotation but overrides `%s.%s`", + method, overridesClass, overridesMethod)); + results.add(getCurrentPath()); + } + return super.visitMethod(t, null); + } + } + new FindMissingOverride().scan(root, null); + return results; + } + /** * Figure out what imports this file should have. Star-imports like `import java.util.*` are converted to individual * class imports. Missing imports are inferred by looking at imports in other source files. diff --git a/src/main/java/org/javacs/JavaCompilerService.java b/src/main/java/org/javacs/JavaCompilerService.java index e771538..2c6aa83 100644 --- a/src/main/java/org/javacs/JavaCompilerService.java +++ b/src/main/java/org/javacs/JavaCompilerService.java @@ -367,6 +367,9 @@ public class JavaCompilerService { index.putAll(counts); } + // TODO when computing the index, store the signature of the target. + // If the target has changed, reindex that file. + // This can take advantage of the fact that code lenses are resolved one-at-a-time! public Map<Ptr, Integer> countReferences(URI file, String contents, ReportProgress progress) { var root = Parser.parse(new StringFileObject(contents, file)); // List all files that import file diff --git a/src/main/java/org/javacs/JavaLanguageServer.java b/src/main/java/org/javacs/JavaLanguageServer.java index 30b869a..7bfa3a5 100644 --- a/src/main/java/org/javacs/JavaLanguageServer.java +++ b/src/main/java/org/javacs/JavaLanguageServer.java @@ -1016,6 +1016,14 @@ class JavaLanguageServer extends LanguageServer { @Override public List<TextEdit> formatting(DocumentFormattingParams params) { updateHoverCache(params.textDocument.uri, contents(params.textDocument.uri).content); + + var edits = new ArrayList<TextEdit>(); + edits.addAll(fixImports()); + edits.addAll(addOverrides()); + return edits; + } + + private List<TextEdit> fixImports() { // TODO if imports already match fixed-imports, return empty list // TODO preserve comments and other details of existing imports var imports = hoverCache.fixImports(); @@ -1063,6 +1071,26 @@ class JavaLanguageServer extends LanguageServer { return edits; } + private List<TextEdit> addOverrides() { + var edits = new ArrayList<TextEdit>(); + var methods = hoverCache.needsOverrideAnnotation(); + var pos = hoverCache.sourcePositions(); + var lines = hoverCache.root.getLineMap(); + for (var t : methods) { + var methodStart = pos.getStartPosition(t.getCompilationUnit(), t.getLeaf()); + var insertLine = lines.getLineNumber(methodStart); + var indent = methodStart - lines.getPosition(insertLine, 0); + var insertText = new StringBuilder(); + for (var i = 0; i < indent; i++) insertText.append(' '); + insertText.append("@Override"); + insertText.append('\n'); + var insertPosition = new Position((int) insertLine, 0); + var insert = new TextEdit(new Range(insertPosition, insertPosition), insertText.toString()); + edits.add(insert); + } + return edits; + } + @Override public List<FoldingRange> foldingRange(FoldingRangeParams params) { updateCachedParse(params.textDocument.uri); diff --git a/src/test/java/org/javacs/FormattingTest.java b/src/test/java/org/javacs/FormattingTest.java new file mode 100644 index 0000000..97974a4 --- /dev/null +++ b/src/test/java/org/javacs/FormattingTest.java @@ -0,0 +1,28 @@ +package org.javacs; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.List; +import org.javacs.lsp.DocumentFormattingParams; +import org.javacs.lsp.TextDocumentIdentifier; +import org.javacs.lsp.TextEdit; +import org.junit.Test; + +public class FormattingTest { + + private static final JavaLanguageServer server = LanguageServerFixture.getJavaLanguageServer(); + + private List<TextEdit> formatting(String file) { + var uri = FindResource.uri(file); + var params = new DocumentFormattingParams(); + params.textDocument = new TextDocumentIdentifier(uri); + return server.formatting(params); + } + + @Test + public void addOverride() { + var edits = formatting("/org/javacs/example/AddOverride.java"); + assertThat(edits, not(empty())); + } +} diff --git a/src/test/test-project/workspace/src/org/javacs/example/AddOverride.java b/src/test/test-project/workspace/src/org/javacs/example/AddOverride.java new file mode 100644 index 0000000..d2fc1d2 --- /dev/null +++ b/src/test/test-project/workspace/src/org/javacs/example/AddOverride.java @@ -0,0 +1,7 @@ +package org.javacs.example; + +class AddOverride implements Runnable { + public void run() { + // Nothing to do + } +}
\ No newline at end of file |