@@ -25,7 +25,7 @@ public struct AnnotatedTestItem {
25
25
/// The test item to be annotated
26
26
public var testItem : TestItem
27
27
28
- /// Whether the `TestItem` is declared in an extension.
28
+ /// Whether the `TestItem` is an extension.
29
29
public var isExtension : Bool
30
30
31
31
public init (
@@ -360,7 +360,7 @@ final class SyntacticSwiftXCTestScanner: SyntaxVisitor {
360
360
private var snapshot : DocumentSnapshot
361
361
362
362
/// The workspace symbols representing the found `XCTestCase` subclasses and test methods.
363
- private var result : [ TestItem ] = [ ]
363
+ private var result : [ AnnotatedTestItem ] = [ ]
364
364
365
365
private init ( snapshot: DocumentSnapshot ) {
366
366
self . snapshot = snapshot
@@ -370,7 +370,7 @@ final class SyntacticSwiftXCTestScanner: SyntaxVisitor {
370
370
public static func findTestSymbols(
371
371
in snapshot: DocumentSnapshot ,
372
372
syntaxTreeManager: SyntaxTreeManager
373
- ) async -> [ TestItem ] {
373
+ ) async -> [ AnnotatedTestItem ] {
374
374
guard snapshot. text. contains ( " XCTestCase " ) || snapshot. text. contains ( " test " ) else {
375
375
// If the file contains tests that can be discovered syntactically, it needs to have a class inheriting from
376
376
// `XCTestCase` or a function starting with `test`.
@@ -437,21 +437,25 @@ final class SyntacticSwiftXCTestScanner: SyntaxVisitor {
437
437
return . visitChildren
438
438
}
439
439
let range = snapshot. range ( of: node. positionAfterSkippingLeadingTrivia..< node. endPositionBeforeTrailingTrivia)
440
- let testItem = TestItem (
441
- id: node. name. text,
442
- label: node. name. text,
443
- disabled: false ,
444
- style: TestStyle . xcTest,
445
- location: Location ( uri: snapshot. uri, range: range) ,
446
- children: testMethods,
447
- tags: [ ]
440
+ let testItem = AnnotatedTestItem (
441
+ testItem: TestItem (
442
+ id: node. name. text,
443
+ label: node. name. text,
444
+ disabled: false ,
445
+ style: TestStyle . xcTest,
446
+ location: Location ( uri: snapshot. uri, range: range) ,
447
+ children: testMethods,
448
+ tags: [ ]
449
+ ) ,
450
+ isExtension: false
448
451
)
449
452
result. append ( testItem)
450
453
return . visitChildren
451
454
}
452
455
453
456
override func visit( _ node: ExtensionDeclSyntax ) -> SyntaxVisitorContinueKind {
454
457
result += findTestMethods ( in: node. memberBlock. members, containerName: node. extendedType. trimmedDescription)
458
+ . map { AnnotatedTestItem ( testItem: $0, isExtension: true ) }
455
459
return . visitChildren
456
460
}
457
461
}
@@ -485,6 +489,20 @@ extension TestItem {
485
489
}
486
490
}
487
491
492
+ extension AnnotatedTestItem {
493
+ /// Use out-of-date semantic information to filter syntactic symbols.
494
+ ///
495
+ /// Delegates to the `TestItem`'s `filterUsing(semanticSymbols:)` method to perform the filtering.
496
+ fileprivate func filterUsing( semanticSymbols: [ Symbol ] ? ) -> AnnotatedTestItem ? {
497
+ guard let testItem = self . testItem. filterUsing ( semanticSymbols: semanticSymbols) else {
498
+ return nil
499
+ }
500
+ var test = self
501
+ test. testItem = testItem
502
+ return test
503
+ }
504
+ }
505
+
488
506
extension Array < AnnotatedTestItem > {
489
507
/// When the test scanners discover tests in extensions they are captured in their own parent `TestItem`, not the
490
508
/// `TestItem` generated from the class/struct's definition. This is largely because of the syntatic nature of the
@@ -569,13 +587,11 @@ extension Array<AnnotatedTestItem> {
569
587
}
570
588
}
571
589
572
- // Filter out the items that have been merged into their parents, sorting the tests by location.
573
- // TestItems not in extensions should be priotitized first.
590
+ // Sort the tests by location, prioritizing TestItems not in extensions.
574
591
let sortedItems = itemDict. values
575
- . compactMap { $0 }
576
592
. sorted { ( $0. isExtension != $1. isExtension) ? !$0. isExtension : ( $0. testItem. location < $1. testItem. location) }
577
593
578
- return sortedItems. map {
594
+ let result = sortedItems. map {
579
595
guard !$0. testItem. children. isEmpty, mergedIds. contains ( $0. testItem. id) else {
580
596
return $0. testItem
581
597
}
@@ -585,20 +601,22 @@ extension Array<AnnotatedTestItem> {
585
601
. mergingTestsInExtensions ( )
586
602
return newItem
587
603
}
604
+ return result
588
605
}
589
606
}
590
607
591
608
extension SwiftLanguageService {
592
- public func syntacticDocumentTests( for uri: DocumentURI , in workspace: Workspace ) async throws -> [ AnnotatedTestItem ] ?
593
- {
609
+ public func syntacticDocumentTests(
610
+ for uri: DocumentURI ,
611
+ in workspace: Workspace
612
+ ) async throws -> [ AnnotatedTestItem ] ? {
594
613
let snapshot = try documentManager. latestSnapshot ( uri)
595
614
let semanticSymbols = workspace. index ( checkedFor: . deletedFiles) ? . symbols ( inFilePath: snapshot. uri. pseudoPath)
596
615
let xctestSymbols = await SyntacticSwiftXCTestScanner . findTestSymbols (
597
616
in: snapshot,
598
617
syntaxTreeManager: syntaxTreeManager
599
618
)
600
619
. compactMap { $0. filterUsing ( semanticSymbols: semanticSymbols) }
601
- . map { AnnotatedTestItem ( testItem: $0, isExtension: false ) }
602
620
603
621
let swiftTestingSymbols = await SyntacticSwiftTestingTestScanner . findTestSymbols (
604
622
in: snapshot,
0 commit comments