@@ -335,6 +335,8 @@ fileprivate enum TaskMetadata: DependencyTracker {
335335 self = . freestanding
336336 case is WorkspaceSymbolsRequest :
337337 self = . freestanding
338+ case is WorkspaceTestsRequest :
339+ self = . freestanding
338340 default :
339341 logger. error (
340342 """
@@ -836,6 +838,8 @@ extension SourceKitServer: MessageHandler {
836838 await request. reply { try await shutdown ( request. params) }
837839 case let request as RequestAndReply < WorkspaceSymbolsRequest > :
838840 await request. reply { try await workspaceSymbols ( request. params) }
841+ case let request as RequestAndReply < WorkspaceTestsRequest > :
842+ await request. reply { try await workspaceTests ( request. params) }
839843 case let request as RequestAndReply < PollIndexRequest > :
840844 await request. reply { try await pollIndex ( request. params) }
841845 case let request as RequestAndReply < BarrierRequest > :
@@ -1490,33 +1494,30 @@ extension SourceKitServer {
14901494 /// Handle a workspace/symbol request, returning the SymbolInformation.
14911495 /// - returns: An array with SymbolInformation for each matching symbol in the workspace.
14921496 func workspaceSymbols( _ req: WorkspaceSymbolsRequest ) async throws -> [ WorkspaceSymbolItem ] ? {
1493- let symbols = findWorkspaceSymbols (
1494- matching: req. query
1495- ) . map ( { symbolOccurrence -> WorkspaceSymbolItem in
1496- let symbolPosition = Position (
1497- line: symbolOccurrence. location. line - 1 , // 1-based -> 0-based
1498- // FIXME: we need to convert the utf8/utf16 column, which may require reading the file!
1499- utf16index: symbolOccurrence. location. utf8Column - 1
1500- )
1501-
1502- let symbolLocation = Location (
1503- uri: DocumentURI ( URL ( fileURLWithPath: symbolOccurrence. location. path) ) ,
1504- range: Range ( symbolPosition)
1505- )
1506-
1507- return . symbolInformation(
1508- SymbolInformation (
1509- name: symbolOccurrence. symbol. name,
1510- kind: symbolOccurrence. symbol. kind. asLspSymbolKind ( ) ,
1511- deprecated: nil ,
1512- location: symbolLocation,
1513- containerName: symbolOccurrence. getContainerName ( )
1514- )
1515- )
1516- } )
1497+ let symbols = findWorkspaceSymbols ( matching: req. query) . map ( WorkspaceSymbolItem . init)
15171498 return symbols
15181499 }
15191500
1501+ func workspaceTests( _ req: WorkspaceTestsRequest ) async throws -> [ WorkspaceSymbolItem ] ? {
1502+ let testSymbols = workspaces. flatMap { ( workspace) -> [ SymbolOccurrence ] in
1503+ guard let index = workspace. index else {
1504+ return [ ]
1505+ }
1506+ let xctestSubclasses = index. occurrences ( ofUSR: " c:objc(cs)XCTest " , roles: [ . baseOf] )
1507+ . flatMap ( \. relations)
1508+ . filter { $0. roles. contains ( . baseOf) }
1509+ . flatMap { index. occurrences ( ofUSR: $0. symbol. usr, roles: [ . definition] ) }
1510+ let testMethods = xctestSubclasses. flatMap { xctestSubclass in
1511+ index. occurrences ( relatedToUSR: xctestSubclass. symbol. usr, roles: [ . childOf] )
1512+ } . filter { testMethodSymbol in
1513+ return testMethodSymbol. symbol. kind == . instanceMethod && testMethodSymbol. symbol. name. starts ( with: " test " )
1514+ && testMethodSymbol. roles. contains ( . definition)
1515+ }
1516+ return xctestSubclasses + testMethods
1517+ }
1518+ return testSymbols. map ( WorkspaceSymbolItem . init)
1519+ }
1520+
15201521 /// Forwards a SymbolInfoRequest to the appropriate toolchain service for this document.
15211522 func symbolInfo(
15221523 _ req: SymbolInfoRequest ,
@@ -2213,3 +2214,27 @@ fileprivate struct DocumentNotificationRequestQueue {
22132214 queue = [ ]
22142215 }
22152216}
2217+ fileprivate extension WorkspaceSymbolItem {
2218+ init ( _ symbolOccurrence: SymbolOccurrence ) {
2219+ let symbolPosition = Position (
2220+ line: symbolOccurrence. location. line - 1 , // 1-based -> 0-based
2221+ // FIXME: we need to convert the utf8/utf16 column, which may require reading the file!
2222+ utf16index: symbolOccurrence. location. utf8Column - 1
2223+ )
2224+
2225+ let symbolLocation = Location (
2226+ uri: DocumentURI ( URL ( fileURLWithPath: symbolOccurrence. location. path) ) ,
2227+ range: Range ( symbolPosition)
2228+ )
2229+
2230+ self = . symbolInformation(
2231+ SymbolInformation (
2232+ name: symbolOccurrence. symbol. name,
2233+ kind: symbolOccurrence. symbol. kind. asLspSymbolKind ( ) ,
2234+ deprecated: nil ,
2235+ location: symbolLocation,
2236+ containerName: symbolOccurrence. getContainerName ( )
2237+ )
2238+ )
2239+ }
2240+ }
0 commit comments