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