@@ -154,16 +154,27 @@ fileprivate extension String {
154154extension Diagnostic {
155155
156156 /// Creates a diagnostic from a sourcekitd response dictionary.
157+ ///
158+ /// `snapshot` is the snapshot of the document for which the diagnostics are generated.
159+ /// `documentManager` is used to resolve positions of notes in secondary files.
157160 init ? (
158161 _ diag: SKDResponseDictionary ,
159162 in snapshot: DocumentSnapshot ,
163+ documentManager: DocumentManager ,
160164 useEducationalNoteAsCode: Bool
161165 ) {
162- // FIXME: this assumes that the diagnostics are all in the same file.
163-
164166 let keys = diag. sourcekitd. keys
165167 let values = diag. sourcekitd. values
166168
169+ guard let filePath: String = diag [ keys. filePath] else {
170+ logger. fault ( " Missing file path in diagnostic " )
171+ return nil
172+ }
173+ guard filePath == snapshot. uri. pseudoPath else {
174+ logger. error ( " Ignoring diagnostic from a different file: \( filePath) " )
175+ return nil
176+ }
177+
167178 guard let message: String = diag [ keys. description] ? . withFirstLetterUppercased ( ) else { return nil }
168179
169180 var range : Range < Position > ? = nil
@@ -237,7 +248,13 @@ extension Diagnostic {
237248 if let sknotes: SKDResponseArray = diag [ keys. diagnostics] {
238249 notes = [ ]
239250 sknotes. forEach { ( _, sknote) -> Bool in
240- guard let note = DiagnosticRelatedInformation ( sknote, in: snapshot) else { return true }
251+ guard
252+ let note = DiagnosticRelatedInformation (
253+ sknote,
254+ primaryDocumentSnapshot: snapshot,
255+ documentManager: documentManager
256+ )
257+ else { return true }
241258 notes? . append ( note)
242259 return true
243260 }
@@ -309,9 +326,28 @@ extension Diagnostic {
309326extension DiagnosticRelatedInformation {
310327
311328 /// Creates related information from a sourcekitd note response dictionary.
312- init ? ( _ diag: SKDResponseDictionary , in snapshot: DocumentSnapshot ) {
329+ ///
330+ /// `primaryDocumentSnapshot` is the snapshot of the document for which the diagnostics are generated.
331+ /// `documentManager` is used to resolve positions of notes in secondary files.
332+ init ? ( _ diag: SKDResponseDictionary , primaryDocumentSnapshot: DocumentSnapshot , documentManager: DocumentManager ) {
313333 let keys = diag. sourcekitd. keys
314334
335+ guard let filePath: String = diag [ keys. filePath] else {
336+ logger. fault ( " Missing file path in related diagnostic information " )
337+ return nil
338+ }
339+ let uri = DocumentURI ( filePath: filePath, isDirectory: false )
340+ let snapshot : DocumentSnapshot
341+ if filePath == primaryDocumentSnapshot. uri. pseudoPath {
342+ snapshot = primaryDocumentSnapshot
343+ } else if let inMemorySnapshot = try ? documentManager. latestSnapshot ( uri) {
344+ snapshot = inMemorySnapshot
345+ } else if let snapshotFromDisk = try ? DocumentSnapshot ( withContentsFromDisk: uri, language: . swift) {
346+ snapshot = snapshotFromDisk
347+ } else {
348+ return nil
349+ }
350+
315351 var position : Position ? = nil
316352 if let line: Int = diag [ keys. line] ,
317353 let utf8Column: Int = diag [ keys. column] ,
0 commit comments