@@ -65,9 +65,21 @@ private func getDefaultToolchain(_ toolchainRegistry: ToolchainRegistry) async -
6565 return await toolchainRegistry. default
6666}
6767
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+
6880fileprivate extension ConfiguredTarget {
6981 init ( _ buildTarget: any SwiftBuildTarget ) {
70- self . init ( targetID: buildTarget. name, runDestinationID: " dummy " )
82+ self . init ( targetID: buildTarget. name, runDestinationID: buildTarget . buildTriple . id )
7183 }
7284
7385 static let forPackageManifest = ConfiguredTarget ( targetID: " " , runDestinationID: " " )
@@ -117,8 +129,8 @@ public actor SwiftPMBuildSystem {
117129 initialValue: nil
118130 )
119131
120- private var fileToTarget : [ DocumentURI : SwiftBuildTarget ] = [ : ]
121- private var sourceDirToTarget : [ DocumentURI : SwiftBuildTarget ] = [ : ]
132+ private var fileToTargets : [ DocumentURI : [ SwiftBuildTarget ] ] = [ : ]
133+ private var sourceDirToTargets : [ DocumentURI : [ SwiftBuildTarget ] ] = [ : ]
122134
123135 /// Maps configured targets ids to their SwiftPM build target as well as an index in their topological sorting.
124136 ///
@@ -320,40 +332,34 @@ extension SwiftPMBuildSystem {
320332
321333 self . targets = Dictionary (
322334 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) )
324336 } ,
325337 uniquingKeysWith: { first, second in
326338 logger. fault ( " Found two targets with the same name \( first. buildTarget. name) " )
327339 return second
328340 }
329341 )
330342
331- self . fileToTarget = [ DocumentURI: SwiftBuildTarget] (
343+ self . fileToTargets = [ DocumentURI: [ SwiftBuildTarget] ] (
332344 modulesGraph. allTargets. flatMap { target in
333- return target. sources. paths. compactMap {
345+ return target. sources. paths. compactMap { ( filePath ) -> ( key : DocumentURI , value : [ SwiftBuildTarget ] ) ? in
334346 guard let buildTarget = buildDescription. getBuildTarget ( for: target, in: modulesGraph) else {
335347 return nil
336348 }
337- return ( key: DocumentURI ( $0 . asURL) , value: buildTarget)
349+ return ( key: DocumentURI ( filePath . asURL) , value: [ buildTarget] )
338350 }
339351 } ,
340- uniquingKeysWith: { td, _ in
341- // FIXME: is there a preferred target?
342- return td
343- }
352+ uniquingKeysWith: { $0 + $1 }
344353 )
345354
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
348357 guard let buildTarget = buildDescription. getBuildTarget ( for: target, in: modulesGraph) else {
349358 return nil
350359 }
351- return ( key: DocumentURI ( target. sources. root. asURL) , value: buildTarget)
360+ return ( key: DocumentURI ( target. sources. root. asURL) , value: [ buildTarget] )
352361 } ,
353- uniquingKeysWith: { td, _ in
354- // FIXME: is there a preferred target?
355- return td
356- }
362+ uniquingKeysWith: { $0 + $1 }
357363 )
358364
359365 guard let delegate = self . delegate else {
@@ -471,8 +477,9 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
471477 return [ ]
472478 }
473479
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)
476483 }
477484
478485 if path. basename == " Package.swift " {
@@ -481,8 +488,8 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
481488 return [ ConfiguredTarget . forPackageManifest]
482489 }
483490
484- if let target = try ? inferredTarget ( for: path) {
485- return [ target ]
491+ if let targets = try ? inferredTargets ( for: path) {
492+ return targets
486493 }
487494
488495 return [ ]
@@ -655,21 +662,21 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
655662 self . watchedFiles. remove ( uri)
656663 }
657664
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
662669 }
663670
664671 if let fileURL = file. fileURL,
665672 let realpath = try ? resolveSymlinks ( AbsolutePath ( validating: fileURL. path) ) ,
666- let td = fileToTarget [ DocumentURI ( realpath. asURL) ]
673+ let targets = fileToTargets [ DocumentURI ( realpath. asURL) ]
667674 {
668- fileToTarget [ file] = td
669- return td
675+ fileToTargets [ file] = targets
676+ return targets
670677 }
671678
672- return nil
679+ return [ ]
673680 }
674681
675682 /// 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 {
707714 // If a Swift file within a target is updated, reload all the other files within the target since they might be
708715 // referring to a function in the updated file.
709716 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 {
711718 continue
712719 }
713- filesWithUpdatedDependencies. formUnion ( target . sources. map { DocumentURI ( $0 ) } )
720+ filesWithUpdatedDependencies. formUnion ( targets . flatMap ( \ . sources) . map ( DocumentURI . init ) )
714721 }
715722
716723 // If a `.swiftmodule` file is updated, this means that we have performed a build / are
@@ -723,7 +730,7 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
723730 // If we have background indexing enabled, this is not necessary because we call `fileDependenciesUpdated` when
724731 // preparation of a target finishes.
725732 if !isForIndexBuild, events. contains ( where: { $0. uri. fileURL? . pathExtension == " swiftmodule " } ) {
726- filesWithUpdatedDependencies. formUnion ( self . fileToTarget . keys)
733+ filesWithUpdatedDependencies. formUnion ( self . fileToTargets . keys)
727734 }
728735 await self . fileDependenciesUpdatedDebouncer. scheduleCall ( filesWithUpdatedDependencies)
729736 }
@@ -736,12 +743,12 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
736743 }
737744
738745 public func sourceFiles( ) -> [ SourceFileInfo ] {
739- return fileToTarget . compactMap { ( uri, target ) -> SourceFileInfo ? in
746+ return fileToTargets . compactMap { ( uri, targets ) -> SourceFileInfo ? in
740747 // We should only set mayContainTests to `true` for files from test targets
741748 // (https://github.com/apple/sourcekit-lsp/issues/1174).
742749 return SourceFileInfo (
743750 uri: uri,
744- isPartOfRootProject: target . isPartOfRootPackage,
751+ isPartOfRootProject: targets . contains ( where : \ . isPartOfRootPackage) ,
745752 mayContainTests: true
746753 )
747754 }
@@ -777,24 +784,25 @@ extension SwiftPMBuildSystem {
777784 /// This finds the target a file belongs to based on its location in the file system.
778785 ///
779786 /// 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 ] {
782789 var dir = path. parentDirectory
783790 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 )
786793 }
787794 dir = dir. parentDirectory
788795 }
789- return nil
796+ return [ ]
790797 }
791798
792- if let result = try impl ( path) {
799+ let result = try impl ( path)
800+ if !result. isEmpty {
793801 return result
794802 }
795803
796804 let canonicalPath = try resolveSymlinks ( path)
797- return try canonicalPath == path ? nil : impl ( canonicalPath)
805+ return try canonicalPath == path ? [ ] : impl ( canonicalPath)
798806 }
799807}
800808
0 commit comments