diff options
Diffstat (limited to 'src/main/java/org/javacs/CompileFile.java')
-rw-r--r-- | src/main/java/org/javacs/CompileFile.java | 218 |
1 files changed, 0 insertions, 218 deletions
diff --git a/src/main/java/org/javacs/CompileFile.java b/src/main/java/org/javacs/CompileFile.java deleted file mode 100644 index 7d00270..0000000 --- a/src/main/java/org/javacs/CompileFile.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.javacs; - -import com.sun.source.tree.*; -import com.sun.source.util.*; -import java.io.IOException; -import java.net.URI; -import java.util.*; -import java.util.logging.Logger; -import javax.lang.model.element.*; - -public class CompileFile implements AutoCloseable { - private final JavaCompilerService parent; - public final URI file; - public final String contents; - private final TaskPool.Borrow borrow; - private final Trees trees; - public final CompilationUnitTree root; - - CompileFile(JavaCompilerService parent, URI file) { - this.parent = parent; - this.file = file; - this.contents = FileStore.contents(file); - this.borrow = CompileFocus.singleFileTask(parent, file, contents); - this.trees = Trees.instance(borrow.task); - var profiler = new Profiler(); - borrow.task.addTaskListener(profiler); - try { - this.root = borrow.task.parse().iterator().next(); - // The results of borrow.task.analyze() are unreliable when errors are present - // You can get at `Element` values using `Trees` - borrow.task.analyze(); - } catch (IOException e) { - throw new RuntimeException(e); - } - profiler.print(); - } - - @Override - public void close() { - borrow.close(); - } - - public SourcePositions sourcePositions() { - return trees.getSourcePositions(); - } - - /** - * Find all elements in `file` that get turned into code-lenses. This needs to match the result of - * `ParseFile#declarations` - */ - public List<Element> declarations() { - var paths = ParseFile.declarations(root); - var els = new ArrayList<Element>(); - for (var p : paths) { - var e = trees.getElement(p); - assert e != null; - els.add(e); - } - return els; - } - - public Index index(List<Element> declarations) { - return new Index(borrow.task, root, parent.diags, declarations); - } - - public Optional<Element> element(int line, int character) { - // LOG.info(String.format("Looking for element at %s(%d,%d)...", file.getPath(), line, character)); - - // First, look for a tree path - var path = CompileFocus.findPath(borrow.task, root, line, character); - if (path == null) { - // LOG.info("...found nothing"); - return Optional.empty(); - } - // LOG.info(String.format("...found tree `%s`", Parser.describeTree(path.getLeaf()))); - - // Then, convert the path to an element - var el = trees.getElement(path); - if (el == null) { - // LOG.info(String.format("...tree does not correspond to an element")); - return Optional.empty(); - } - - return Optional.of(el); - } - - private List<Element> overrides(ExecutableElement method) { - var elements = borrow.task.getElements(); - var types = borrow.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. - */ - public List<String> fixImports() { - // Check diagnostics for missing imports - var unresolved = new HashSet<String>(); - for (var d : parent.diags) { - if (d.getCode().equals("compiler.err.cant.resolve.location") && d.getSource().toUri().equals(file)) { - long start = d.getStartPosition(), end = d.getEndPosition(); - var id = contents.substring((int) start, (int) end); - if (id.matches("[A-Z]\\w+")) { - unresolved.add(id); - } else LOG.warning(id + " doesn't look like a class"); - } else if (d.getMessage(null).contains("cannot find to")) { - var lines = d.getMessage(null).split("\n"); - var firstLine = lines.length > 0 ? lines[0] : ""; - LOG.warning(String.format("%s %s doesn't look like to-not-found", d.getCode(), firstLine)); - } - } - // Look at imports in other classes to help us guess how to fix imports - // TODO cache parsed imports on a per-file basis - var sourcePathImports = Parser.existingImports(FileStore.all()); - var classes = new HashSet<String>(); - classes.addAll(parent.jdkClasses); - classes.addAll(parent.classPathClasses); - var fixes = Parser.resolveSymbols(unresolved, sourcePathImports, classes); - // Figure out which existing imports are actually used - var trees = Trees.instance(borrow.task); - var references = new HashSet<String>(); - class FindUsedImports extends TreePathScanner<Void, Void> { - @Override - public Void visitIdentifier(IdentifierTree node, Void nothing) { - var e = trees.getElement(getCurrentPath()); - if (e instanceof TypeElement) { - var t = (TypeElement) e; - var qualifiedName = t.getQualifiedName().toString(); - var lastDot = qualifiedName.lastIndexOf('.'); - var packageName = lastDot == -1 ? "" : qualifiedName.substring(0, lastDot); - var thisPackage = Objects.toString(root.getPackageName(), ""); - // java.lang.* and current package are imported by default - if (!packageName.equals("java.lang") - && !packageName.equals(thisPackage) - && !packageName.equals("")) { - references.add(qualifiedName); - } - } - return null; - } - } - new FindUsedImports().scan(root, null); - // Take the intersection of existing imports ^ existing identifiers - var qualifiedNames = new HashSet<String>(); - for (var i : root.getImports()) { - var imported = i.getQualifiedIdentifier().toString(); - if (imported.endsWith(".*")) { - var packageName = Parser.mostName(imported); - var isUsed = references.stream().anyMatch(r -> r.startsWith(packageName)); - if (isUsed) qualifiedNames.add(imported); - else LOG.warning("There are no references to package " + imported); - } else { - if (references.contains(imported)) qualifiedNames.add(imported); - else LOG.warning("There are no references to class " + imported); - } - } - // Add qualified names from fixes - qualifiedNames.addAll(fixes.values()); - // Sort in alphabetical order - var sorted = new ArrayList<String>(); - sorted.addAll(qualifiedNames); - Collections.sort(sorted); - return sorted; - } - - private static final Logger LOG = Logger.getLogger("main"); -} |