@@ -338,7 +338,10 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
338
338
let files : [ DocumentURI : SourceFileInfo ]
339
339
340
340
/// The source directories in the workspace, ie. all `SourceItem`s that have `kind == .directory`.
341
- let directories : [ DocumentURI : SourceFileInfo ]
341
+ ///
342
+ /// `pathComponents` is the result of `key.fileURL?.pathComponents`. We frequently need these path components to
343
+ /// determine if a file is descendent of the directory and computing them from the `DocumentURI` is expensive.
344
+ let directories : [ DocumentURI : ( pathComponents: [ String ] ? , info: SourceFileInfo ) ]
342
345
}
343
346
344
347
private let cachedSourceFilesAndDirectories = Cache < SourceFilesAndDirectoriesKey , SourceFilesAndDirectories > ( )
@@ -679,12 +682,12 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
679
682
if let targets = filesAndDirectories. files [ document] ? . targets {
680
683
result. formUnion ( targets)
681
684
}
682
- if !filesAndDirectories. directories. isEmpty, let documentPath = document. fileURL {
683
- for (directory, info) in filesAndDirectories. directories {
684
- guard let directoryPath = directory. fileURL else {
685
+ if !filesAndDirectories. directories. isEmpty, let documentPathComponents = document. fileURL? . pathComponents {
686
+ for (directory, ( directoryPathComponents , info) ) in filesAndDirectories. directories {
687
+ guard let directoryPathComponents , let directoryPath = directory. fileURL else {
685
688
continue
686
689
}
687
- if documentPath . isDescendant ( of: directoryPath ) {
690
+ if isDescendant ( documentPathComponents , of: directoryPathComponents ) {
688
691
result. formUnion ( info. targets)
689
692
}
690
693
}
@@ -1055,7 +1058,7 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
1055
1058
1056
1059
return try await cachedSourceFilesAndDirectories. get ( key, isolation: self ) { key in
1057
1060
var files : [ DocumentURI : SourceFileInfo ] = [ : ]
1058
- var directories : [ DocumentURI : SourceFileInfo ] = [ : ]
1061
+ var directories : [ DocumentURI : ( pathComponents : [ String ] ? , info : SourceFileInfo ) ] = [ : ]
1059
1062
for sourcesItem in key. sourcesItems {
1060
1063
let target = targets [ sourcesItem. target] ? . target
1061
1064
let isPartOfRootProject = !( target? . tags. contains ( . dependency) ?? false )
@@ -1077,7 +1080,9 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
1077
1080
case . file:
1078
1081
files [ sourceItem. uri] = info. merging ( files [ sourceItem. uri] )
1079
1082
case . directory:
1080
- directories [ sourceItem. uri] = info. merging ( directories [ sourceItem. uri] )
1083
+ directories [ sourceItem. uri] = (
1084
+ sourceItem. uri. fileURL? . pathComponents, info. merging ( directories [ sourceItem. uri] ? . info)
1085
+ )
1081
1086
}
1082
1087
}
1083
1088
}
@@ -1226,3 +1231,12 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
1226
1231
}
1227
1232
}
1228
1233
}
1234
+
1235
+ /// Returns `true` if the path components `selfPathComponents`, retrieved from `URL.pathComponents` are a descendent
1236
+ /// of the other path components.
1237
+ ///
1238
+ /// This operates directly on path components instead of `URL`s because computing the path components of a URL is
1239
+ /// expensive and this allows us to cache the path components.
1240
+ private func isDescendant( _ selfPathComponents: [ String ] , of otherPathComponents: [ String ] ) -> Bool {
1241
+ return selfPathComponents. dropLast ( ) . starts ( with: otherPathComponents)
1242
+ }
0 commit comments