@@ -65,7 +65,8 @@ private void run() throws IOException {
6565
6666 private void runTyped (List <Path > files , PackageTable packages ) {
6767 writer .emitTyped (typedMetadata ());
68- filesStream (files ).forEach (document -> processTypedDocument (document , packages ));
68+ InverseReferenceRelationships references = inverseReferenceRelationships (files );
69+ filesStream (files ).forEach (document -> processTypedDocument (document , packages , references ));
6970 }
7071
7172 private String typedSymbol (String symbol , Package pkg ) {
@@ -82,7 +83,8 @@ public static boolean isDefinitionRole(Role role) {
8283 return role == Role .DEFINITION || role == Role .SYNTHETIC_DEFINITION ;
8384 }
8485
85- private void processTypedDocument (Path path , PackageTable packages ) {
86+ private void processTypedDocument (
87+ Path path , PackageTable packages , InverseReferenceRelationships references ) {
8688 for (ScipTextDocument doc : parseTextDocument (path ).collect (Collectors .toList ())) {
8789 if (doc .semanticdb .getOccurrencesCount () == 0 ) {
8890 continue ;
@@ -130,6 +132,19 @@ private void processTypedDocument(Path path, PackageTable packages) {
130132 Scip .SymbolInformation .Builder scipInfo =
131133 Scip .SymbolInformation .newBuilder ().setSymbol (typedSymbol (info .getSymbol (), pkg ));
132134
135+ // TODO: this can be removed once https://github.com/sourcegraph/sourcegraph/issues/50927 is
136+ // fixed.
137+ ArrayList <String > inverseReferences = references .map .get (info .getSymbol ());
138+ if (inverseReferences != null ) {
139+ for (String inverseReference : inverseReferences ) {
140+ scipInfo .addRelationships (
141+ Scip .Relationship .newBuilder ()
142+ .setSymbol (inverseReference )
143+ .setIsImplementation (true )
144+ .setIsReference (true ));
145+ }
146+ }
147+
133148 for (int i = 0 ; i < info .getDefinitionRelationshipsCount (); i ++) {
134149 String definitionSymbol = info .getDefinitionRelationships (i );
135150 if (definitionSymbol .isEmpty ()) {
@@ -245,6 +260,50 @@ private Stream<Path> filesStream(List<Path> files) {
245260 return options .parallel ? files .parallelStream () : files .stream ();
246261 }
247262
263+ private static class InverseReferenceRelationships {
264+ public final Map <String , ArrayList <String >> map ;
265+
266+ private InverseReferenceRelationships (Map <String , ArrayList <String >> map ) {
267+ this .map = map ;
268+ }
269+ }
270+
271+ private InverseReferenceRelationships inverseReferenceRelationships (List <Path > files ) {
272+ if (!options .emitInverseRelationships ) {
273+ return new InverseReferenceRelationships (Collections .emptyMap ());
274+ }
275+ return new InverseReferenceRelationships (
276+ filesStream (files )
277+ .flatMap (this ::parseTextDocument )
278+ .flatMap (this ::referenceRelationships )
279+ .collect (
280+ Collectors .groupingBy (
281+ SymbolRelationship ::getTo ,
282+ Collectors .mapping (
283+ SymbolRelationship ::getFrom , Collectors .toCollection (ArrayList ::new )))));
284+ }
285+
286+ private Stream <SymbolRelationship > referenceRelationships (ScipTextDocument document ) {
287+ ArrayList <SymbolRelationship > relationships = new ArrayList <>();
288+ for (int i = 0 ; i < document .semanticdb .getSymbolsCount (); i ++) {
289+ SymbolInformation info = document .semanticdb .getSymbols (i );
290+ if (!supportsReferenceRelationship (info )) {
291+ continue ;
292+ }
293+ if (info .getSymbol ().isEmpty () || SemanticdbSymbols .isLocal (info .getSymbol ())) {
294+ continue ;
295+ }
296+ for (int j = 0 ; j < info .getOverriddenSymbolsCount (); j ++) {
297+ String overriddenSymbol = info .getOverriddenSymbols (j );
298+ if (SemanticdbSymbols .isLocal (overriddenSymbol )) {
299+ continue ;
300+ }
301+ relationships .add (new SymbolRelationship (info .getSymbol (), overriddenSymbol ));
302+ }
303+ }
304+ return relationships .stream ();
305+ }
306+
248307 private Set <String > exportSymbols (List <Path > files ) {
249308 return filesStream (files )
250309 .flatMap (this ::parseTextDocument )
0 commit comments