@@ -1530,20 +1530,24 @@ extension SourceKitLSPServer {
1530
1530
)
1531
1531
}
1532
1532
1533
- /// Find all symbols in the workspace that include a string in their name .
1534
- /// - returns: An array of SymbolOccurrences that match the string .
1535
- func findWorkspaceSymbols ( matching : String ) throws -> [ SymbolOccurrence ] {
1533
+ /// Handle a workspace/symbol request, returning the SymbolInformation .
1534
+ /// - returns: An array with SymbolInformation for each matching symbol in the workspace .
1535
+ func workspaceSymbols ( _ req : WorkspaceSymbolsRequest ) async throws -> [ WorkspaceSymbolItem ] ? {
1536
1536
// Ignore short queries since they are:
1537
1537
// - noisy and slow, since they can match many symbols
1538
1538
// - normally unintentional, triggered when the user types slowly or if the editor doesn't
1539
1539
// debounce events while the user is typing
1540
- guard matching . count >= minWorkspaceSymbolPatternLength else {
1540
+ guard req . query . count >= minWorkspaceSymbolPatternLength else {
1541
1541
return [ ]
1542
1542
}
1543
- var symbolOccurrenceResults : [ SymbolOccurrence ] = [ ]
1543
+ var symbolsAndIndex : [ ( symbol : SymbolOccurrence , index : CheckedIndex ) ] = [ ]
1544
1544
for workspace in workspaces {
1545
- workspace. index ( checkedFor: . deletedFiles) ? . forEachCanonicalSymbolOccurrence (
1546
- containing: matching,
1545
+ guard let index = workspace. index ( checkedFor: . deletedFiles) else {
1546
+ continue
1547
+ }
1548
+ var symbolOccurrences : [ SymbolOccurrence ] = [ ]
1549
+ index. forEachCanonicalSymbolOccurrence (
1550
+ containing: req. query,
1547
1551
anchorStart: false ,
1548
1552
anchorEnd: false ,
1549
1553
subsequence: true ,
@@ -1555,19 +1559,36 @@ extension SourceKitLSPServer {
1555
1559
guard !symbol. location. isSystem && !symbol. roles. contains ( . accessorOf) else {
1556
1560
return true
1557
1561
}
1558
- symbolOccurrenceResults . append ( symbol)
1562
+ symbolOccurrences . append ( symbol)
1559
1563
return true
1560
1564
}
1561
1565
try Task . checkCancellation ( )
1566
+ symbolsAndIndex += symbolOccurrences. map {
1567
+ return ( $0, index)
1568
+ }
1562
1569
}
1563
- return symbolOccurrenceResults. sorted ( )
1564
- }
1570
+ return symbolsAndIndex. sorted ( by: { $0. symbol < $1. symbol } ) . map { symbolOccurrence, index in
1571
+ let symbolPosition = Position (
1572
+ line: symbolOccurrence. location. line - 1 , // 1-based -> 0-based
1573
+ // FIXME: we need to convert the utf8/utf16 column, which may require reading the file!
1574
+ utf16index: symbolOccurrence. location. utf8Column - 1
1575
+ )
1565
1576
1566
- /// Handle a workspace/symbol request, returning the SymbolInformation.
1567
- /// - returns: An array with SymbolInformation for each matching symbol in the workspace.
1568
- func workspaceSymbols( _ req: WorkspaceSymbolsRequest ) async throws -> [ WorkspaceSymbolItem ] ? {
1569
- let symbols = try findWorkspaceSymbols ( matching: req. query) . map ( WorkspaceSymbolItem . init)
1570
- return symbols
1577
+ let symbolLocation = Location (
1578
+ uri: symbolOccurrence. location. documentUri,
1579
+ range: Range ( symbolPosition)
1580
+ )
1581
+
1582
+ return WorkspaceSymbolItem . symbolInformation (
1583
+ SymbolInformation (
1584
+ name: symbolOccurrence. symbol. name,
1585
+ kind: symbolOccurrence. symbol. kind. asLspSymbolKind ( ) ,
1586
+ deprecated: nil ,
1587
+ location: symbolLocation,
1588
+ containerName: index. containerName ( of: symbolOccurrence)
1589
+ )
1590
+ )
1591
+ }
1571
1592
}
1572
1593
1573
1594
/// Forwards a SymbolInfoRequest to the appropriate toolchain service for this document.
@@ -2087,7 +2108,7 @@ extension SourceKitLSPServer {
2087
2108
}
2088
2109
return self . indexToLSPCallHierarchyItem (
2089
2110
symbol: definition. symbol,
2090
- containerName: definition . containerName,
2111
+ containerName: index . containerName ( of : definition ) ,
2091
2112
location: location
2092
2113
)
2093
2114
} . sorted ( by: { Location ( uri: $0. uri, range: $0. range) < Location ( uri: $1. uri, range: $1. range) } )
@@ -2163,6 +2184,12 @@ extension SourceKitLSPServer {
2163
2184
let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: caller. usr)
2164
2185
let definitionSymbolLocation = definition? . location
2165
2186
let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation2)
2187
+ let containerName : String ? =
2188
+ if let definition {
2189
+ index. containerName ( of: definition)
2190
+ } else {
2191
+ nil
2192
+ }
2166
2193
2167
2194
let locations = calls. compactMap { indexToLSPLocation2 ( $0. location) } . sorted ( )
2168
2195
guard !locations. isEmpty else {
@@ -2172,7 +2199,7 @@ extension SourceKitLSPServer {
2172
2199
return CallHierarchyIncomingCall (
2173
2200
from: indexToLSPCallHierarchyItem2 (
2174
2201
symbol: caller,
2175
- containerName: definition ? . containerName,
2202
+ containerName: containerName,
2176
2203
location: definitionLocation ?? locations. first!
2177
2204
) ,
2178
2205
fromRanges: locations. map ( \. range)
@@ -2216,11 +2243,17 @@ extension SourceKitLSPServer {
2216
2243
let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: occurrence. symbol. usr)
2217
2244
let definitionSymbolLocation = definition? . location
2218
2245
let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation2)
2246
+ let containerName : String ? =
2247
+ if let definition {
2248
+ index. containerName ( of: definition)
2249
+ } else {
2250
+ nil
2251
+ }
2219
2252
2220
2253
return CallHierarchyOutgoingCall (
2221
2254
to: indexToLSPCallHierarchyItem2 (
2222
2255
symbol: occurrence. symbol,
2223
- containerName: definition ? . containerName,
2256
+ containerName: containerName,
2224
2257
location: definitionLocation ?? location // Use occurrence location as fallback
2225
2258
) ,
2226
2259
fromRanges: [ location. range]
@@ -2522,6 +2555,35 @@ fileprivate extension CheckedIndex {
2522
2555
}
2523
2556
return result
2524
2557
}
2558
+
2559
+ /// Get the name of the symbol that is a parent of this symbol, if one exists
2560
+ func containerName( of symbol: SymbolOccurrence ) -> String ? {
2561
+ // The container name of accessors is the container of the surrounding variable.
2562
+ let accessorOf = symbol. relations. filter { $0. roles. contains ( . accessorOf) }
2563
+ if let primaryVariable = accessorOf. sorted ( ) . first {
2564
+ if accessorOf. count > 1 {
2565
+ logger. fault ( " Expected an occurrence to an accessor of at most one symbol, not multiple " )
2566
+ }
2567
+ if let primaryVariable = primaryDefinitionOrDeclarationOccurrence ( ofUSR: primaryVariable. symbol. usr) {
2568
+ return containerName ( of: primaryVariable)
2569
+ }
2570
+ }
2571
+
2572
+ let containers = symbol. relations. filter { $0. roles. contains ( . childOf) }
2573
+ if containers. count > 1 {
2574
+ logger. fault ( " Expected an occurrence to a child of at most one symbol, not multiple " )
2575
+ }
2576
+ return containers. filter {
2577
+ switch $0. symbol. kind {
2578
+ case . module, . namespace, . enum, . struct, . class, . protocol, . extension, . union:
2579
+ return true
2580
+ case . unknown, . namespaceAlias, . macro, . typealias, . function, . variable, . field, . enumConstant,
2581
+ . instanceMethod, . classMethod, . staticMethod, . instanceProperty, . classProperty, . staticProperty, . constructor,
2582
+ . destructor, . conversionFunction, . parameter, . using, . concept, . commentTag:
2583
+ return false
2584
+ }
2585
+ } . sorted ( ) . first? . symbol. name
2586
+ }
2525
2587
}
2526
2588
2527
2589
extension IndexSymbolKind {
@@ -2572,26 +2634,6 @@ extension IndexSymbolKind {
2572
2634
}
2573
2635
}
2574
2636
2575
- extension SymbolOccurrence {
2576
- /// Get the name of the symbol that is a parent of this symbol, if one exists
2577
- var containerName : String ? {
2578
- let containers = relations. filter { $0. roles. contains ( . childOf) }
2579
- if containers. count > 1 {
2580
- logger. fault ( " Expected an occurrence to a child of at most one symbol, not multiple " )
2581
- }
2582
- return containers. filter {
2583
- switch $0. symbol. kind {
2584
- case . module, . namespace, . enum, . struct, . class, . protocol, . extension, . union:
2585
- return true
2586
- case . unknown, . namespaceAlias, . macro, . typealias, . function, . variable, . field, . enumConstant,
2587
- . instanceMethod, . classMethod, . staticMethod, . instanceProperty, . classProperty, . staticProperty, . constructor,
2588
- . destructor, . conversionFunction, . parameter, . using, . concept, . commentTag:
2589
- return false
2590
- }
2591
- } . sorted ( ) . first? . symbol. name
2592
- }
2593
- }
2594
-
2595
2637
/// Simple struct for pending notifications/requests, including a cancellation handler.
2596
2638
/// For convenience the notifications/request handlers are type erased via wrapping.
2597
2639
fileprivate struct NotificationRequestOperation {
@@ -2637,31 +2679,6 @@ fileprivate func transitiveSubtypeClosure(ofUsrs usrs: [String], index: CheckedI
2637
2679
return result
2638
2680
}
2639
2681
2640
- extension WorkspaceSymbolItem {
2641
- init ( _ symbolOccurrence: SymbolOccurrence ) {
2642
- let symbolPosition = Position (
2643
- line: symbolOccurrence. location. line - 1 , // 1-based -> 0-based
2644
- // FIXME: we need to convert the utf8/utf16 column, which may require reading the file!
2645
- utf16index: symbolOccurrence. location. utf8Column - 1
2646
- )
2647
-
2648
- let symbolLocation = Location (
2649
- uri: symbolOccurrence. location. documentUri,
2650
- range: Range ( symbolPosition)
2651
- )
2652
-
2653
- self = . symbolInformation(
2654
- SymbolInformation (
2655
- name: symbolOccurrence. symbol. name,
2656
- kind: symbolOccurrence. symbol. kind. asLspSymbolKind ( ) ,
2657
- deprecated: nil ,
2658
- location: symbolLocation,
2659
- containerName: symbolOccurrence. containerName
2660
- )
2661
- )
2662
- }
2663
- }
2664
-
2665
2682
fileprivate extension RequestID {
2666
2683
/// Returns a numeric value for this request ID.
2667
2684
///
0 commit comments