Skip to content

Commit

Permalink
convert to public API (#618)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arthurm1 authored Aug 17, 2023
1 parent 6f17cbe commit 4ca307a
Show file tree
Hide file tree
Showing 65 changed files with 2,036 additions and 1,807 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ public enum CompilerRange {
/** Map the compiler start/end positions to SemanticDB start/end positions. */
FROM_START_TO_END,

/**
* Map the compiler point position to SemanticDB end and use (point - symbol name length) for the
* SemanticDB start position.
*/
FROM_END_TO_SYMBOL_NAME,

/**
* Map the compiler point position to SemanticDB start and use (point + symbol name length) for
* the SemanticDB end position.
Expand Down Expand Up @@ -59,6 +65,16 @@ public boolean isFromPoint() {
}
}

public boolean isFromEndPoint() {
switch (this) {
case FROM_END_TO_SYMBOL_NAME:
case FROM_END_WITH_TEXT_SEARCH:
return true;
default:
return false;
}
}

public boolean isFromTextSearch() {
switch (this) {
case FROM_TEXT_SEARCH:
Expand All @@ -70,6 +86,15 @@ public boolean isFromTextSearch() {
}
}

public boolean isPlusOne() {
switch (this) {
case FROM_POINT_TO_SYMBOL_NAME_PLUS_ONE:
return true;
default:
return false;
}
}

public boolean isFromEnd() {
return this == CompilerRange.FROM_END_WITH_TEXT_SEARCH;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
package com.sourcegraph.semanticdb_javac;

import com.sun.tools.javac.code.Symbol;

import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import java.util.*;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.type.NoType;
import java.util.IdentityHashMap;
import java.util.ArrayList;

import static com.sourcegraph.semanticdb_javac.Debugging.pprint;

/** Cache of SemanticDB symbols that can be referenced between files. */
public final class GlobalSymbolsCache {

private final IdentityHashMap<Symbol, String> globals = new IdentityHashMap<>();
private final IdentityHashMap<Element, String> globals = new IdentityHashMap<>();
private final SemanticdbJavacOptions options;

public GlobalSymbolsCache(SemanticdbJavacOptions options) {
this.options = options;
}

public String semanticdbSymbol(Symbol sym, LocalSymbolsCache locals) {
public String semanticdbSymbol(Element sym, LocalSymbolsCache locals) {
String result = globals.get(sym);
if (result != null) return result;
String localResult = locals.get(sym);
Expand All @@ -31,33 +36,54 @@ public String semanticdbSymbol(Symbol sym, LocalSymbolsCache locals) {
return result;
}

public String semanticdbSymbol(Element element, LocalSymbolsCache locals) {
return semanticdbSymbol((Symbol) element, locals);
}

public boolean isNone(Symbol sym) {
public boolean isNone(Element sym) {
return sym == null;
}

private String uncachedSemanticdbSymbol(Symbol sym, LocalSymbolsCache locals) {
if (isNone(sym)) return SemanticdbSymbols.NONE;
String owner = semanticdbSymbol(sym.owner, locals);
if (owner.equals(SemanticdbSymbols.NONE)) {
return SemanticdbSymbols.ROOT_PACKAGE;
} else if (SemanticdbSymbols.isLocal(owner) || isAnonymousClass(sym) || isLocalVariable(sym)) {
return locals.put(sym);
}
private String uncachedSemanticdbSymbol(Element sym, LocalSymbolsCache locals) {
if (isNone(sym)) return SemanticdbSymbols.ROOT_PACKAGE;

if (sym instanceof PackageElement) {
if (((PackageElement) sym).isUnnamed()) return SemanticdbSymbols.ROOT_PACKAGE;

StringBuilder sb = new StringBuilder();
String qualifiedName = ((PackageElement) sym).getQualifiedName().toString();
int i = 0;
int j = 0;
while (j < qualifiedName.length()) {
if (i == qualifiedName.length() || qualifiedName.charAt(i) == '.') {
final String name = qualifiedName.substring(j, i);
SemanticdbSymbols.Descriptor desc =
new SemanticdbSymbols.Descriptor(SemanticdbSymbols.Descriptor.Kind.Package, name);
sb.append(desc.encode());
j = i + 1;
}
i++;
}

return sb.toString();
} else
// check for Module without referring to Module as it doesn't exist < JDK 9
if (sym.asType() instanceof NoType) return SemanticdbSymbols.ROOT_PACKAGE;

if (isAnonymousClass(sym) || isLocalVariable(sym)) return locals.put(sym);

String owner = semanticdbSymbol(sym.getEnclosingElement(), locals);
if (SemanticdbSymbols.isLocal(owner)) return locals.put(sym);

SemanticdbSymbols.Descriptor desc = semanticdbDescriptor(sym);
if (options.verboseEnabled && desc.kind == SemanticdbSymbols.Descriptor.Kind.None) {
pprint(sym.getQualifiedName().toString());
if (sym instanceof QualifiedNameable)
pprint(((QualifiedNameable) sym).getQualifiedName().toString());
else pprint(sym.getSimpleName().toString());
pprint(
String.format(
"sym: %s (%s - superclass %s)", sym, sym.getClass(), sym.getClass().getSuperclass()));
}
return SemanticdbSymbols.global(owner, desc);
}

private boolean isLocalVariable(Symbol sym) {
private boolean isLocalVariable(Element sym) {
switch (sym.getKind()) {
case PARAMETER:
case EXCEPTION_PARAMETER:
Expand All @@ -68,28 +94,25 @@ private boolean isLocalVariable(Symbol sym) {
}
}

private boolean isAnonymousClass(Symbol sym) {
return sym instanceof Symbol.ClassSymbol && sym.name.isEmpty();
private boolean isAnonymousClass(Element sym) {
return sym instanceof TypeElement && sym.getSimpleName().length() == 0;
}

private SemanticdbSymbols.Descriptor semanticdbDescriptor(Symbol sym) {
if (sym instanceof Symbol.ClassSymbol) {
private SemanticdbSymbols.Descriptor semanticdbDescriptor(Element sym) {
if (sym instanceof TypeElement) {
return new SemanticdbSymbols.Descriptor(
SemanticdbSymbols.Descriptor.Kind.Type, sym.name.toString());
} else if (sym instanceof Symbol.MethodSymbol) {
SemanticdbSymbols.Descriptor.Kind.Type, sym.getSimpleName().toString());
} else if (sym instanceof ExecutableElement) {
return new SemanticdbSymbols.Descriptor(
SemanticdbSymbols.Descriptor.Kind.Method,
sym.name.toString(),
methodDisambiguator((Symbol.MethodSymbol) sym));
} else if (sym instanceof Symbol.PackageSymbol) {
return new SemanticdbSymbols.Descriptor(
SemanticdbSymbols.Descriptor.Kind.Package, sym.name.toString());
} else if (sym instanceof Symbol.TypeVariableSymbol) {
sym.getSimpleName().toString(),
methodDisambiguator((ExecutableElement) sym));
} else if (sym instanceof TypeParameterElement) {
return new SemanticdbSymbols.Descriptor(
SemanticdbSymbols.Descriptor.Kind.TypeParameter, sym.name.toString());
} else if (sym instanceof Symbol.VarSymbol) {
SemanticdbSymbols.Descriptor.Kind.TypeParameter, sym.getSimpleName().toString());
} else if (sym instanceof VariableElement) {
return new SemanticdbSymbols.Descriptor(
SemanticdbSymbols.Descriptor.Kind.Term, sym.name.toString());
SemanticdbSymbols.Descriptor.Kind.Term, sym.getSimpleName().toString());
} else {
return SemanticdbSymbols.Descriptor.NONE;
}
Expand All @@ -113,11 +136,11 @@ private SemanticdbSymbols.Descriptor semanticdbDescriptor(Symbol sym) {
* <p><a href="https://scalameta.org/docs/semanticdb/specification.html#symbol-2">Link to
* SemanticDB spec</a>.
*/
private String methodDisambiguator(Symbol.MethodSymbol sym) {
Iterable<? extends Element> elements = sym.owner.getEnclosedElements();
private String methodDisambiguator(ExecutableElement sym) {
Iterable<? extends Element> elements = sym.getEnclosingElement().getEnclosedElements();
ArrayList<ExecutableElement> methods = new ArrayList<>();
for (Element e : elements) {
if (e instanceof ExecutableElement && e.getSimpleName() == sym.name) {
if (e instanceof ExecutableElement && e.getSimpleName() == sym.getSimpleName()) {
methods.add((ExecutableElement) e);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package com.sourcegraph.semanticdb_javac;

import com.sun.tools.javac.code.Symbol;
import javax.lang.model.element.Element;

import java.util.IdentityHashMap;

/** Cache of SemanticDB symbols that are local to a single file. */
public final class LocalSymbolsCache {

private final IdentityHashMap<Symbol, String> symbols = new IdentityHashMap<>();
private final IdentityHashMap<Element, String> symbols = new IdentityHashMap<>();
private int localsCounter = -1;

public String get(Symbol sym) {
public String get(Element sym) {
return symbols.get(sym);
}

public String put(Symbol sym) {
public String put(Element sym) {
localsCounter++;
String result = SemanticdbSymbols.local(localsCounter);
symbols.put(sym, result);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,93 @@
package com.sourcegraph.semanticdb_javac;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.LineMap;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import javax.tools.Diagnostic;

import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import java.io.IOException;
import java.util.HashMap;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.sourcegraph.semanticdb_javac.Debugging.pprint;

public class RangeFinder {
public static Optional<Semanticdb.Range> findRange(
TreePath path,
Trees trees,
CompilationUnitTree root,
public static class StartEndRange {
public int start;
public int end;

StartEndRange(int start, int end) {
this.start = start;
this.end = end;
}
}

public static Optional<StartEndRange> findRange(
Element element,
int startPos,
String name,
int originalStartPos,
int originalEndPos,
String source,
boolean fromEnd) {
LineMap lineMap = root.getLineMap();
Name name = element.getSimpleName();
if (name.contentEquals("<init>")) name = element.getEnclosingElement().getSimpleName();

int endPos = (int) trees.getSourcePositions().getEndPosition(root, path.getLeaf());
// false for anonymous classes
if (name.length() != 0) {
startPos = findNameIn(name, fromEnd ? endPos : startPos, source, fromEnd);
endPos = startPos + name.length();
}
int startPos = findNameIn(name, originalStartPos, originalEndPos, element, source, fromEnd);
int endPos = startPos + name.length();

if (endPos == -1 || startPos == -1) {
return Optional.empty();
}

Semanticdb.Range range =
Semanticdb.Range.newBuilder()
.setStartLine((int) lineMap.getLineNumber(startPos) - 1)
.setStartCharacter((int) lineMap.getColumnNumber(startPos) - 1)
.setEndLine((int) lineMap.getLineNumber(endPos) - 1)
.setEndCharacter((int) lineMap.getColumnNumber(endPos) - 1)
.build();
return Optional.of(range);
return Optional.of(new StartEndRange(startPos, endPos));
}

private static int findNameFromEnd(
String name,
int originalStartPos,
int originalEndPos,
int end,
Element element,
String source) {
if (end < 0) return -1;
int offset = source.lastIndexOf(name, end);
if (offset == -1 && originalStartPos != Diagnostic.NOPOS && originalEndPos != Diagnostic.NOPOS)
return originalStartPos;
if (offset == -1) {
return -1;
}
int endOfWord = offset + name.length();
// found name in wrong word? e.g. finding `"A"` in `A("A")`
if (offset > 0 && Character.isJavaIdentifierPart(source.charAt(offset - 1)))
return findNameFromEnd(name, originalStartPos, originalEndPos, offset - 1, element, source);
if (endOfWord < source.length() && Character.isJavaIdentifierPart(source.charAt(endOfWord)))
return findNameFromEnd(name, originalStartPos, originalEndPos, offset - 1, element, source);

return offset;
}

private static int findNameFromStart(
String name,
int start,
int originalStartPos,
int originalEndPos,
Element element,
String source) {
if (start >= source.length()) return -1;
int offset = source.indexOf(name, start);
if (offset == -1 && originalStartPos != Diagnostic.NOPOS && originalEndPos != Diagnostic.NOPOS)
return originalStartPos;
if (offset == -1) {
return -1;
}
int end = offset + name.length();
// found name in wrong word? e.g. finding `"A"` in `A("A")`
if (offset > 0 && Character.isJavaIdentifierPart(source.charAt(offset - 1)))
return findNameFromStart(name, end + 1, originalStartPos, originalEndPos, element, source);
if (end < source.length() && Character.isJavaIdentifierPart(source.charAt(end)))
return findNameFromStart(name, end + 1, originalStartPos, originalEndPos, element, source);

return offset;
}

private static int findNameIn(CharSequence name, int start, String source, boolean fromEnd) {
if (source.equals("")) return -1;
private static int findNameIn(
String name, int start, int end, Element element, String source, boolean fromEnd) {
if (source.length() == 0) return -1;

int offset;
if (fromEnd) offset = source.lastIndexOf(name.toString(), start);
else offset = source.indexOf(name.toString(), start);
if (fromEnd) offset = findNameFromEnd(name, start, start, end, element, source);
else offset = findNameFromStart(name, start, end, end, element, source);
if (offset > -1) {
return offset;
}
Expand Down
Loading

0 comments on commit 4ca307a

Please sign in to comment.