@@ -65,9 +65,21 @@ private func getDefaultToolchain(_ toolchainRegistry: ToolchainRegistry) async -
65
65
return await toolchainRegistry. default
66
66
}
67
67
68
+ fileprivate extension BuildTriple {
69
+ /// A string that can be used to identify the build triple in `ConfiguredTarget.runDestinationID`.
70
+ var id : String {
71
+ switch self {
72
+ case . tools:
73
+ return " tools "
74
+ case . destination:
75
+ return " destination "
76
+ }
77
+ }
78
+ }
79
+
68
80
fileprivate extension ConfiguredTarget {
69
81
init ( _ buildTarget: any SwiftBuildTarget ) {
70
- self . init ( targetID: buildTarget. name, runDestinationID: " dummy " )
82
+ self . init ( targetID: buildTarget. name, runDestinationID: buildTarget . buildTriple . id )
71
83
}
72
84
73
85
static let forPackageManifest = ConfiguredTarget ( targetID: " " , runDestinationID: " " )
@@ -117,8 +129,8 @@ public actor SwiftPMBuildSystem {
117
129
initialValue: nil
118
130
)
119
131
120
- private var fileToTarget : [ DocumentURI : SwiftBuildTarget ] = [ : ]
121
- private var sourceDirToTarget : [ DocumentURI : SwiftBuildTarget ] = [ : ]
132
+ private var fileToTargets : [ DocumentURI : [ SwiftBuildTarget ] ] = [ : ]
133
+ private var sourceDirToTargets : [ DocumentURI : [ SwiftBuildTarget ] ] = [ : ]
122
134
123
135
/// Maps configured targets ids to their SwiftPM build target as well as an index in their topological sorting.
124
136
///
@@ -320,40 +332,34 @@ extension SwiftPMBuildSystem {
320
332
321
333
self . targets = Dictionary (
322
334
try buildDescription. allTargetsInTopologicalOrder ( in: modulesGraph) . enumerated ( ) . map { ( index, target) in
323
- return ( key: ConfiguredTarget ( target) , ( index, target) )
335
+ return ( key: ConfiguredTarget ( target) , value : ( index, target) )
324
336
} ,
325
337
uniquingKeysWith: { first, second in
326
338
logger. fault ( " Found two targets with the same name \( first. buildTarget. name) " )
327
339
return second
328
340
}
329
341
)
330
342
331
- self . fileToTarget = [ DocumentURI: SwiftBuildTarget] (
343
+ self . fileToTargets = [ DocumentURI: [ SwiftBuildTarget] ] (
332
344
modulesGraph. allTargets. flatMap { target in
333
- return target. sources. paths. compactMap {
345
+ return target. sources. paths. compactMap { ( filePath ) -> ( key : DocumentURI , value : [ SwiftBuildTarget ] ) ? in
334
346
guard let buildTarget = buildDescription. getBuildTarget ( for: target, in: modulesGraph) else {
335
347
return nil
336
348
}
337
- return ( key: DocumentURI ( $0 . asURL) , value: buildTarget)
349
+ return ( key: DocumentURI ( filePath . asURL) , value: [ buildTarget] )
338
350
}
339
351
} ,
340
- uniquingKeysWith: { td, _ in
341
- // FIXME: is there a preferred target?
342
- return td
343
- }
352
+ uniquingKeysWith: { $0 + $1 }
344
353
)
345
354
346
- self . sourceDirToTarget = [ DocumentURI: SwiftBuildTarget] (
347
- modulesGraph. allTargets. compactMap { ( target) -> ( DocumentURI , SwiftBuildTarget ) ? in
355
+ self . sourceDirToTargets = [ DocumentURI: [ SwiftBuildTarget] ] (
356
+ modulesGraph. allTargets. compactMap { ( target) -> ( DocumentURI , [ SwiftBuildTarget ] ) ? in
348
357
guard let buildTarget = buildDescription. getBuildTarget ( for: target, in: modulesGraph) else {
349
358
return nil
350
359
}
351
- return ( key: DocumentURI ( target. sources. root. asURL) , value: buildTarget)
360
+ return ( key: DocumentURI ( target. sources. root. asURL) , value: [ buildTarget] )
352
361
} ,
353
- uniquingKeysWith: { td, _ in
354
- // FIXME: is there a preferred target?
355
- return td
356
- }
362
+ uniquingKeysWith: { $0 + $1 }
357
363
)
358
364
359
365
guard let delegate = self . delegate else {
@@ -471,8 +477,9 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
471
477
return [ ]
472
478
}
473
479
474
- if let target = buildTarget ( for: uri) {
475
- return [ ConfiguredTarget ( target) ]
480
+ let targets = buildTargets ( for: uri)
481
+ if !targets. isEmpty {
482
+ return targets. map ( ConfiguredTarget . init)
476
483
}
477
484
478
485
if path. basename == " Package.swift " {
@@ -481,8 +488,8 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
481
488
return [ ConfiguredTarget . forPackageManifest]
482
489
}
483
490
484
- if let target = try ? inferredTarget ( for: path) {
485
- return [ target ]
491
+ if let targets = try ? inferredTargets ( for: path) {
492
+ return targets
486
493
}
487
494
488
495
return [ ]
@@ -655,21 +662,21 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
655
662
self . watchedFiles. remove ( uri)
656
663
}
657
664
658
- /// Returns the resolved target description for the given file, if one is known.
659
- private func buildTarget ( for file: DocumentURI ) -> SwiftBuildTarget ? {
660
- if let td = fileToTarget [ file] {
661
- return td
665
+ /// Returns the resolved target descriptions for the given file, if one is known.
666
+ private func buildTargets ( for file: DocumentURI ) -> [ SwiftBuildTarget ] {
667
+ if let targets = fileToTargets [ file] {
668
+ return targets
662
669
}
663
670
664
671
if let fileURL = file. fileURL,
665
672
let realpath = try ? resolveSymlinks ( AbsolutePath ( validating: fileURL. path) ) ,
666
- let td = fileToTarget [ DocumentURI ( realpath. asURL) ]
673
+ let targets = fileToTargets [ DocumentURI ( realpath. asURL) ]
667
674
{
668
- fileToTarget [ file] = td
669
- return td
675
+ fileToTargets [ file] = targets
676
+ return targets
670
677
}
671
678
672
- return nil
679
+ return [ ]
673
680
}
674
681
675
682
/// An event is relevant if it modifies a file that matches one of the file rules used by the SwiftPM workspace.
@@ -707,10 +714,10 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
707
714
// If a Swift file within a target is updated, reload all the other files within the target since they might be
708
715
// referring to a function in the updated file.
709
716
for event in events {
710
- guard event. uri. fileURL? . pathExtension == " swift " , let target = fileToTarget [ event. uri] else {
717
+ guard event. uri. fileURL? . pathExtension == " swift " , let targets = fileToTargets [ event. uri] else {
711
718
continue
712
719
}
713
- filesWithUpdatedDependencies. formUnion ( target . sources. map { DocumentURI ( $0 ) } )
720
+ filesWithUpdatedDependencies. formUnion ( targets . flatMap ( \ . sources) . map ( DocumentURI . init ) )
714
721
}
715
722
716
723
// If a `.swiftmodule` file is updated, this means that we have performed a build / are
@@ -723,7 +730,7 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
723
730
// If we have background indexing enabled, this is not necessary because we call `fileDependenciesUpdated` when
724
731
// preparation of a target finishes.
725
732
if !isForIndexBuild, events. contains ( where: { $0. uri. fileURL? . pathExtension == " swiftmodule " } ) {
726
- filesWithUpdatedDependencies. formUnion ( self . fileToTarget . keys)
733
+ filesWithUpdatedDependencies. formUnion ( self . fileToTargets . keys)
727
734
}
728
735
await self . fileDependenciesUpdatedDebouncer. scheduleCall ( filesWithUpdatedDependencies)
729
736
}
@@ -736,12 +743,12 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
736
743
}
737
744
738
745
public func sourceFiles( ) -> [ SourceFileInfo ] {
739
- return fileToTarget . compactMap { ( uri, target ) -> SourceFileInfo ? in
746
+ return fileToTargets . compactMap { ( uri, targets ) -> SourceFileInfo ? in
740
747
// We should only set mayContainTests to `true` for files from test targets
741
748
// (https://github.com/apple/sourcekit-lsp/issues/1174).
742
749
return SourceFileInfo (
743
750
uri: uri,
744
- isPartOfRootProject: target . isPartOfRootPackage,
751
+ isPartOfRootProject: targets . contains ( where : \ . isPartOfRootPackage) ,
745
752
mayContainTests: true
746
753
)
747
754
}
@@ -777,24 +784,25 @@ extension SwiftPMBuildSystem {
777
784
/// This finds the target a file belongs to based on its location in the file system.
778
785
///
779
786
/// This is primarily intended to find the target a header belongs to.
780
- private func inferredTarget ( for path: AbsolutePath ) throws -> ConfiguredTarget ? {
781
- func impl( _ path: AbsolutePath ) throws -> ConfiguredTarget ? {
787
+ private func inferredTargets ( for path: AbsolutePath ) throws -> [ ConfiguredTarget ] {
788
+ func impl( _ path: AbsolutePath ) throws -> [ ConfiguredTarget ] {
782
789
var dir = path. parentDirectory
783
790
while !dir. isRoot {
784
- if let buildTarget = sourceDirToTarget [ DocumentURI ( dir. asURL) ] {
785
- return ConfiguredTarget ( buildTarget )
791
+ if let buildTargets = sourceDirToTargets [ DocumentURI ( dir. asURL) ] {
792
+ return buildTargets . map ( ConfiguredTarget . init )
786
793
}
787
794
dir = dir. parentDirectory
788
795
}
789
- return nil
796
+ return [ ]
790
797
}
791
798
792
- if let result = try impl ( path) {
799
+ let result = try impl ( path)
800
+ if !result. isEmpty {
793
801
return result
794
802
}
795
803
796
804
let canonicalPath = try resolveSymlinks ( path)
797
- return try canonicalPath == path ? nil : impl ( canonicalPath)
805
+ return try canonicalPath == path ? [ ] : impl ( canonicalPath)
798
806
}
799
807
}
800
808
0 commit comments