@@ -14,6 +14,7 @@ import LSPLogging
14
14
import LanguageServerProtocol
15
15
import SKSupport
16
16
import SourceKitD
17
+ import SwiftDiagnostics
17
18
18
19
extension CodeAction {
19
20
@@ -69,6 +70,13 @@ extension CodeAction {
69
70
)
70
71
}
71
72
73
+ init ? ( _ fixIt: FixIt , in snapshot: DocumentSnapshot ) {
74
+ // FIXME: Once https://github.com/apple/swift-syntax/pull/2226 is merged and
75
+ // FixItApplier is public, use it to compute the edits that should be
76
+ // applied to the source.
77
+ return nil
78
+ }
79
+
72
80
/// Describe a fixit's edit briefly.
73
81
///
74
82
/// For example, "Replace 'x' with 'y'", or "Remove 'z'".
@@ -161,7 +169,7 @@ extension Diagnostic {
161
169
return nil
162
170
}
163
171
164
- var severity : DiagnosticSeverity ? = nil
172
+ var severity : LanguageServerProtocol . DiagnosticSeverity ? = nil
165
173
if let uid: sourcekitd_uid_t = diag [ keys. severity] {
166
174
switch uid {
167
175
case values. diag_error:
@@ -234,6 +242,51 @@ extension Diagnostic {
234
242
codeActions: actions
235
243
)
236
244
}
245
+
246
+ init ? (
247
+ _ diag: SwiftDiagnostics . Diagnostic ,
248
+ in snapshot: DocumentSnapshot
249
+ ) {
250
+ guard let position = snapshot. position ( of: diag. position) else {
251
+ logger. error (
252
+ """
253
+ Cannot construct Diagnostic from SwiftSyntax diagnostic because its UTF-8 offset \( diag. position. utf8Offset) \
254
+ is out of range of the source file \( snapshot. uri. forLogging)
255
+ """
256
+ )
257
+ return nil
258
+ }
259
+ // Start with a zero-length range based on the position.
260
+ // If the diagnostic has highlights associated with it that start at the
261
+ // position, use that as the diagnostic's range.
262
+ var range = Range ( position)
263
+ for highlight in diag. highlights {
264
+ let swiftSyntaxRange = highlight. positionAfterSkippingLeadingTrivia..< highlight. endPositionBeforeTrailingTrivia
265
+ guard let highlightRange = snapshot. range ( of: swiftSyntaxRange) else {
266
+ break
267
+ }
268
+ if range. upperBound == highlightRange. lowerBound {
269
+ range = range. lowerBound..< highlightRange. upperBound
270
+ } else {
271
+ break
272
+ }
273
+ }
274
+
275
+ let relatedInformation = diag. notes. compactMap { DiagnosticRelatedInformation ( $0, in: snapshot) }
276
+ let codeActions = diag. fixIts. compactMap { CodeAction ( $0, in: snapshot) }
277
+
278
+ self . init (
279
+ range: range,
280
+ severity: diag. diagMessage. severity. lspSeverity,
281
+ code: nil ,
282
+ codeDescription: nil ,
283
+ source: " SwiftSyntax " ,
284
+ message: diag. message,
285
+ tags: nil ,
286
+ relatedInformation: relatedInformation,
287
+ codeActions: codeActions
288
+ )
289
+ }
237
290
}
238
291
239
292
extension DiagnosticRelatedInformation {
@@ -271,74 +324,31 @@ extension DiagnosticRelatedInformation {
271
324
codeActions: actions
272
325
)
273
326
}
274
- }
275
-
276
- extension Diagnostic {
277
- func withRange( _ newRange: Range < Position > ) -> Diagnostic {
278
- var updated = self
279
- updated. range = newRange
280
- return updated
281
- }
282
- }
283
-
284
- struct CachedDiagnostic {
285
- var diagnostic : Diagnostic
286
- var stage : DiagnosticStage
287
-
288
- func withRange( _ newRange: Range < Position > ) -> CachedDiagnostic {
289
- return CachedDiagnostic (
290
- diagnostic: self . diagnostic. withRange ( newRange) ,
291
- stage: self . stage
292
- )
293
- }
294
- }
295
327
296
- extension CachedDiagnostic {
297
- init ? (
298
- _ diag: SKDResponseDictionary ,
299
- in snapshot: DocumentSnapshot ,
300
- useEducationalNoteAsCode: Bool
301
- ) {
302
- let sk = diag. sourcekitd
303
- guard
304
- let diagnostic = Diagnostic (
305
- diag,
306
- in: snapshot,
307
- useEducationalNoteAsCode: useEducationalNoteAsCode
328
+ init ? ( _ note: Note , in snapshot: DocumentSnapshot ) {
329
+ let nodeRange = note. node. positionAfterSkippingLeadingTrivia..< note. node. endPositionBeforeTrailingTrivia
330
+ guard let range = snapshot. range ( of: nodeRange) else {
331
+ logger. error (
332
+ """
333
+ Cannot construct DiagnosticRelatedInformation because the range \( nodeRange, privacy: . public) \
334
+ is out of range of the source file \( snapshot. uri. forLogging) .
335
+ """
308
336
)
309
- else {
310
337
return nil
311
338
}
312
- self . diagnostic = diagnostic
313
- let stageUID : sourcekitd_uid_t ? = diag [ sk. keys. diagnostic_stage]
314
- self . stage = stageUID. flatMap { DiagnosticStage ( $0, sourcekitd: sk) } ?? . parse
339
+ self . init (
340
+ location: Location ( uri: snapshot. uri, range: range) ,
341
+ message: note. message
342
+ )
315
343
}
316
344
}
317
345
318
- /// Returns the new diagnostics after merging in any existing diagnostics from a higher diagnostic
319
- /// stage that should not be cleared yet.
320
- ///
321
- /// Sourcekitd returns parse diagnostics immediately after edits, but we do not want to clear the
322
- /// semantic diagnostics until we have semantic level diagnostics from after the edit.
323
- ///
324
- /// However, if fallback arguments are being used, we withhold semantic diagnostics in favor of only
325
- /// emitting syntactic diagnostics.
326
- func mergeDiagnostics(
327
- old: [ CachedDiagnostic ] ,
328
- new: [ CachedDiagnostic ] ,
329
- stage: DiagnosticStage ,
330
- isFallback: Bool
331
- ) -> [ CachedDiagnostic ] {
332
- if stage == . sema {
333
- return isFallback ? old. filter { $0. stage == . parse } : new
334
- }
335
-
336
- #if DEBUG
337
- if let sema = new. first ( where: { $0. stage == . sema } ) {
338
- logger. fault ( " unexpected semantic diagnostic in parse diagnostics \( String ( reflecting: sema. diagnostic) ) " )
346
+ extension Diagnostic {
347
+ func withRange( _ newRange: Range < Position > ) -> Diagnostic {
348
+ var updated = self
349
+ updated. range = newRange
350
+ return updated
339
351
}
340
- #endif
341
- return new. filter { $0. stage == . parse } + old. filter { $0. stage == . sema }
342
352
}
343
353
344
354
/// Whether a diagostic is semantic or syntatic (parse).
@@ -361,3 +371,14 @@ extension DiagnosticStage {
361
371
}
362
372
}
363
373
}
374
+
375
+ fileprivate extension SwiftDiagnostics . DiagnosticSeverity {
376
+ var lspSeverity : LanguageServerProtocol . DiagnosticSeverity {
377
+ switch self {
378
+ case . error: return . error
379
+ case . warning: return . warning
380
+ case . note: return . information
381
+ case . remark: return . hint
382
+ }
383
+ }
384
+ }
0 commit comments