Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
codeintel: Ensure we represent every referenced symbol in a SCIP index (
Browse files Browse the repository at this point in the history
  • Loading branch information
efritz authored Jan 12, 2023
1 parent 542e437 commit 5a51622
Showing 1 changed file with 45 additions and 8 deletions.
53 changes: 45 additions & 8 deletions enterprise/internal/codeintel/uploads/internal/background/scip.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ func correlateSCIP(
if pkg, ok := packageFromSymbol(symbol.Symbol); ok {
packageSet[pkg] = false
}

for _, relationship := range symbol.Relationships {
if pkg, ok := packageFromSymbol(relationship.Symbol); ok {
packageSet[pkg] = false
}
}
}

for _, occurrence := range document.Occurrences {
Expand Down Expand Up @@ -265,25 +271,56 @@ func canonicalizeDocument(document *scip.Document, externalSymbolsByName map[str
// if there is an occurrence that references the external symbol name and no local symbol information
// exists.
func injectExternalSymbols(document *scip.Document, externalSymbolsByName map[string]*scip.SymbolInformation) {
symbolNames := make(map[string]struct{}, len(document.Symbols))
// Build set of existing definitions
definitionsSet := make(map[string]struct{}, len(document.Symbols))
for _, symbol := range document.Symbols {
symbolNames[symbol.Symbol] = struct{}{}
definitionsSet[symbol.Symbol] = struct{}{}
}

// Build a set of occurrence and symbol relationship references
referencesSet := make(map[string]struct{}, len(document.Symbols))
for _, symbol := range document.Symbols {
for _, relationship := range symbol.Relationships {
referencesSet[relationship.Symbol] = struct{}{}
}
}
for _, occurrence := range document.Occurrences {
if occurrence.Symbol == "" || scip.IsLocalSymbol(occurrence.Symbol) {
continue
}

// Ensure we only add each symbol once
if _, ok := symbolNames[occurrence.Symbol]; ok {
continue
}
symbolNames[occurrence.Symbol] = struct{}{}
referencesSet[occurrence.Symbol] = struct{}{}
}

// Add any references that do not have an associated definition
for len(referencesSet) > 0 {
// Collect unreferenced symbol names for new symbols. This can happen if we have
// a set of external symbols that reference each other. The references set acts
// as the frontier of our search.
newReferencesSet := map[string]struct{}{}

if symbol, ok := externalSymbolsByName[occurrence.Symbol]; ok {
for symbolName := range referencesSet {
if _, ok := definitionsSet[symbolName]; ok {
continue
}
definitionsSet[symbolName] = struct{}{}

symbol, ok := externalSymbolsByName[symbolName]
if !ok {
continue
}

// Add new definition for referenced symbol
document.Symbols = append(document.Symbols, symbol)

// Populate new frontier
for _, relationship := range symbol.Relationships {
newReferencesSet[relationship.Symbol] = struct{}{}
}
}

// Continue resolving references while we added new symbols
referencesSet = newReferencesSet
}
}

Expand Down

0 comments on commit 5a51622

Please sign in to comment.