1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
package import IndexStoreDB
import SKLogging
import SemanticIndex
@_spi(LinkCompletion) import SwiftDocC
extension CheckedIndex {
/// Find a `SymbolOccurrence` that is considered the primary definition of the symbol with the given `DocCSymbolLink`.
///
/// If the `DocCSymbolLink` has an ambiguous definition, the most important role of this function is to deterministically return
/// the same result every time.
package func primaryDefinitionOrDeclarationOccurrence(
ofDocCSymbolLink symbolLink: DocCSymbolLink
) -> SymbolOccurrence? {
var components = symbolLink.components
guard components.count > 0 else {
return nil
}
// Do a lookup to find the top level symbol
let topLevelSymbol = components.removeLast()
var topLevelSymbolOccurrences: [SymbolOccurrence] = []
forEachCanonicalSymbolOccurrence(byName: topLevelSymbol.name) { symbolOccurrence in
topLevelSymbolOccurrences.append(symbolOccurrence)
return true // continue
}
topLevelSymbolOccurrences = topLevelSymbolOccurrences.filter {
let symbolInformation = LinkCompletionTools.SymbolInformation(fromSymbolOccurrence: $0)
return symbolInformation.matches(topLevelSymbol.disambiguation)
}
// Search each potential symbol's parents to find an exact match
let symbolOccurences = topLevelSymbolOccurrences.filter { topLevelSymbolOccurrence in
var components = components
var symbolOccurrence = topLevelSymbolOccurrence
while let nextComponent = components.popLast(), let parentSymbolOccurrence = symbolOccurrence.parent(self) {
let parentSymbolInformation = LinkCompletionTools.SymbolInformation(
fromSymbolOccurrence: parentSymbolOccurrence
)
guard parentSymbolOccurrence.symbol.name == nextComponent.name,
parentSymbolInformation.matches(nextComponent.disambiguation)
else {
return false
}
symbolOccurrence = parentSymbolOccurrence
}
// If we have exactly one component left, check to see if it's the module name
if components.count == 1 {
let lastComponent = components.removeLast()
guard lastComponent.name == topLevelSymbolOccurrence.location.moduleName else {
return false
}
}
guard components.isEmpty else {
return false
}
return true
}.sorted()
if symbolOccurences.count > 1 {
logger.debug("Multiple symbols found for DocC symbol link '\(symbolLink.linkString)'")
}
return symbolOccurences.first
}
}
extension SymbolOccurrence {
func parent(_ index: CheckedIndex) -> SymbolOccurrence? {
let allParentRelations =
relations
.filter { $0.roles.contains(.childOf) }
.sorted()
if allParentRelations.count > 1 {
logger.debug("Symbol \(symbol.usr) has multiple parent symbols")
}
guard let parentRelation = allParentRelations.first else {
return nil
}
if parentRelation.symbol.kind == .extension {
let allSymbolOccurrences = index.occurrences(relatedToUSR: parentRelation.symbol.usr, roles: .extendedBy)
.sorted()
if allSymbolOccurrences.count > 1 {
logger.debug("Extension \(parentRelation.symbol.usr) extends multiple symbols")
}
return allSymbolOccurrences.first
}
return index.primaryDefinitionOrDeclarationOccurrence(ofUSR: parentRelation.symbol.usr)
}
}
|