Skip to content

Commit ee732de

Browse files
committed
emit type and signature constructs for symbol definition occurences
1 parent 17a7d1d commit ee732de

File tree

7 files changed

+314
-1
lines changed

7 files changed

+314
-1
lines changed

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/Debugging.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ public static void pprint(Object any) {
77
if (any instanceof String) {
88
any = String.format("\"%s\"", any);
99
}
10-
System.out.printf("%s:%s %s%n", trace.getFileName(), trace.getLineNumber(), any);
10+
System.err.printf("%s:%s %s%n", trace.getFileName(), trace.getLineNumber(), any);
1111
}
1212
}

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/GlobalSymbolsCache.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ public String semanticdbSymbol(Symbol sym, LocalSymbolsCache locals) {
3030
return result;
3131
}
3232

33+
public String semanticdbSymbol(Element element, LocalSymbolsCache locals) {
34+
return semanticdbSymbol((Symbol) element, locals);
35+
}
36+
3337
public boolean isNone(Symbol sym) {
3438
return sym == null;
3539
}
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
package com.sourcegraph.semanticdb_javac;
2+
3+
import com.sun.tools.javac.code.Symbol;
4+
import com.sun.tools.javac.code.Type;
5+
import com.sourcegraph.semanticdb_javac.Semanticdb.*;
6+
import com.sun.tools.javac.util.List;
7+
8+
import javax.lang.model.element.Element;
9+
import javax.lang.model.element.ElementKind;
10+
import javax.lang.model.type.*;
11+
import javax.lang.model.type.IntersectionType;
12+
import javax.lang.model.util.SimpleTypeVisitor8;
13+
import java.util.ArrayList;
14+
15+
import static com.sourcegraph.semanticdb_javac.Debugging.pprint;
16+
17+
public final class SemanticdbSignatures {
18+
private final GlobalSymbolsCache cache;
19+
private final LocalSymbolsCache locals;
20+
21+
public SemanticdbSignatures(GlobalSymbolsCache cache, LocalSymbolsCache locals) {
22+
this.cache = cache;
23+
this.locals = locals;
24+
}
25+
26+
public Signature generateSignature(Symbol sym) {
27+
if (sym instanceof Symbol.ClassSymbol) {
28+
return generateClassSignature((Symbol.ClassSymbol) sym);
29+
} else if (sym instanceof Symbol.MethodSymbol) {
30+
return generateMethodSignature((Symbol.MethodSymbol) sym);
31+
} else if (sym instanceof Symbol.VarSymbol) {
32+
return generateFieldSignature((Symbol.VarSymbol) sym);
33+
} else if (sym instanceof Symbol.TypeVariableSymbol) {
34+
return generateTypeSignature((Symbol.TypeVariableSymbol) sym);
35+
}
36+
return null;
37+
}
38+
39+
private Signature generateClassSignature(Symbol.ClassSymbol sym) {
40+
ClassSignature.Builder builder = ClassSignature.newBuilder();
41+
42+
builder.setTypeParameters(generateScope(sym.getTypeParameters()));
43+
44+
if (sym.getSuperclass() != Type.noType) {
45+
builder.addParents(generateType(sym.getSuperclass()));
46+
}
47+
for (Type iType : sym.getInterfaces()) {
48+
builder.addParents(generateType(iType));
49+
}
50+
51+
Scope.Builder declarations = Scope.newBuilder();
52+
for (Symbol enclosed : sym.getEnclosedElements()) {
53+
declarations.addSymlinks(cache.semanticdbSymbol(enclosed, locals));
54+
}
55+
builder.setDeclarations(declarations);
56+
57+
return Signature.newBuilder().setClassSignature(builder).build();
58+
}
59+
60+
private Signature generateMethodSignature(Symbol.MethodSymbol sym) {
61+
MethodSignature.Builder builder = MethodSignature.newBuilder();
62+
63+
builder.setTypeParameters(generateScope(sym.getTypeParameters()));
64+
65+
builder.addParameterLists(generateScope(sym.params()));
66+
67+
Semanticdb.Type returnType = generateType(sym.getReturnType());
68+
if (returnType != null) {
69+
builder.setReturnType(returnType);
70+
}
71+
72+
return Signature.newBuilder().setMethodSignature(builder).build();
73+
}
74+
75+
private Signature generateFieldSignature(Symbol.VarSymbol sym) {
76+
if (generateType(sym.type) == null) {
77+
// pprint(generateType(sym.type) + " " + sym.type + " " + cache.semanticdbSymbol(sym,
78+
// locals));
79+
}
80+
return Signature.newBuilder()
81+
.setValueSignature(ValueSignature.newBuilder().setTpe(generateType(sym.type)))
82+
.build();
83+
}
84+
85+
private Signature generateTypeSignature(Symbol.TypeVariableSymbol sym) {
86+
TypeSignature.Builder builder = TypeSignature.newBuilder();
87+
88+
pprint(sym.type.getKind() + " " + sym);
89+
90+
builder.setTypeParameters(generateScope(sym.getTypeParameters()));
91+
92+
builder.setUpperBound(generateType(sym.type.getUpperBound()));
93+
94+
return Signature.newBuilder().setTypeSignature(builder).build();
95+
}
96+
97+
private <T extends Element> Scope generateScope(List<T> elements) {
98+
Scope.Builder scope = Scope.newBuilder();
99+
for (T typeVar : elements) {
100+
String s = cache.semanticdbSymbol(typeVar, locals);
101+
scope.addSymlinks(s);
102+
}
103+
return scope.build();
104+
}
105+
106+
private Semanticdb.Type generateType(TypeMirror mirror) {
107+
return mirror.accept(new SemanticdbTypeVisitor(cache, locals), null);
108+
}
109+
110+
/** A TypeMirror tree visitor that constructs a recursive SemanticDB Type structure. */
111+
private static class SemanticdbTypeVisitor extends SimpleTypeVisitor8<Semanticdb.Type, Void> {
112+
private final GlobalSymbolsCache cache;
113+
private final LocalSymbolsCache locals;
114+
115+
private SemanticdbTypeVisitor(GlobalSymbolsCache cache, LocalSymbolsCache locals) {
116+
this.cache = cache;
117+
this.locals = locals;
118+
}
119+
120+
@Override
121+
public Semanticdb.Type visitDeclared(DeclaredType t, Void unused) {
122+
boolean isExistential =
123+
t.getTypeArguments().stream().anyMatch((type) -> type instanceof WildcardType);
124+
125+
ArrayList<Semanticdb.Type> typeParams = new ArrayList<>();
126+
for (TypeMirror type : t.getTypeArguments()) {
127+
Semanticdb.Type visit = super.visit(type);
128+
if (visit == null) {
129+
pprint(type + " " + visit + " " + type.getClass());
130+
continue;
131+
}
132+
typeParams.add(visit);
133+
}
134+
135+
if (!isExistential) {
136+
return Semanticdb.Type.newBuilder()
137+
.setTypeRef(
138+
TypeRef.newBuilder()
139+
.setSymbol(cache.semanticdbSymbol(t.asElement(), locals))
140+
.addAllTypeArguments(typeParams))
141+
.build();
142+
} else {
143+
return Semanticdb.Type.newBuilder()
144+
.setExistentialType(
145+
ExistentialType.newBuilder()
146+
.setTpe(
147+
Semanticdb.Type.newBuilder()
148+
.setTypeRef(
149+
TypeRef.newBuilder()
150+
.setSymbol(cache.semanticdbSymbol(t.asElement(), locals))
151+
.addAllTypeArguments(typeParams))))
152+
.build();
153+
}
154+
}
155+
156+
@Override
157+
public Semanticdb.Type visitArray(ArrayType t, Void unused) {
158+
return Semanticdb.Type.newBuilder()
159+
.setTypeRef(
160+
TypeRef.newBuilder()
161+
.setSymbol("scala/Array#")
162+
.addTypeArguments(super.visit(t.getComponentType())))
163+
.build();
164+
}
165+
166+
@Override
167+
public Semanticdb.Type visitPrimitive(PrimitiveType t, Void unused) {
168+
return Semanticdb.Type.newBuilder()
169+
.setTypeRef(TypeRef.newBuilder().setSymbol(primitiveSymbol(t.getKind())))
170+
.build();
171+
}
172+
173+
@Override
174+
public Semanticdb.Type visitTypeVariable(TypeVariable t, Void unused) {
175+
return Semanticdb.Type.newBuilder()
176+
.setTypeRef(
177+
TypeRef.newBuilder().setSymbol(cache.semanticdbSymbol(t.asElement(), locals)).build())
178+
.build();
179+
}
180+
181+
@Override
182+
public Semanticdb.Type visitIntersection(IntersectionType t, Void unused) {
183+
ArrayList<Semanticdb.Type> types = new ArrayList<>();
184+
for (TypeMirror type : t.getBounds()) {
185+
types.add(super.visit(type));
186+
}
187+
188+
return Semanticdb.Type.newBuilder()
189+
.setIntersectionType(Semanticdb.IntersectionType.newBuilder().addAllTypes(types).build())
190+
.build();
191+
}
192+
193+
@Override
194+
public Semanticdb.Type visitWildcard(WildcardType t, Void unused) {
195+
new Exception().printStackTrace();
196+
return Semanticdb.Type.newBuilder()
197+
.setExistentialType(ExistentialType.newBuilder().build())
198+
.build();
199+
}
200+
201+
public String primitiveSymbol(TypeKind kind) {
202+
switch (kind) {
203+
case BOOLEAN:
204+
return "scala/Boolean#";
205+
case BYTE:
206+
return "scala/Byte#";
207+
case SHORT:
208+
return "scala/Short#";
209+
case INT:
210+
return "scala/Int#";
211+
case LONG:
212+
return "scala/Long#";
213+
case CHAR:
214+
return "scala/Char#";
215+
case FLOAT:
216+
return "scala/Float#";
217+
case DOUBLE:
218+
return "scala/Double#";
219+
case VOID:
220+
return "scala/Unit#";
221+
default:
222+
throw new IllegalArgumentException("got " + kind.name());
223+
}
224+
}
225+
}
226+
}

