@@ -1530,20 +1530,24 @@ extension SourceKitLSPServer {
15301530 )
15311531 }
15321532
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 ] ? {
15361536 // Ignore short queries since they are:
15371537 // - noisy and slow, since they can match many symbols
15381538 // - normally unintentional, triggered when the user types slowly or if the editor doesn't
15391539 // debounce events while the user is typing
1540- guard matching . count >= minWorkspaceSymbolPatternLength else {
1540+ guard req . query . count >= minWorkspaceSymbolPatternLength else {
15411541 return [ ]
15421542 }
1543- var symbolOccurrenceResults : [ SymbolOccurrence ] = [ ]
1543+ var symbolsAndIndex : [ ( symbol : SymbolOccurrence , index : CheckedIndex ) ] = [ ]
15441544 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,
15471551 anchorStart: false ,
15481552 anchorEnd: false ,
15491553 subsequence: true ,
@@ -1555,19 +1559,36 @@ extension SourceKitLSPServer {
15551559 guard !symbol. location. isSystem && !symbol. roles. contains ( . accessorOf) else {
15561560 return true
15571561 }
1558- symbolOccurrenceResults . append ( symbol)
1562+ symbolOccurrences . append ( symbol)
15591563 return true
15601564 }
15611565 try Task . checkCancellation ( )
1566+ symbolsAndIndex += symbolOccurrences. map {
1567+ return ( $0, index)
1568+ }
15621569 }
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+ )
15651576
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+ }
15711592 }
15721593
15731594 /// Forwards a SymbolInfoRequest to the appropriate toolchain service for this document.
@@ -2087,7 +2108,7 @@ extension SourceKitLSPServer {
20872108 }
20882109 return self . indexToLSPCallHierarchyItem (
20892110 symbol: definition. symbol,
2090- containerName: definition . containerName,
2111+ containerName: index . containerName ( of : definition ) ,
20912112 location: location
20922113 )
20932114 } . sorted ( by: { Location ( uri: $0. uri, range: $0. range) < Location ( uri: $1. uri, range: $1. range) } )
@@ -2163,6 +2184,12 @@ extension SourceKitLSPServer {
21632184 let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: caller. usr)
21642185 let definitionSymbolLocation = definition? . location
21652186 let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation2)
2187+ let containerName : String ? =
2188+ if let definition {
2189+ index. containerName ( of: definition)
2190+ } else {
2191+ nil
2192+ }
21662193
21672194 let locations = calls. compactMap { indexToLSPLocation2 ( $0. location) } . sorted ( )
21682195 guard !locations. isEmpty else {
@@ -2172,7 +2199,7 @@ extension SourceKitLSPServer {
21722199 return CallHierarchyIncomingCall (
21732200 from: indexToLSPCallHierarchyItem2 (
21742201 symbol: caller,
2175- containerName: definition ? . containerName,
2202+ containerName: containerName,
21762203 location: definitionLocation ?? locations. first!
21772204 ) ,
21782205 fromRanges: locations. map ( \. range)
@@ -2216,11 +2243,17 @@ extension SourceKitLSPServer {
22162243 let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: occurrence. symbol. usr)
22172244 let definitionSymbolLocation = definition? . location
22182245 let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation2)
2246+ let containerName : String ? =
2247+ if let definition {
2248+ index. containerName ( of: definition)
2249+ } else {
2250+ nil
2251+ }
22192252
22202253 return CallHierarchyOutgoingCall (
22212254 to: indexToLSPCallHierarchyItem2 (
22222255 symbol: occurrence. symbol,
2223- containerName: definition ? . containerName,
2256+ containerName: containerName,
22242257 location: definitionLocation ?? location // Use occurrence location as fallback
22252258 ) ,
22262259 fromRanges: [ location. range]
@@ -2522,6 +2555,35 @@ fileprivate extension CheckedIndex {
25222555 }
25232556 return result
25242557 }
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+ }
25252587}
25262588
25272589extension IndexSymbolKind {
@@ -2572,26 +2634,6 @@ extension IndexSymbolKind {
25722634 }
25732635}
25742636
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-
25952637/// Simple struct for pending notifications/requests, including a cancellation handler.
25962638/// For convenience the notifications/request handlers are type erased via wrapping.
25972639fileprivate struct NotificationRequestOperation {
@@ -2637,31 +2679,6 @@ fileprivate func transitiveSubtypeClosure(ofUsrs usrs: [String], index: CheckedI
26372679 return result
26382680}
26392681
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-
26652682fileprivate extension RequestID {
26662683 /// Returns a numeric value for this request ID.
26672684 ///
0 commit comments