@@ -343,7 +343,26 @@ package actor BuildServerManager: QueueBasedMessageHandler {
343343 }
344344
345345 /// Provider of file to main file mappings.
346- private var mainFilesProvider : MainFilesProvider ?
346+ ///
347+ /// Force-unwrapped optional because initializing it requires access to `self`.
348+ private var mainFilesProvider : Task < MainFilesProvider ? , Never > ! {
349+ didSet {
350+ // Must only be set once
351+ precondition ( oldValue == nil )
352+ precondition ( mainFilesProvider != nil )
353+ }
354+ }
355+
356+ package func mainFilesProvider< T: MainFilesProvider > ( as: T . Type ) async -> T ? {
357+ guard let mainFilesProvider = mainFilesProvider else {
358+ return nil
359+ }
360+ guard let index = await mainFilesProvider. value as? T else {
361+ logger. fault ( " Expected the main files provider of the build server manager to be an ` \( T . self) ` " )
362+ return nil
363+ }
364+ return index
365+ }
347366
348367 /// Build server delegate that will receive notifications about setting changes, etc.
349368 private weak var delegate : BuildServerManagerDelegate ?
@@ -465,7 +484,11 @@ package actor BuildServerManager: QueueBasedMessageHandler {
465484 toolchainRegistry: ToolchainRegistry ,
466485 options: SourceKitLSPOptions ,
467486 connectionToClient: BuildServerManagerConnectionToClient ,
468- buildServerHooks: BuildServerHooks
487+ buildServerHooks: BuildServerHooks ,
488+ createMainFilesProvider:
489+ @escaping @Sendable (
490+ SourceKitInitializeBuildResponseData ? , _ mainFilesChangedCallback: @escaping @Sendable ( ) async -> Void
491+ ) async -> MainFilesProvider ?
469492 ) async {
470493 self . toolchainRegistry = toolchainRegistry
471494 self . options = options
@@ -578,6 +601,11 @@ package actor BuildServerManager: QueueBasedMessageHandler {
578601 await buildServerAdapter. send ( OnBuildInitializedNotification ( ) )
579602 return initializeResponse
580603 }
604+ self . mainFilesProvider = Task {
605+ await createMainFilesProvider ( initializationData) { [ weak self] in
606+ await self ? . mainFilesChanged ( )
607+ }
608+ }
581609 }
582610
583611 /// Explicitly shut down the build server.
@@ -630,12 +658,6 @@ package actor BuildServerManager: QueueBasedMessageHandler {
630658 self . delegate = delegate
631659 }
632660
633- /// - Note: Needed because we need the `indexStorePath` and `indexDatabasePath` from the build server to create an
634- /// IndexStoreDB, which serves as the `MainFilesProvider`. And thus this can't be set during initialization.
635- package func setMainFilesProvider( _ mainFilesProvider: MainFilesProvider ? ) {
636- self . mainFilesProvider = mainFilesProvider
637- }
638-
639661 // MARK: Handling messages from the build server
640662
641663 package func handle( notification: some NotificationType ) async {
@@ -1274,13 +1296,12 @@ package actor BuildServerManager: QueueBasedMessageHandler {
12741296 }
12751297
12761298 private func buildTargets( ) async throws -> [ BuildTargetIdentifier : BuildTargetInfo ] {
1277- guard let buildServerAdapter = try await buildServerAdapterAfterInitialized else {
1278- return [ : ]
1279- }
1280-
12811299 let request = WorkspaceBuildTargetsRequest ( )
12821300 let result = try await cachedBuildTargets. get ( request, isolation: self ) { request in
12831301 let result = try await withTimeout ( self . options. buildServerWorkspaceRequestsTimeoutOrDefault) {
1302+ guard let buildServerAdapter = try await self . buildServerAdapterAfterInitialized else {
1303+ return [ : ]
1304+ }
12841305 let buildTargets = try await buildServerAdapter. send ( request) . targets
12851306 let ( depths, dependents) = await self . targetDepthsAndDependents ( for: buildTargets)
12861307 var result : [ BuildTargetIdentifier : BuildTargetInfo ] = [ : ]
@@ -1325,7 +1346,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
13251346 }
13261347
13271348 package func sourceFiles( in targets: Set < BuildTargetIdentifier > ) async throws -> [ SourcesItem ] {
1328- guard let buildServerAdapter = try await buildServerAdapterAfterInitialized , !targets. isEmpty else {
1349+ guard !targets. isEmpty else {
13291350 return [ ]
13301351 }
13311352
@@ -1346,6 +1367,9 @@ package actor BuildServerManager: QueueBasedMessageHandler {
13461367
13471368 let response = try await cachedTargetSources. get ( request, isolation: self ) { request in
13481369 try await withTimeout ( self . options. buildServerWorkspaceRequestsTimeoutOrDefault) {
1370+ guard let buildServerAdapter = try await self . buildServerAdapterAfterInitialized else {
1371+ return BuildTargetSourcesResponse ( items: [ ] )
1372+ }
13491373 return try await buildServerAdapter. send ( request)
13501374 } resultReceivedAfterTimeout: { newResult in
13511375 await self . buildTargetsDidChange ( . sourceFilesReceivedResultAfterTimeout( request: request, newResult: newResult) )
@@ -1393,7 +1417,6 @@ package actor BuildServerManager: QueueBasedMessageHandler {
13931417 /// - Important: This method returns both buildable and non-buildable source files. Callers need to check
13941418 /// `SourceFileInfo.isBuildable` if they are only interested in buildable source files.
13951419 private func sourceFilesAndDirectories( ) async throws -> SourceFilesAndDirectories {
1396- let supportsOutputPaths = await initializationData? . outputPathsProvider ?? false
13971420
13981421 return try await cachedSourceFilesAndDirectories. get (
13991422 SourceFilesAndDirectoriesKey ( ) ,
@@ -1411,7 +1434,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
14111434 for sourceItem in sourcesItem. sources {
14121435 let sourceKitData = sourceItem. sourceKitData
14131436 let outputPath : OutputPath ? =
1414- if !supportsOutputPaths {
1437+ if !( await self . initializationData ? . outputPathsProvider ?? false ) {
14151438 . notSupported
14161439 } else if let outputPath = sourceKitData? . outputPath {
14171440 . path( outputPath)
@@ -1499,7 +1522,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
14991522 /// path is `/tmp`). If the realpath that indexstore-db returns could not be found in the build server's source files
15001523 /// but the standardized path is part of the source files, return the standardized path instead.
15011524 package func mainFiles( containing uri: DocumentURI ) async -> [ DocumentURI ] {
1502- guard let mainFilesProvider else {
1525+ guard let mainFilesProvider = await mainFilesProvider . value else {
15031526 return [ uri]
15041527 }
15051528 let mainFiles = Array ( await mainFilesProvider. mainFiles ( containing: uri, crossLanguage: false ) )
0 commit comments