semanticdb-javac/src/main/java/com/sourcegraph/semanticdb_javac/SemanticdbVisitor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.Iterator;
2222
import java.util.Optional;
2323

24+
import static com.sourcegraph.semanticdb_javac.Debugging.pprint;
25+
2426
/** Walks the AST of a typechecked compilation unit and generates a SemanticDB TextDocument. */
2527
public class SemanticdbVisitor extends TreePathScanner<Void, Void> {
2628

@@ -54,6 +56,7 @@ public SemanticdbVisitor(
5456
}
5557

5658
public Semanticdb.TextDocument buildTextDocument(CompilationUnitTree tree) {
59+
// pprint(semanticdbUri());
5760
this.scan(tree, null); // Trigger recursive AST traversal to collect SemanticDB information.
5861

5962
return Semanticdb.TextDocument.newBuilder()
@@ -80,6 +83,7 @@ private void emitSymbolOccurrence(
8083
private void emitSymbolInformation(Symbol sym) {
8184
Semanticdb.SymbolInformation.Builder builder =
8285
Semanticdb.SymbolInformation.newBuilder().setSymbol(semanticdbSymbol(sym));
86+
// .setSignature(semanticdbSignature(sym));
8387
Semanticdb.Documentation documentation = semanticdbDocumentation(sym);
8488
if (documentation != null) builder.setDocumentation(documentation);
8589

@@ -179,6 +183,10 @@ public Void visitNewClass(NewClassTree node, Void unused) {
179183
// Utilities to generate SemanticDB data structures.
180184
// =================================================
181185

186+
private Semanticdb.Signature semanticdbSignature(Symbol sym) {
187+
return new SemanticdbSignatures(globals, locals).generateSignature(sym);
188+
}
189+
182190
private String semanticdbSymbol(Symbol sym) {
183191
return globals.semanticdbSymbol(sym, locals);
184192
}

semanticdb-javac/src/main/protobuf/semanticdb.proto

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,36 @@ message Range {
4141
int32 end_character = 4;
4242
}
4343

44+
message Signature {
45+
oneof sealed_value {
46+
ClassSignature class_signature = 1;
47+
MethodSignature method_signature = 2;
48+
TypeSignature type_signature = 3;
49+
ValueSignature value_signature = 4;
50+
}
51+
}
52+
53+
message ClassSignature {
54+
Scope type_parameters = 1;
55+
repeated Type parents = 2;
56+
Scope declarations = 4;
57+
}
58+
59+
message MethodSignature {
60+
Scope type_parameters = 1;
61+
repeated Scope parameter_lists = 2;
62+
Type return_type = 3;
63+
}
64+
65+
message TypeSignature {
66+
Scope type_parameters = 1;
67+
Type upper_bound = 3;
68+
}
69+
70+
message ValueSignature {
71+
Type tpe = 1;
72+
}
73+
4474
message SymbolInformation {
4575
enum Kind {
4676
reserved 1, 2, 4, 5, 15, 16;
@@ -86,6 +116,7 @@ message SymbolInformation {
86116
Kind kind = 3;
87117
int32 properties = 4;
88118
string display_name = 5;
119+
Signature signature = 17;
89120
repeated string overridden_symbols = 19;
90121
Documentation documentation = 20;
91122
}
@@ -113,3 +144,30 @@ message SymbolOccurrence {
113144
Role role = 3;
114145
}
115146

147+
message Scope {
148+
repeated string symlinks = 1;
149+
}
150+
151+
message Type {
152+
reserved 1, 3, 4, 5, 6, 11, 12, 15, 16;
153+
oneof sealed_value {
154+
TypeRef type_ref = 2;
155+
IntersectionType intersection_type = 17;
156+
ExistentialType existential_type = 9;
157+
}
158+
}
159+
160+
message TypeRef {
161+
Type prefix = 1;
162+
string symbol = 2;
163+
repeated Type type_arguments = 3;
164+
}
165+
message IntersectionType {
166+
repeated Type types = 1;
167+
}
168+
169+
message ExistentialType {
170+
reserved 2;
171+
Type tpe = 1;
172+
Scope declarations = 3;
173+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package minimized;
22

3+
import java.util.List;
4+
35
public class ParameterizedTypes<A, B> {
6+
//Class<?> clazz;
7+
48
public String app(A a, B b) {
59
return a.toString() + b;
610
}
11+
12+
public List<?> doStuff() { return null; }
713
}

tests/snapshots/src/main/generated/minimized/ParameterizedTypes.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package minimized;
22

3+
import java.util.List;
4+
// ^^^^ reference java/
5+
// ^^^^ reference java/util/
6+
// ^^^^ reference java/util/List#
7+
38
public class ParameterizedTypes<A, B> {
49
// ^^^^^^^^^^^^^^^^^^ definition minimized/ParameterizedTypes#
510
// ^^^^^^^^^^^^^^^^^^ definition minimized/ParameterizedTypes#`<init>`().
611
// ^ definition minimized/ParameterizedTypes#[A]
712
// ^ definition minimized/ParameterizedTypes#[B]
13+
//Class<?> clazz;
14+
815
public String app(A a, B b) {
916
// ^^^^^^ reference java/lang/String#
1017
// ^^^ definition minimized/ParameterizedTypes#app().
@@ -17,4 +24,8 @@ public String app(A a, B b) {
1724
// ^^^^^^^^ reference java/lang/Object#toString().
1825
// ^ reference local1
1926
}
27+
28+
public List<?> doStuff() { return null; }
29+
// ^^^^ reference java/util/List#
30+
// ^^^^^^^ definition minimized/ParameterizedTypes#doStuff().
2031
}

0 commit comments

Comments
 (0)