@@ -210,10 +210,10 @@ package actor SwiftPMBuildSystem {
210
210
/// Maps source and header files to the target that include them.
211
211
private var fileToTargets : [ DocumentURI : Set < BuildTargetIdentifier > ] = [ : ]
212
212
213
- /// Maps target ids to their SwiftPM build target as well as the depth at which they occur in the build
214
- /// graph. Top level targets on which no other target depends have a depth of `1`. Targets with dependencies have a
215
- /// greater depth.
216
- private var targets : [ BuildTargetIdentifier : ( buildTarget : SwiftBuildTarget , depth : Int ) ] = [ : ]
213
+ /// Maps target ids to their SwiftPM build target.
214
+ private var swiftPMTargets : [ BuildTargetIdentifier : SwiftBuildTarget ] = [ : ]
215
+
216
+ private var targetDependencies : [ BuildTargetIdentifier : Set < BuildTargetIdentifier > ] = [ : ]
217
217
218
218
static package func projectRoot(
219
219
for path: TSCBasic . AbsolutePath ,
@@ -361,6 +361,15 @@ package actor SwiftPMBuildSystem {
361
361
)
362
362
363
363
self . reloadPackageStatusCallback = reloadPackageStatusCallback
364
+
365
+ packageLoadingQueue. async {
366
+ await orLog ( " Initial package loading " ) {
367
+ // Schedule an initial generation of the build graph. Once the build graph is loaded, the build system will send
368
+ // call `fileHandlingCapabilityChanged`, which allows us to move documents to a workspace with this build
369
+ // system.
370
+ try await self . reloadPackageAssumingOnPackageLoadingQueue ( )
371
+ }
372
+ }
364
373
}
365
374
366
375
/// Creates a build system using the Swift Package Manager, if this workspace is a package.
@@ -398,15 +407,9 @@ package actor SwiftPMBuildSystem {
398
407
extension SwiftPMBuildSystem {
399
408
/// (Re-)load the package settings by parsing the manifest and resolving all the targets and
400
409
/// dependencies.
401
- @discardableResult
402
- package func schedulePackageReload( ) -> Task < Void , Swift . Error > {
403
- return packageLoadingQueue. asyncThrowing {
404
- try await self . reloadPackageImpl ( )
405
- }
406
- }
407
-
410
+ ///
408
411
/// - Important: Must only be called on `packageLoadingQueue`.
409
- private func reloadPackageImpl ( ) async throws {
412
+ private func reloadPackageAssumingOnPackageLoadingQueue ( ) async throws {
410
413
await reloadPackageStatusCallback ( . start)
411
414
await testHooks. reloadPackageDidStart ? ( )
412
415
defer {
@@ -437,22 +440,26 @@ extension SwiftPMBuildSystem {
437
440
/// properties because otherwise we might end up in an inconsistent state
438
441
/// with only some properties modified.
439
442
440
- self . targets = [ : ]
443
+ self . swiftPMTargets = [ : ]
441
444
self . fileToTargets = [ : ]
445
+ self . targetDependencies = [ : ]
446
+
442
447
buildDescription. traverseModules { buildTarget, parent, depth in
443
448
let targetIdentifier = orLog ( " Getting build target identifier " ) { try BuildTargetIdentifier ( buildTarget) }
444
449
guard let targetIdentifier else {
445
450
return
446
451
}
447
- var depth = depth
448
- if let existingDepth = targets [ targetIdentifier] ? . depth {
449
- depth = max ( existingDepth, depth)
450
- } else {
452
+ if swiftPMTargets [ targetIdentifier] == nil {
451
453
for source in buildTarget. sources + buildTarget. headers {
452
454
fileToTargets [ DocumentURI ( source) , default: [ ] ] . insert ( targetIdentifier)
453
455
}
454
456
}
455
- targets [ targetIdentifier] = ( buildTarget, depth)
457
+ if let parent,
458
+ let parentIdentifier = orLog ( " Getting parent build target identifier " , { try BuildTargetIdentifier ( parent) } )
459
+ {
460
+ self . targetDependencies [ parentIdentifier, default: [ ] ] . insert ( targetIdentifier)
461
+ }
462
+ swiftPMTargets [ targetIdentifier] = buildTarget
456
463
}
457
464
458
465
await messageHandler? . sendNotificationToSourceKitLSP ( DidChangeBuildTargetNotification ( changes: nil ) )
@@ -511,9 +518,9 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
511
518
}
512
519
513
520
package func buildTargets( request: BuildTargetsRequest ) async throws -> BuildTargetsResponse {
514
- let targets = self . targets . map { ( targetId, target) in
521
+ let targets = self . swiftPMTargets . map { ( targetId, target) in
515
522
var tags : [ BuildTargetTag ] = [ . test]
516
- if target. depth != 1 {
523
+ if ! target. isPartOfRootPackage {
517
524
tags. append ( . dependency)
518
525
}
519
526
return BuildTarget (
@@ -524,8 +531,7 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
524
531
capabilities: BuildTargetCapabilities ( ) ,
525
532
// Be conservative with the languages that might be used in the target. SourceKit-LSP doesn't use this property.
526
533
languageIds: [ . c, . cpp, . objective_c, . objective_cpp, . swift] ,
527
- // FIXME: (BSP migration) List the target's dependencies
528
- dependencies: [ ]
534
+ dependencies: self . targetDependencies [ targetId, default: [ ] ] . sorted { $0. uri. stringValue < $1. uri. stringValue }
529
535
)
530
536
}
531
537
return BuildTargetsResponse ( targets: targets)
@@ -536,10 +542,10 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
536
542
// TODO: Query The SwiftPM build system for the document's language and add it to SourceItem.data
537
543
// (https://github.com/swiftlang/sourcekit-lsp/issues/1267)
538
544
for target in request. targets {
539
- guard let swiftPMTarget = self . targets [ target] else {
545
+ guard let swiftPMTarget = self . swiftPMTargets [ target] else {
540
546
continue
541
547
}
542
- let sources = swiftPMTarget. buildTarget . sources. map {
548
+ let sources = swiftPMTarget. sources. map {
543
549
SourceItem ( uri: DocumentURI ( $0) , kind: . file, generated: false )
544
550
}
545
551
result. append ( SourcesItem ( target: target, sources: sources) )
@@ -557,13 +563,13 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
557
563
return try settings ( forPackageManifest: path)
558
564
}
559
565
560
- guard let buildTarget = self . targets [ request. target] ? . buildTarget else {
566
+ guard let swiftPMTarget = self . swiftPMTargets [ request. target] else {
561
567
logger. fault ( " Did not find target \( request. target. forLogging) " )
562
568
return nil
563
569
}
564
570
565
- if !buildTarget . sources. lazy. map ( DocumentURI . init) . contains ( request. textDocument. uri) ,
566
- let substituteFile = buildTarget . sources. sorted ( by: { $0. path < $1. path } ) . first
571
+ if !swiftPMTarget . sources. lazy. map ( DocumentURI . init) . contains ( request. textDocument. uri) ,
572
+ let substituteFile = swiftPMTarget . sources. sorted ( by: { $0. path < $1. path } ) . first
567
573
{
568
574
logger. info ( " Getting compiler arguments for \( url) using substitute file \( substituteFile) " )
569
575
// If `url` is not part of the target's source, it's most likely a header file. Fake compiler arguments for it
@@ -574,7 +580,7 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
574
580
// getting its compiler arguments and then patching up the compiler arguments by replacing the substitute file
575
581
// with the `.cpp` file.
576
582
let buildSettings = FileBuildSettings (
577
- compilerArguments: try await compilerArguments ( for: DocumentURI ( substituteFile) , in: buildTarget ) ,
583
+ compilerArguments: try await compilerArguments ( for: DocumentURI ( substituteFile) , in: swiftPMTarget ) ,
578
584
workingDirectory: projectRoot. pathString
579
585
) . patching ( newFile: try resolveSymlinks ( path) . pathString, originalFile: substituteFile. absoluteString)
580
586
return SourceKitOptionsResponse (
@@ -584,7 +590,7 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
584
590
}
585
591
586
592
return SourceKitOptionsResponse (
587
- compilerArguments: try await compilerArguments ( for: request. textDocument. uri, in: buildTarget ) ,
593
+ compilerArguments: try await compilerArguments ( for: request. textDocument. uri, in: swiftPMTarget ) ,
588
594
workingDirectory: projectRoot. pathString
589
595
)
590
596
}
@@ -620,43 +626,10 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
620
626
return InverseSourcesResponse ( targets: targets ( for: request. textDocument. uri) )
621
627
}
622
628
623
- package func scheduleBuildGraphGeneration( ) async throws {
624
- self . schedulePackageReload ( )
625
- }
626
-
627
629
package func waitForUpToDateBuildGraph( ) async {
628
630
await self . packageLoadingQueue. async { } . valuePropagatingCancellation
629
631
}
630
632
631
- package func topologicalSort( of targets: [ BuildTargetIdentifier ] ) -> [ BuildTargetIdentifier ] ? {
632
- return targets. sorted { ( lhs: BuildTargetIdentifier , rhs: BuildTargetIdentifier ) -> Bool in
633
- let lhsDepth = self . targets [ lhs] ? . depth ?? 0
634
- let rhsDepth = self . targets [ rhs] ? . depth ?? 0
635
- return lhsDepth > rhsDepth
636
- }
637
- }
638
-
639
- package func targets( dependingOn targets: [ BuildTargetIdentifier ] ) -> [ BuildTargetIdentifier ] ? {
640
- let targetDepths = targets. compactMap { self . targets [ $0] ? . depth }
641
- let minimumTargetDepth : Int ?
642
- if targetDepths. count == targets. count {
643
- minimumTargetDepth = targetDepths. max ( )
644
- } else {
645
- // One of the targets didn't have an entry in self.targets. We don't know what might depend on it.
646
- minimumTargetDepth = nil
647
- }
648
-
649
- // Files that occur before the target in the topological sorting don't depend on it.
650
- // Ideally, we should consult the dependency graph here for more accurate dependency analysis instead of relying on
651
- // a flattened list (https://github.com/swiftlang/sourcekit-lsp/issues/1312).
652
- return self . targets. compactMap { ( targets, value) -> BuildTargetIdentifier ? in
653
- if let minimumTargetDepth, value. depth >= minimumTargetDepth {
654
- return nil
655
- }
656
- return targets
657
- }
658
- }
659
-
660
633
package func prepare( request: PrepareTargetsRequest ) async throws -> VoidResponse {
661
634
// TODO: Support preparation of multiple targets at once. (https://github.com/swiftlang/sourcekit-lsp/issues/1262)
662
635
for target in request. targets {
@@ -810,25 +783,12 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuiltInBuildSystem {
810
783
package func didChangeWatchedFiles( notification: BuildServerProtocol . DidChangeWatchedFilesNotification ) async {
811
784
if notification. changes. contains ( where: { self . fileEventShouldTriggerPackageReload ( event: $0) } ) {
812
785
logger. log ( " Reloading package because of file change " )
813
- await orLog ( " Reloading package " ) {
814
- try await self . schedulePackageReload ( ) . value
815
- }
816
- }
817
- }
818
-
819
- package func sourceFiles( ) -> [ SourceFileInfo ] {
820
- var sourceFiles : [ DocumentURI : SourceFileInfo ] = [ : ]
821
- for (buildTarget, depth) in self . targets. values {
822
- for sourceFile in buildTarget. sources {
823
- let uri = DocumentURI ( sourceFile)
824
- sourceFiles [ uri] = SourceFileInfo (
825
- uri: uri,
826
- isPartOfRootProject: depth == 1 || ( sourceFiles [ uri] ? . isPartOfRootProject ?? false ) ,
827
- mayContainTests: true
828
- )
829
- }
786
+ await packageLoadingQueue. async {
787
+ await orLog ( " Reloading package " ) {
788
+ try await self . reloadPackageAssumingOnPackageLoadingQueue ( )
789
+ }
790
+ } . valuePropagatingCancellation
830
791
}
831
- return sourceFiles. values. sorted { $0. uri. pseudoPath < $1. uri. pseudoPath }
832
792
}
833
793
834
794
package func addSourceFilesDidChangeCallback( _ callback: @Sendable @escaping ( ) async -> Void ) async {
0 commit comments