diff options
Diffstat (limited to 'src/main/java/org')
-rw-r--r-- | src/main/java/org/javacs/JavaCompilerService.java | 20 | ||||
-rw-r--r-- | src/main/java/org/javacs/WarnUnused.java | 63 | ||||
-rw-r--r-- | src/main/java/org/javacs/Warning.java | 70 |
3 files changed, 151 insertions, 2 deletions
diff --git a/src/main/java/org/javacs/JavaCompilerService.java b/src/main/java/org/javacs/JavaCompilerService.java index 1646ecb..3d47052 100644 --- a/src/main/java/org/javacs/JavaCompilerService.java +++ b/src/main/java/org/javacs/JavaCompilerService.java @@ -137,28 +137,44 @@ public class JavaCompilerService { public List<Diagnostic<? extends JavaFileObject>> reportErrors(Collection<URI> uris) { LOG.info(String.format("Report errors in %d files...", uris.size())); - var options = options(sourcePath, classPath); // Construct list of sources var files = new ArrayList<File>(); for (var p : uris) files.add(new File(p)); var sources = fileManager.getJavaFileObjectsFromFiles(files); + // Create task + var options = options(sourcePath, classPath); var task = (JavacTask) compiler.getTask(null, fileManager, diags::add, options, Collections.emptyList(), sources); + var trees = Trees.instance(task); + // Print timing information for optimization var profiler = new Profiler(); task.addTaskListener(profiler); + // Run compilation diags.clear(); + Iterable<? extends CompilationUnitTree> roots; try { + roots = task.parse(); task.analyze(); } catch (IOException e) { throw new RuntimeException(e); } profiler.print(); - LOG.info(String.format("...found %d errors", diags.size())); + // Check for unused privates + for (var r : roots) { + var warnUnused = new WarnUnused(task); + warnUnused.scan(r, null); + for (var unusedEl : warnUnused.notUsed()) { + var path = trees.getPath(unusedEl); + diags.add( + new Warning(task, path, "unused", String.format("`%s` is not used", unusedEl.getSimpleName()))); + } + } + return Collections.unmodifiableList(new ArrayList<>(diags)); } diff --git a/src/main/java/org/javacs/WarnUnused.java b/src/main/java/org/javacs/WarnUnused.java new file mode 100644 index 0000000..451a524 --- /dev/null +++ b/src/main/java/org/javacs/WarnUnused.java @@ -0,0 +1,63 @@ +package org.javacs; + +import com.sun.source.tree.*; +import com.sun.source.util.*; +import java.util.*; +import javax.lang.model.element.*; + +class WarnUnused extends TreePathScanner<Void, Void> { + private final Trees trees; + private final Set<Element> declared = new HashSet<>(), used = new HashSet<>(); + + WarnUnused(JavacTask task) { + this.trees = Trees.instance(task); + } + + Set<Element> notUsed() { + declared.removeAll(used); + return declared; + } + + Element current() { + return trees.getElement(getCurrentPath()); + } + + boolean isPrivate(VariableTree t) { + return t.getModifiers().getFlags().contains(Modifier.PRIVATE); + } + + boolean isLocal(VariableTree t) { + var parent = getCurrentPath().getParentPath().getLeaf(); + return !(parent instanceof ClassTree); + } + + boolean isPrivate(MethodTree t) { + return t.getModifiers().getFlags().contains(Modifier.PRIVATE); + } + + @Override + public Void visitVariable(VariableTree t, Void __) { + if (isPrivate(t) || isLocal(t)) { + declared.add(current()); + } + return super.visitVariable(t, null); + } + + @Override + public Void visitIdentifier(IdentifierTree t, Void __) { + used.add(current()); + return super.visitIdentifier(t, null); + } + + @Override + public Void visitMemberSelect(MemberSelectTree t, Void __) { + used.add(current()); + return super.visitMemberSelect(t, null); + } + + @Override + public Void visitMemberReference(MemberReferenceTree t, Void __) { + used.add(current()); + return super.visitMemberReference(t, null); + } +} diff --git a/src/main/java/org/javacs/Warning.java b/src/main/java/org/javacs/Warning.java new file mode 100644 index 0000000..a173d40 --- /dev/null +++ b/src/main/java/org/javacs/Warning.java @@ -0,0 +1,70 @@ +package org.javacs; + +import com.sun.source.tree.LineMap; +import com.sun.source.util.*; +import java.util.Locale; +import javax.tools.*; +import javax.tools.JavaFileObject; + +class Warning implements Diagnostic<JavaFileObject> { + + private final JavaFileObject source; + private final LineMap lines; + private final long start, end; + private final String code, message; + + Warning(JavacTask task, TreePath path, String code, String message) { + this.source = path.getCompilationUnit().getSourceFile(); + this.lines = path.getCompilationUnit().getLineMap(); + var pos = Trees.instance(task).getSourcePositions(); + this.start = pos.getStartPosition(path.getCompilationUnit(), path.getLeaf()); + this.end = pos.getEndPosition(path.getCompilationUnit(), path.getLeaf()); + this.code = code; + this.message = message; + } + + @Override + public Kind getKind() { + return Kind.WARNING; + } + + @Override + public JavaFileObject getSource() { + return source; + } + + @Override + public long getPosition() { + return start; + } + + @Override + public long getStartPosition() { + return start; + } + + @Override + public long getEndPosition() { + return end; + } + + @Override + public long getLineNumber() { + return lines.getLineNumber(start); + } + + @Override + public long getColumnNumber() { + return lines.getColumnNumber(start); + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getMessage(Locale locale) { + return message; + } +} |