@@ -21,6 +21,7 @@ import SwiftExtensions
21
21
import ToolchainRegistry
22
22
23
23
import struct TSCBasic. AbsolutePath
24
+ import func TSCBasic. resolveSymlinks
24
25
25
26
fileprivate typealias RequestCache < Request: RequestType & Hashable > = Cache < Request , Request . Response >
26
27
@@ -78,6 +79,18 @@ fileprivate extension BuildTarget {
78
79
}
79
80
}
80
81
82
+ fileprivate extension DocumentURI {
83
+ /// If this is a file URI pointing to a symlink, return the realpath of the URI, otherwise return `nil`.
84
+ var symlinkTarget : DocumentURI ? {
85
+ guard let fileUrl = fileURL, let path = AbsolutePath ( validatingOrNil: fileUrl. path) ,
86
+ let symlinksResolved = try ? TSCBasic . resolveSymlinks ( path) , symlinksResolved != path
87
+ else {
88
+ return nil
89
+ }
90
+ return DocumentURI ( symlinksResolved. asURL)
91
+ }
92
+ }
93
+
81
94
/// Entry point for all build system queries.
82
95
package actor BuildSystemManager : QueueBasedMessageHandler {
83
96
package static let signpostLoggingCategory : String = " build-system-manager-message-handling "
@@ -570,9 +583,8 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
570
583
return nil
571
584
}
572
585
if connectionToBuildSystem == nil {
573
- // If there is no build system and we only have the fallback build system,
574
- // we will never get real build settings. Consider the build settings
575
- // non-fallback.
586
+ // If there is no build system and we only have the fallback build system, we will never get real build settings.
587
+ // Consider the build settings non-fallback.
576
588
settings. isFallback = false
577
589
}
578
590
return settings
@@ -588,16 +600,37 @@ package actor BuildSystemManager: QueueBasedMessageHandler {
588
600
for document: DocumentURI ,
589
601
language: Language
590
602
) async -> FileBuildSettings ? {
591
- let mainFile = await mainFile ( for: document, language: language)
592
- let target = await canonicalTarget ( for: mainFile)
593
- guard var settings = await buildSettings ( for: mainFile, in: target, language: language) else {
603
+ func mainFileAndSettings(
604
+ basedOn document: DocumentURI
605
+ ) async -> ( mainFile: DocumentURI , settings: FileBuildSettings ) ? {
606
+ let mainFile = await self . mainFile ( for: document, language: language)
607
+ let target = await canonicalTarget ( for: mainFile)
608
+ guard let settings = await buildSettings ( for: mainFile, in: target, language: language) else {
609
+ return nil
610
+ }
611
+ return ( mainFile, settings)
612
+ }
613
+
614
+ var settings : FileBuildSettings ?
615
+ var mainFile : DocumentURI ?
616
+ if let mainFileAndSettings = await mainFileAndSettings ( basedOn: document) {
617
+ ( mainFile, settings) = mainFileAndSettings
618
+ }
619
+ if settings? . isFallback ?? true , let symlinkTarget = document. symlinkTarget,
620
+ let mainFileAndSettings = await mainFileAndSettings ( basedOn: symlinkTarget)
621
+ {
622
+ ( mainFile, settings) = mainFileAndSettings
623
+ }
624
+ guard var settings, let mainFile else {
594
625
return nil
595
626
}
627
+
596
628
if mainFile != document {
597
629
// If the main file isn't the file itself, we need to patch the build settings
598
630
// to reference `document` instead of `mainFile`.
599
631
settings = settings. patching ( newFile: document, originalFile: mainFile)
600
632
}
633
+
601
634
await BuildSettingsLogger . shared. log ( settings: settings, for: document)
602
635
return settings
603
636
}
0 commit comments