diff --git a/Sources/BuildSystemIntegration/BuildSystemManager.swift b/Sources/BuildSystemIntegration/BuildSystemManager.swift index def53ffc..7b68fd97 100644 --- a/Sources/BuildSystemIntegration/BuildSystemManager.swift +++ b/Sources/BuildSystemIntegration/BuildSystemManager.swift @@ -727,6 +727,12 @@ package actor BuildSystemManager: QueueBasedMessageHandler { return result } + package func buildTarget(named identifier: BuildTargetIdentifier) async -> BuildTarget? { + return await orLog("Getting built target with ID") { + try await buildTargets()[identifier]?.target + } + } + package func sourceFiles(in targets: Set) async throws -> [SourcesItem] { guard let connectionToBuildSystem else { return [] diff --git a/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift b/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift index ed6e74aa..51da5502 100644 --- a/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift +++ b/Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift @@ -462,7 +462,10 @@ package actor SwiftPMBuildSystem: BuiltInBuildSystem { package func buildTargets(request: WorkspaceBuildTargetsRequest) async throws -> WorkspaceBuildTargetsResponse { var targets = self.swiftPMTargets.map { (targetId, target) in - var tags: [BuildTargetTag] = [.test] + var tags: [BuildTargetTag] = [] + if target.isTestTarget { + tags.append(.test) + } if !target.isPartOfRootPackage { tags.append(.dependency) } diff --git a/Sources/SourceKitLSP/TestDiscovery.swift b/Sources/SourceKitLSP/TestDiscovery.swift index 34396908..bca98386 100644 --- a/Sources/SourceKitLSP/TestDiscovery.swift +++ b/Sources/SourceKitLSP/TestDiscovery.swift @@ -522,6 +522,14 @@ extension SwiftLanguageService { for uri: DocumentURI, in workspace: Workspace ) async throws -> [AnnotatedTestItem]? { + let targetIdentifiers = await workspace.buildSystemManager.targets(for: uri) + let isInTestTarget = await targetIdentifiers.asyncContains(where: { + await workspace.buildSystemManager.buildTarget(named: $0)?.tags.contains(.test) ?? true + }) + if !targetIdentifiers.isEmpty && !isInTestTarget { + // If we know the targets for the file and the file is not part of any test target, don't scan it for tests. + return nil + } let snapshot = try documentManager.latestSnapshot(uri) let semanticSymbols = workspace.index(checkedFor: .deletedFiles)?.symbols(inFilePath: snapshot.uri.pseudoPath) let xctestSymbols = await SyntacticSwiftXCTestScanner.findTestSymbols( diff --git a/Sources/SwiftExtensions/Sequence+AsyncMap.swift b/Sources/SwiftExtensions/Sequence+AsyncMap.swift index a2d27654..dc0b27e8 100644 --- a/Sources/SwiftExtensions/Sequence+AsyncMap.swift +++ b/Sources/SwiftExtensions/Sequence+AsyncMap.swift @@ -81,4 +81,11 @@ extension Sequence { return nil } + + /// Just like `Sequence.contains` but allows an `async` predicate function. + package func asyncContains( + @_inheritActorContext where predicate: @Sendable (Element) async throws -> Bool + ) async rethrows -> Bool { + return try await asyncFirst(predicate) != nil + } } diff --git a/Tests/SourceKitLSPTests/DocumentTestDiscoveryTests.swift b/Tests/SourceKitLSPTests/DocumentTestDiscoveryTests.swift index 9f89290a..312a543a 100644 --- a/Tests/SourceKitLSPTests/DocumentTestDiscoveryTests.swift +++ b/Tests/SourceKitLSPTests/DocumentTestDiscoveryTests.swift @@ -1424,4 +1424,21 @@ final class DocumentTestDiscoveryTests: XCTestCase { ] ) } + + func testSwiftTestingTestsAreNotReportedInNonTestTargets() async throws { + let project = try await SwiftPMTestProject( + files: [ + "FileA.swift": """ + @Suite struct MyTests { + @Test func inStruct() {} + } + """ + ] + ) + + let (uri, _) = try project.openDocument("FileA.swift") + + let tests = try await project.testClient.send(DocumentTestsRequest(textDocument: TextDocumentIdentifier(uri))) + XCTAssertEqual(tests, []) + } } diff --git a/Tests/SourceKitLSPTests/WorkspaceTestDiscoveryTests.swift b/Tests/SourceKitLSPTests/WorkspaceTestDiscoveryTests.swift index f4e02488..e792f427 100644 --- a/Tests/SourceKitLSPTests/WorkspaceTestDiscoveryTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceTestDiscoveryTests.swift @@ -1063,6 +1063,21 @@ final class WorkspaceTestDiscoveryTests: XCTestCase { ] ) } + + func testSwiftTestingTestsAreNotDiscoveredInNonTestTargets() async throws { + let project = try await SwiftPMTestProject( + files: [ + "FileA.swift": """ + @Suite struct MyTests { + @Test func inStruct() {} + } + """ + ] + ) + + let tests = try await project.testClient.send(WorkspaceTestsRequest()) + XCTAssertEqual(tests, []) + } } extension TestItem {