diff --git a/Sources/BuildServerProtocol/Messages/InitializeBuildRequest.swift b/Sources/BuildServerProtocol/Messages/InitializeBuildRequest.swift index bbf2deb3..9e20afdd 100644 --- a/Sources/BuildServerProtocol/Messages/InitializeBuildRequest.swift +++ b/Sources/BuildServerProtocol/Messages/InitializeBuildRequest.swift @@ -283,11 +283,11 @@ public struct SourceKitInitializeBuildResponseData: LSPAnyCodable, Codable, Send public var sourceKitOptionsProvider: Bool? public init( - indexDatabasePath: String?, - indexStorePath: String?, - watchers: [FileSystemWatcher]?, - prepareProvider: Bool?, - sourceKitOptionsProvider: Bool? + indexDatabasePath: String? = nil, + indexStorePath: String? = nil, + watchers: [FileSystemWatcher]? = nil, + prepareProvider: Bool? = nil, + sourceKitOptionsProvider: Bool? = nil ) { self.indexDatabasePath = indexDatabasePath self.indexStorePath = indexStorePath diff --git a/Sources/BuildSystemIntegration/TestBuildSystem.swift b/Sources/BuildSystemIntegration/TestBuildSystem.swift index 018f5cac..9d726cb2 100644 --- a/Sources/BuildSystemIntegration/TestBuildSystem.swift +++ b/Sources/BuildSystemIntegration/TestBuildSystem.swift @@ -37,9 +37,15 @@ package actor TestBuildSystem: MessageHandler { connectionToSourceKitLSP.send(OnBuildTargetDidChangeNotification(changes: nil)) } - package nonisolated var supportsPreparation: Bool { false } + private let initializeData: SourceKitInitializeBuildResponseData - package init(connectionToSourceKitLSP: any Connection) { + package init( + initializeData: SourceKitInitializeBuildResponseData = SourceKitInitializeBuildResponseData( + sourceKitOptionsProvider: true + ), + connectionToSourceKitLSP: any Connection + ) { + self.initializeData = initializeData self.connectionToSourceKitLSP = connectionToSourceKitLSP } @@ -90,6 +96,8 @@ package actor TestBuildSystem: MessageHandler { handle(request, using: self.workspaceBuildTargetsRequest) case let request as WorkspaceWaitForBuildSystemUpdatesRequest: handle(request, using: self.workspaceWaitForBuildSystemUpdatesRequest) + case let request as BuildTargetPrepareRequest: + handle(request, using: self.prepareTarget) default: reply(.failure(ResponseError.methodNotFound(type(of: request).method))) } @@ -101,7 +109,8 @@ package actor TestBuildSystem: MessageHandler { version: "", bspVersion: "2.2.0", capabilities: BuildServerCapabilities(), - data: nil + dataKind: .sourceKit, + data: initializeData.encodeToLSPAny() ) } @@ -148,6 +157,10 @@ package actor TestBuildSystem: MessageHandler { return buildSettingsByFile[request.textDocument.uri] } + func prepareTarget(_ request: BuildTargetPrepareRequest) async throws -> VoidResponse { + return VoidResponse() + } + package func waitForBuildSystemUpdates(request: WorkspaceWaitForBuildSystemUpdatesRequest) async -> VoidResponse { return VoidResponse() } diff --git a/Sources/SemanticIndex/SemanticIndexManager.swift b/Sources/SemanticIndex/SemanticIndexManager.swift index 9550c329..bb8ff355 100644 --- a/Sources/SemanticIndex/SemanticIndexManager.swift +++ b/Sources/SemanticIndex/SemanticIndexManager.swift @@ -673,7 +673,7 @@ package final actor SemanticIndexManager { /// `indexFilesWithUpToDateUnit` is `true`. /// /// The returned task finishes when all files are indexed. - private func scheduleIndexing( + package func scheduleIndexing( of files: some Collection & Sendable, indexFilesWithUpToDateUnit: Bool, priority: TaskPriority? diff --git a/Sources/SourceKitLSP/Workspace.swift b/Sources/SourceKitLSP/Workspace.swift index 74fc6374..58d4ccbd 100644 --- a/Sources/SourceKitLSP/Workspace.swift +++ b/Sources/SourceKitLSP/Workspace.swift @@ -435,8 +435,24 @@ package final class Workspace: Sendable, BuildSystemManagerDelegate { package func buildTargetsChanged(_ changes: [BuildTargetEvent]?) async { await sourceKitLSPServer?.fileHandlingCapabilityChanged() - let testFiles = await orLog("Getting test files") { try await buildSystemManager.testFiles() } ?? [] - await syntacticTestIndex.listOfTestFilesDidChange(testFiles) + await orLog("Scheduling re-indexing of changed targets") { + var sourceFiles = try await self.buildSystemManager.sourceFiles(includeNonBuildableFiles: false) + if let changes { + let changedTargets = changes.map(\.target) + sourceFiles = sourceFiles.filter { + !$0.value.targets.intersection(changedTargets).isEmpty + } + } + _ = await semanticIndexManager?.scheduleIndexing( + of: sourceFiles.keys, + indexFilesWithUpToDateUnit: false, + priority: .low + ) + } + await orLog("Scheduling syntactic test re-indexing") { + let testFiles = try await buildSystemManager.testFiles() + await syntacticTestIndex.listOfTestFilesDidChange(testFiles) + } } package var clientSupportsWorkDoneProgress: Bool { diff --git a/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift b/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift index 6dee3b09..abcf4e67 100644 --- a/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift +++ b/Tests/SourceKitLSPTests/BackgroundIndexingTests.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +import BuildServerProtocol import BuildSystemIntegration import LanguageServerProtocol import LanguageServerProtocolExtensions @@ -1910,6 +1911,72 @@ final class BackgroundIndexingTests: XCTestCase { try await project.testClient.send(IsIndexingRequest()).indexing == false } } + + func testIndexFileIfBuildTargetsChange() async throws { + let testBuildSystem = ThreadSafeBox(initialValue: nil) + let project = try await MultiFileTestProject( + files: [ + "Test.swift": """ + func 1️⃣myTestFunc() {} + """ + ], + hooks: Hooks( + buildSystemHooks: BuildSystemHooks(injectBuildServer: { projectRoot, connectionToSourceKitLSP in + assert(testBuildSystem.value == nil, "Build system injector hook can only create a single TestBuildSystem") + let buildSystem = TestBuildSystem( + initializeData: SourceKitInitializeBuildResponseData( + indexDatabasePath: projectRoot.appendingPathComponent("index-db").path, + indexStorePath: projectRoot.appendingPathComponent("index-store").path, + prepareProvider: true, + sourceKitOptionsProvider: true + ), + connectionToSourceKitLSP: connectionToSourceKitLSP + ) + testBuildSystem.value = buildSystem + let connection = LocalConnection(receiverName: "TestBuildSystem") + connection.start(handler: buildSystem) + return connection + }) + ), + enableBackgroundIndexing: true + ) + let fileUrl = try XCTUnwrap(project.uri(for: "Test.swift").fileURL) + + var compilerArguments = [fileUrl.path] + if let defaultSDKPath { + compilerArguments += ["-sdk", defaultSDKPath] + } + + // We don't initially index Test.swift because we don't have build settings for it. + + try await XCTUnwrap(testBuildSystem.value).setBuildSettings( + for: DocumentURI(fileUrl), + to: TextDocumentSourceKitOptionsResponse(compilerArguments: compilerArguments) + ) + + // But once we get build settings for it, we should index the file. + + try await repeatUntilExpectedResult { + let workspaceSymbols = try await project.testClient.send(WorkspaceSymbolsRequest(query: "myTestFunc")) + guard let workspaceSymbols, !workspaceSymbols.isEmpty else { + // No results yet, indexing of the file might not have finished. + return false + } + XCTAssertEqual( + workspaceSymbols, + [ + .symbolInformation( + SymbolInformation( + name: "myTestFunc()", + kind: .function, + location: try project.location(from: "1️⃣", to: "1️⃣", in: "Test.swift") + ) + ) + ] + ) + return true + } + } } extension HoverResponseContents { diff --git a/Tests/SourceKitLSPTests/WorkspaceSymbolsTests.swift b/Tests/SourceKitLSPTests/WorkspaceSymbolsTests.swift index 4a9882a0..af743377 100644 --- a/Tests/SourceKitLSPTests/WorkspaceSymbolsTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceSymbolsTests.swift @@ -76,20 +76,14 @@ class WorkspaceSymbolsTests: XCTestCase { SymbolInformation( name: "afuncFromA()", kind: .function, - location: Location( - uri: try project.uri(for: "PackageALib.swift"), - range: Range(try project.position(of: "1️⃣", in: "PackageALib.swift")) - ) + location: try project.location(from: "1️⃣", to: "1️⃣", in: "PackageALib.swift") ) ), .symbolInformation( SymbolInformation( name: "funcFromB()", kind: .function, - location: Location( - uri: try project.uri(for: "PackageBLib.swift"), - range: Range(try project.position(of: "2️⃣", in: "PackageBLib.swift")) - ) + location: try project.location(from: "2️⃣", to: "2️⃣", in: "PackageBLib.swift") ) ), ]