Skip to content

Commit bf4ca0c

Browse files
authored
Merge pull request #557 from sourcegraph/olafurpg/scip-gap
Close SCIP/LSIF feature gap
2 parents dbb7d6a + 2bc9b3e commit bf4ca0c

19 files changed

+718
-453
lines changed

scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipSemanticdb.java

+106-71
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ private void runTyped(List<Path> files, PackageTable packages) {
6868
}
6969

7070
private String typedSymbol(String symbol, Package pkg) {
71+
if (symbol.isEmpty()) {
72+
return "";
73+
}
7174
if (symbol.startsWith("local")) {
7275
return "local " + symbol.substring("local".length());
7376
}
@@ -91,6 +94,9 @@ private void processTypedDocument(Path path, PackageTable packages) {
9194
.collect(Collectors.joining("/"));
9295
Scip.Document.Builder tdoc = Scip.Document.newBuilder().setRelativePath(relativePath);
9396
for (SymbolOccurrence occ : doc.sortedSymbolOccurrences()) {
97+
if (occ.getSymbol().isEmpty()) {
98+
continue;
99+
}
94100
int role = 0;
95101
if (isDefinitionRole(occ.getRole())) {
96102
role |= Scip.SymbolRole.Definition_VALUE;
@@ -116,12 +122,35 @@ private void processTypedDocument(Path path, PackageTable packages) {
116122
}
117123
Symtab symtab = new Symtab(doc.semanticdb);
118124
for (SymbolInformation info : doc.semanticdb.getSymbolsList()) {
125+
if (info.getSymbol().isEmpty()) {
126+
continue;
127+
}
119128
Package pkg = packages.packageForSymbol(info.getSymbol()).orElse(Package.EMPTY);
120129
Scip.SymbolInformation.Builder tinfo =
121130
Scip.SymbolInformation.newBuilder().setSymbol(typedSymbol(info.getSymbol(), pkg));
122131

132+
for (int i = 0; i < info.getDefinitionRelationshipsCount(); i++) {
133+
String definitionSymbol = info.getDefinitionRelationships(i);
134+
if (definitionSymbol.isEmpty()) {
135+
continue;
136+
}
137+
Package definitionSymbolPkg =
138+
packages.packageForSymbol(definitionSymbol).orElse(Package.EMPTY);
139+
SymbolInformation definitionInfo = symtab.symbols.get(definitionSymbol);
140+
tinfo.addRelationships(
141+
Scip.Relationship.newBuilder()
142+
.setSymbol(typedSymbol(definitionSymbol, definitionSymbolPkg))
143+
.setIsDefinition(true)
144+
.setIsReference(
145+
definitionInfo != null
146+
&& definitionInfo.getDisplayName().equals(info.getDisplayName())
147+
&& supportsReferenceRelationship(info)));
148+
}
123149
for (int i = 0; i < info.getOverriddenSymbolsCount(); i++) {
124150
String overriddenSymbol = info.getOverriddenSymbols(i);
151+
if (overriddenSymbol.isEmpty()) {
152+
continue;
153+
}
125154
if (isIgnoredOverriddenSymbol(overriddenSymbol)) {
126155
continue;
127156
}
@@ -225,82 +254,85 @@ private Integer processDocumentUnsafe(
225254
Set<Integer> rangeIds = new LinkedHashSet<>();
226255

227256
for (SymbolOccurrence occ : doc.sortedSymbolOccurrences()) {
228-
SymbolInformation symbolInformation =
229-
doc.symbols.getOrDefault(occ.getSymbol(), SymbolInformation.getDefaultInstance());
230-
ResultIds ids = results.getOrInsertResultSet(occ.getSymbol());
231-
int rangeId = writer.emitRange(occ.getRange());
232-
rangeIds.add(rangeId);
233-
234-
// Range
235-
if (occ.getRole() != Role.SYNTHETIC_DEFINITION) {
236-
writer.emitNext(rangeId, ids.resultSet);
237-
}
238-
239-
// Reference
240-
writer.emitItem(ids.referenceResult, rangeId, doc.id);
241-
242-
// Definition
243-
if (isDefinitionRole(occ.getRole())) {
244-
if (ids.isDefinitionDefined()) {
245-
writer.emitItem(ids.definitionResult, rangeId, doc.id);
246-
} else {
247-
options.reporter.error(
248-
new NoSuchElementException(
249-
String.format("no definition ID for symbol '%s'", occ.getSymbol())));
257+
for (String symbol : occ.getSymbol().split(";")) {
258+
SymbolInformation symbolInformation =
259+
doc.symbols.getOrDefault(symbol, SymbolInformation.getDefaultInstance());
260+
ResultIds ids = results.getOrInsertResultSet(symbol);
261+
int rangeId = writer.emitRange(occ.getRange());
262+
rangeIds.add(rangeId);
263+
264+
// Range
265+
if (occ.getRole() != Role.SYNTHETIC_DEFINITION) {
266+
writer.emitNext(rangeId, ids.resultSet);
250267
}
251268

252-
// Hover 1: signature
253-
String documentation = symbolInformation.getDocumentation().getMessage();
254-
StringBuilder markupContent = new StringBuilder(documentation.length());
255-
if (symbolInformation.hasSignature()) {
256-
String language =
257-
doc.semanticdb.getLanguage().toString().toLowerCase(Locale.ROOT).intern();
258-
String signature = new SignatureFormatter(symbolInformation, symtab).formatSymbol();
259-
markupContent
260-
.append("```")
261-
.append(language)
262-
.append('\n')
263-
.append(signature)
264-
.append("\n```");
265-
}
269+
// Reference
270+
writer.emitItem(ids.referenceResult, rangeId, doc.id);
266271

267-
// Hover 2: docstring
268-
if (!documentation.isEmpty()) {
269-
if (markupContent.length() != 0) markupContent.append("\n---\n");
270-
markupContent.append(documentation.replaceAll("\n", "\n\n"));
271-
}
272+
// Definition
273+
if (isDefinitionRole(occ.getRole())) {
274+
if (ids.isDefinitionDefined()) {
275+
writer.emitItem(ids.definitionResult, rangeId, doc.id);
276+
} else {
277+
options.reporter.error(
278+
new NoSuchElementException(
279+
String.format("no definition ID for symbol '%s'", symbol)));
280+
}
272281

273-
if (markupContent.length() == 0) {
274-
// Always emit a non-empty hover message to prevent Sourcegraph from falling back to
275-
// Search-Based hover messages.
276-
markupContent.append(symbolInformation.getDisplayName());
277-
}
282+
// Hover 1: signature
283+
String documentation = symbolInformation.getDocumentation().getMessage();
284+
StringBuilder markupContent = new StringBuilder(documentation.length());
285+
if (symbolInformation.hasSignature()) {
286+
String language =
287+
doc.semanticdb.getLanguage().toString().toLowerCase(Locale.ROOT).intern();
288+
String signature = new SignatureFormatter(symbolInformation, symtab).formatSymbol();
289+
markupContent
290+
.append("```")
291+
.append(language)
292+
.append('\n')
293+
.append(signature)
294+
.append("\n```");
295+
}
278296

279-
int hoverId =
280-
writer.emitHoverResult(
281-
new MarkupContent(MarkupKind.MARKDOWN, markupContent.toString()));
282-
writer.emitHoverEdge(ids.resultSet, hoverId);
283-
}
297+
// Hover 2: docstring
298+
if (!documentation.isEmpty()) {
299+
if (markupContent.length() != 0) markupContent.append("\n---\n");
300+
markupContent.append(documentation.replaceAll("\n", "\n\n"));
301+
}
284302

285-
// Overrides
286-
if (symbolInformation.getOverriddenSymbolsCount() > 0
287-
&& supportsReferenceRelationship(symbolInformation)
288-
&& occ.getRole() == Role.DEFINITION) {
289-
List<Integer> overriddenReferenceResultIds =
290-
new ArrayList<>(symbolInformation.getOverriddenSymbolsCount());
291-
for (int i = 0; i < symbolInformation.getOverriddenSymbolsCount(); i++) {
292-
String overriddenSymbol = symbolInformation.getOverriddenSymbols(i);
293-
if (isIgnoredOverriddenSymbol(overriddenSymbol)) {
294-
continue;
303+
if (markupContent.length() == 0) {
304+
// Always emit a non-empty hover message to prevent Sourcegraph from falling
305+
// back to
306+
// Search-Based hover messages.
307+
markupContent.append(symbolInformation.getDisplayName());
295308
}
296-
ResultIds overriddenIds = results.getOrInsertResultSet(overriddenSymbol);
297-
overriddenReferenceResultIds.add(overriddenIds.referenceResult);
298-
writer.emitReferenceResultsItemEdge(
299-
overriddenIds.referenceResult, Collections.singletonList(rangeId), doc.id);
309+
310+
int hoverId =
311+
writer.emitHoverResult(
312+
new MarkupContent(MarkupKind.MARKDOWN, markupContent.toString()));
313+
writer.emitHoverEdge(ids.resultSet, hoverId);
300314
}
301-
if (overriddenReferenceResultIds.size() > 0) {
302-
writer.emitReferenceResultsItemEdge(
303-
ids.referenceResult, overriddenReferenceResultIds, doc.id);
315+
316+
// Overrides
317+
if (symbolInformation.getOverriddenSymbolsCount() > 0
318+
&& supportsReferenceRelationship(symbolInformation)
319+
&& occ.getRole() == Role.DEFINITION) {
320+
List<Integer> overriddenReferenceResultIds =
321+
new ArrayList<>(symbolInformation.getOverriddenSymbolsCount());
322+
for (int i = 0; i < symbolInformation.getOverriddenSymbolsCount(); i++) {
323+
String overriddenSymbol = symbolInformation.getOverriddenSymbols(i);
324+
if (isIgnoredOverriddenSymbol(overriddenSymbol)) {
325+
continue;
326+
}
327+
ResultIds overriddenIds = results.getOrInsertResultSet(overriddenSymbol);
328+
overriddenReferenceResultIds.add(overriddenIds.referenceResult);
329+
writer.emitReferenceResultsItemEdge(
330+
overriddenIds.referenceResult, Collections.singletonList(rangeId), doc.id);
331+
}
332+
if (overriddenReferenceResultIds.size() > 0) {
333+
writer.emitReferenceResultsItemEdge(
334+
ids.referenceResult, overriddenReferenceResultIds, doc.id);
335+
}
304336
}
305337
}
306338
}
@@ -363,16 +395,19 @@ private Semanticdb.TextDocuments textDocumentsParseFromBytes(byte[] bytes) throw
363395
in.setRecursionLimit(1000);
364396
return Semanticdb.TextDocuments.parseFrom(in);
365397
} catch (NoSuchMethodError ignored) {
366-
// NOTE(olafur): For some reason, NoSuchMethodError gets thrown when running `snapshots/run`
367-
// in the sbt build. I'm unable to reproduce the error in `snapshots/test` or when running the
398+
// NOTE(olafur): For some reason, NoSuchMethodError gets thrown when running
399+
// `snapshots/run`
400+
// in the sbt build. I'm unable to reproduce the error in `snapshots/test` or
401+
// when running the
368402
// published version
369403
// of `scip-java index`.
370404
return Semanticdb.TextDocuments.parseFrom(bytes);
371405
}
372406
}
373407

374408
private boolean isIgnoredOverriddenSymbol(String symbol) {
375-
// Skip java/lang/Object# and similar symbols from Scala since it's the parent of all classes
409+
// Skip java/lang/Object# and similar symbols from Scala since it's the parent
410+
// of all classes
376411
// making it noisy for "find implementations" results.
377412
return symbol.equals("java/lang/Object#");
378413
}

scip-semanticdb/src/main/java/com/sourcegraph/scip_semanticdb/ScipTextDocument.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -87,29 +87,29 @@ public static Semanticdb.TextDocument manifestOccurrencesForSyntheticSymbols(
8787
return semanticdb;
8888
}
8989
Semanticdb.TextDocument.Builder builder = Semanticdb.TextDocument.newBuilder(semanticdb);
90+
builder.clearSymbols();
9091
HashMap<String, Semanticdb.SymbolOccurrence> definitionOccurrences = new HashMap<>();
9192
for (Semanticdb.SymbolOccurrence occ : semanticdb.getOccurrencesList()) {
9293
if (occ.getRole() == Semanticdb.SymbolOccurrence.Role.DEFINITION) {
9394
definitionOccurrences.put(occ.getSymbol(), occ);
9495
}
9596
}
9697
for (Semanticdb.SymbolInformation info : semanticdb.getSymbolsList()) {
98+
Semanticdb.SymbolInformation.Builder newInfo = Semanticdb.SymbolInformation.newBuilder(info);
9799
Semanticdb.SymbolOccurrence definition = definitionOccurrences.get(info.getSymbol());
98100
if (definition != null) {
101+
builder.addSymbols(newInfo);
99102
continue;
100103
}
101104
for (Semanticdb.SymbolOccurrence alternativeSymbol : alternativeSymbols(info)) {
102105
Semanticdb.SymbolOccurrence alternativeDefinition =
103106
definitionOccurrences.get(alternativeSymbol.getSymbol());
104107
if (alternativeDefinition != null) {
105-
builder.addOccurrences(
106-
Semanticdb.SymbolOccurrence.newBuilder()
107-
.setRange(alternativeDefinition.getRange())
108-
.setRole(alternativeSymbol.getRole())
109-
.setSymbol(info.getSymbol()));
108+
newInfo.addDefinitionRelationships(alternativeDefinition.getSymbol());
110109
break;
111110
}
112111
}
112+
builder.addSymbols(newInfo);
113113
}
114114
return builder.build();
115115
}

tests/snapshots/src/main/generated/BaseByteRenderer.scala

+17-11
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,35 @@ import upickle.core.{ArrVisitor, ObjVisitor}
2424
class BaseByteRenderer[T <: upickle.core.ByteOps.Output]
2525
// ^^^^^^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#
2626
// documentation ```scala\nclass BaseByteRenderer[T <: Output]\n```
27-
// ^^^^^^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer.
27+
// ________________ synthetic_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer.
2828
// documentation ```scala\nobject BaseByteRenderer\n```
29+
// relationship is_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#
2930
// ^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#[T]
3031
// documentation ```scala\nT <: Output\n```
3132
// ^^^^^^^ reference semanticdb maven . . upickle/
3233
// ^^^^ reference semanticdb maven . . upickle/core/
3334
// ^^^^^^^ reference semanticdb maven maven/com.lihaoyi/upickle-core_2.13 1.4.0 upickle/core/ByteOps.
3435
// ^^^^^^ reference semanticdb maven maven/com.lihaoyi/upickle-core_2.13 1.4.0 upickle/core/ByteOps.Output#
3536
(out: T,
36-
// ^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`<init>`().(out)
37-
// documentation ```scala\nout: T \n```
3837
// ^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#out.
3938
// documentation ```scala\nprivate[this] val out: T\n```
39+
// ___ synthetic_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`<init>`().(out)
40+
// documentation ```scala\nout: T \n```
41+
// relationship is_reference is_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#out.
4042
// ^ reference semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#[T]
4143
indent: Int = -1,
42-
// ^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`<init>`().(indent)
43-
// documentation ```scala\ndefault indent: Int \n```
4444
// ^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#indent.
4545
// documentation ```scala\nprivate[this] val indent: Int\n```
46+
// ______ synthetic_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`<init>`().(indent)
47+
// documentation ```scala\ndefault indent: Int \n```
48+
// relationship is_reference is_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#indent.
4649
// ^^^ reference semanticdb maven maven/org.scala-lang/scala-library 2.13.10 scala/Int#
4750
escapeUnicode: Boolean = false) extends JsVisitor[T, T]{
48-
// ^^^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`<init>`().(escapeUnicode)
49-
// documentation ```scala\ndefault escapeUnicode: Boolean \n```
5051
// ^^^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#escapeUnicode.
5152
// documentation ```scala\nprivate[this] val escapeUnicode: Boolean\n```
53+
// _____________ synthetic_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`<init>`().(escapeUnicode)
54+
// documentation ```scala\ndefault escapeUnicode: Boolean \n```
55+
// relationship is_reference is_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#escapeUnicode.
5256
// ^^^^^^^ reference semanticdb maven maven/org.scala-lang/scala-library 2.13.10 scala/Boolean#
5357
// ^^^^^^^^^ reference semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/JsVisitor#
5458
// ^ reference semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#[T]
@@ -80,18 +84,20 @@ class BaseByteRenderer[T <: upickle.core.ByteOps.Output]
8084
}
8185

8286
private[this] var depth: Int = 0
83-
// ^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`depth_=`().
84-
// documentation ```scala\nprivate[this] var depth_=(x$1: Int): Unit\n```
8587
// ^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#depth().
8688
// documentation ```scala\nprivate[this] var depth: Int\n```
89+
// _____ synthetic_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`depth_=`().
90+
// documentation ```scala\nprivate[this] var depth_=(x$1: Int): Unit\n```
91+
// relationship is_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#depth().
8792
// ^^^ reference semanticdb maven maven/org.scala-lang/scala-library 2.13.10 scala/Int#
8893

8994

9095
private[this] var commaBuffered = false
91-
// ^^^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`commaBuffered_=`().
92-
// documentation ```scala\nprivate[this] var commaBuffered_=(x$1: Boolean): Unit\n```
9396
// ^^^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#commaBuffered().
9497
// documentation ```scala\nprivate[this] var commaBuffered: Boolean\n```
98+
// _____________ synthetic_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#`commaBuffered_=`().
99+
// documentation ```scala\nprivate[this] var commaBuffered_=(x$1: Boolean): Unit\n```
100+
// relationship is_definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#commaBuffered().
95101

96102
def flushBuffer() = {
97103
// ^^^^^^^^^^^ definition semanticdb maven maven/com.lihaoyi/ujson_2.13 1.4.0 ujson/BaseByteRenderer#flushBuffer().

0 commit comments

Comments
 (0)