@@ -154,16 +154,28 @@ 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+ let uri = DocumentURI ( filePath: filePath, isDirectory: false )
174+ guard uri == snapshot. uri else {
175+ logger. error ( " Ignoring diagnostic from a different file: \( uri) " )
176+ return nil
177+ }
178+
167179 guard let message: String = diag [ keys. description] ? . withFirstLetterUppercased ( ) else { return nil }
168180
169181 var range : Range < Position > ? = nil
@@ -237,7 +249,13 @@ extension Diagnostic {
237249 if let sknotes: SKDResponseArray = diag [ keys. diagnostics] {
238250 notes = [ ]
239251 sknotes. forEach { ( _, sknote) -> Bool in
240- guard let note = DiagnosticRelatedInformation ( sknote, in: snapshot) else { return true }
252+ guard
253+ let note = DiagnosticRelatedInformation (
254+ sknote,
255+ primaryDocumentSnapshot: snapshot,
256+ documentManager: documentManager
257+ )
258+ else { return true }
241259 notes? . append ( note)
242260 return true
243261 }
@@ -309,9 +327,28 @@ extension Diagnostic {
309327extension DiagnosticRelatedInformation {
310328
311329 /// Creates related information from a sourcekitd note response dictionary.
312- init ? ( _ diag: SKDResponseDictionary , in snapshot: DocumentSnapshot ) {
330+ ///
331+ /// `primaryDocumentSnapshot` is the snapshot of the document for which the diagnostics are generated.
332+ /// `documentManager` is used to resolve positions of notes in secondary files.
333+ init ? ( _ diag: SKDResponseDictionary , primaryDocumentSnapshot: DocumentSnapshot , documentManager: DocumentManager ) {
313334 let keys = diag. sourcekitd. keys
314335
336+ guard let filePath: String = diag [ keys. filePath] else {
337+ logger. fault ( " Missing file path in related diagnostic information " )
338+ return nil
339+ }
340+ let uri = DocumentURI ( filePath: filePath, isDirectory: false )
341+ let snapshot : DocumentSnapshot
342+ if uri == primaryDocumentSnapshot. uri {
343+ snapshot = primaryDocumentSnapshot
344+ } else if let inMemorySnapshot = try ? documentManager. latestSnapshot ( uri) {
345+ snapshot = inMemorySnapshot
346+ } else if let snapshotFromDisk = try ? DocumentSnapshot ( withContentsFromDisk: uri, language: . swift) {
347+ snapshot = snapshotFromDisk
348+ } else {
349+ return nil
350+ }
351+
315352 var position : Position ? = nil
316353 if let line: Int = diag [ keys. line] ,
317354 let utf8Column: Int = diag [ keys. column] ,
0 commit comments