Skip to content

Commit 2bc9b3e

Browse files
committed
Close SCIP/LSIF feature gap
Previously, scip-java had custom support for Scala that was only supported by the LSIF writer. This meant that Scala users were recommended to use LSIF instead of SCIP. Now that Sourcegraph supports native SCIP uploads (and stores SCIP in the database) it's time to close this feature gap so that Scala users can use SCIP instead of LSIF.
1 parent dbb7d6a commit 2bc9b3e

File tree

19 files changed

+718
-453
lines changed

19 files changed

+718
-453
lines changed

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

Lines changed: 106 additions & 71 deletions
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

Lines changed: 5 additions & 5 deletions
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

Lines changed: 17 additions & 11 deletions
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)