diff --git a/crates/oxc_language_server/src/snapshots/fixtures_linter_invalid_syntax@debugger.ts.snap b/crates/oxc_language_server/src/snapshots/fixtures_linter_invalid_syntax@debugger.ts.snap index ee3385228e0f5..ef28102b99036 100644 --- a/crates/oxc_language_server/src/snapshots/fixtures_linter_invalid_syntax@debugger.ts.snap +++ b/crates/oxc_language_server/src/snapshots/fixtures_linter_invalid_syntax@debugger.ts.snap @@ -8,8 +8,10 @@ file: fixtures/linter/invalid_syntax/debugger.ts code: "" code_description.href: "None" message: "Unexpected token" -range: Range { start: Position { line: 2147483647, character: 2147483647 }, end: Position { line: 2147483647, character: 2147483647 } } -related_information: None +range: Range { start: Position { line: 0, character: 9 }, end: Position { line: 0, character: 10 } } +related_information[0].message: "" +related_information[0].location.uri: "file:///fixtures/linter/invalid_syntax/debugger.ts" +related_information[0].location.range: Range { start: Position { line: 0, character: 9 }, end: Position { line: 0, character: 10 } } severity: Some(Error) source: Some("oxc") tags: None diff --git a/crates/oxc_linter/src/lsp.rs b/crates/oxc_linter/src/lsp.rs index fd014102b475b..1e000aa614976 100644 --- a/crates/oxc_linter/src/lsp.rs +++ b/crates/oxc_linter/src/lsp.rs @@ -65,17 +65,37 @@ pub struct MessageWithPosition<'a> { pub fixes: PossibleFixesWithPosition<'a>, } -impl From for MessageWithPosition<'_> { - fn from(from: OxcDiagnostic) -> Self { - Self { - message: from.message.clone(), - labels: None, - help: from.help.clone(), - severity: from.severity, - code: from.code.clone(), - url: from.url.clone(), - fixes: PossibleFixesWithPosition::None, - } +// clippy: the source field is checked and assumed to be less than 4GB, and +// we assume that the fix offset will not exceed 2GB in either direction +#[expect(clippy::cast_possible_truncation)] +pub fn oxc_diagnostic_to_message_with_position<'a>( + diagnostic: &OxcDiagnostic, + source_text: &str, + rope: &Rope, +) -> MessageWithPosition<'a> { + let labels = diagnostic.labels.as_ref().map(|labels| { + labels + .iter() + .map(|labeled_span| { + let offset = labeled_span.offset() as u32; + let start_position = offset_to_position(rope, offset, source_text); + let end_position = + offset_to_position(rope, offset + labeled_span.len() as u32, source_text); + let message = labeled_span.label().map(|label| Cow::Owned(label.to_string())); + + SpanPositionMessage::new(start_position, end_position).with_message(message) + }) + .collect::>() + }); + + MessageWithPosition { + message: diagnostic.message.clone(), + severity: diagnostic.severity, + help: diagnostic.help.clone(), + url: diagnostic.url.clone(), + code: diagnostic.code.clone(), + labels, + fixes: PossibleFixesWithPosition::None, } } diff --git a/crates/oxc_linter/src/service/runtime.rs b/crates/oxc_linter/src/service/runtime.rs index 85861b83e6f92..208442eaa8fc5 100644 --- a/crates/oxc_linter/src/service/runtime.rs +++ b/crates/oxc_linter/src/service/runtime.rs @@ -682,7 +682,9 @@ impl Runtime { use oxc_data_structures::rope::Rope; - use crate::lsp::message_to_message_with_position; + use crate::lsp::{ + message_to_message_with_position, oxc_diagnostic_to_message_with_position, + }; // Wrap allocator in `MessageCloner` so can clone `Message`s into it let message_cloner = MessageCloner::new(allocator); @@ -715,10 +717,15 @@ impl Runtime { } Err(diagnostics) => { if !diagnostics.is_empty() { - messages - .lock() - .unwrap() - .extend(diagnostics.into_iter().map(Into::into)); + messages.lock().unwrap().extend( + diagnostics.into_iter().map(|diagnostic| { + oxc_diagnostic_to_message_with_position( + &diagnostic, + source_text, + rope, + ) + }), + ); } None } @@ -745,8 +752,7 @@ impl Runtime { }); }); - // ToDo: oxc_diagnostic::Error is not compatible with MessageWithPosition - // send use OxcDiagnostic or even better the MessageWithPosition struct + // The receiving messages should be only file system reads or source type errors // while let Ok(diagnostics) = receiver.recv() { // if let Some(diagnostics) = diagnostics { // messages.lock().unwrap().extend(