diff --git a/crates/oxc_language_server/src/linter/error_with_position.rs b/crates/oxc_language_server/src/linter/error_with_position.rs index e899b77dfdc7b..26f022ef7af80 100644 --- a/crates/oxc_language_server/src/linter/error_with_position.rs +++ b/crates/oxc_language_server/src/linter/error_with_position.rs @@ -1,18 +1,18 @@ -use std::{borrow::Cow, str::FromStr}; +use std::str::FromStr; use tower_lsp_server::lsp_types::{ - self, CodeDescription, DiagnosticRelatedInformation, DiagnosticSeverity, NumberOrString, - Position, Range, Uri, + self, CodeDescription, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, + NumberOrString, Position, Range, Uri, }; use oxc_data_structures::rope::{Rope, get_line_column}; -use oxc_diagnostics::{OxcCode, OxcDiagnostic, Severity}; +use oxc_diagnostics::{OxcCode, Severity}; use oxc_linter::{Fix, Message, PossibleFixes}; use oxc_span::GetSpan; #[derive(Debug, Clone, Default)] pub struct DiagnosticReport { - pub diagnostic: lsp_types::Diagnostic, + pub diagnostic: Diagnostic, pub fixed_content: PossibleFixContent, } @@ -31,103 +31,117 @@ pub enum PossibleFixContent { Multiple(Vec), } -fn message_with_position_to_lsp_diagnostic( - message: &MessageWithPosition<'_>, +// 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 message_to_lsp_diagnostic( + message: &Message<'_>, uri: &Uri, -) -> lsp_types::Diagnostic { - let severity = match message.severity { + source_text: &str, + rope: &Rope, +) -> DiagnosticReport { + let severity = match message.error.severity { Severity::Error => Some(lsp_types::DiagnosticSeverity::ERROR), _ => Some(lsp_types::DiagnosticSeverity::WARNING), }; - let related_information = message.labels.as_ref().map(|spans| { + let related_information = message.error.labels.as_ref().map(|spans| { spans .iter() - .map(|span| lsp_types::DiagnosticRelatedInformation { - location: lsp_types::Location { - uri: uri.clone(), - range: lsp_types::Range { - start: lsp_types::Position { - line: span.start().line, - character: span.start().character, - }, - end: lsp_types::Position { - line: span.end().line, - character: span.end().character, - }, + .map(|span| { + let offset = span.offset() as u32; + let start_position = offset_to_position(rope, offset, source_text); + let end_position = + offset_to_position(rope, offset + span.len() as u32, source_text); + + lsp_types::DiagnosticRelatedInformation { + location: lsp_types::Location { + uri: uri.clone(), + range: lsp_types::Range::new(start_position, end_position), }, - }, - message: span - .message() - .map_or_else(String::new, |message| message.clone().into_owned()), + message: span + .label() + .map_or_else(String::new, std::string::ToString::to_string), + } }) .collect() }); - let range = message.labels.as_ref().map_or(Range::default(), |labels| { - let start = labels.first().map(SpanPositionMessage::start).cloned().unwrap_or_default(); - let end = labels.first().map(SpanPositionMessage::end).cloned().unwrap_or_default(); - Range { - start: Position::new(start.line, start.character), - end: Position::new(end.line, end.character), - } + let range = message.error.labels.as_ref().map_or(Range::default(), |labels| { + let offset = labels.first().map(|span| span.offset() as u32).unwrap_or_default(); + let length = labels.first().map(|span| span.len() as u32).unwrap_or_default(); + + let start_position = offset_to_position(rope, offset, source_text); + let end_position = offset_to_position(rope, offset + length, source_text); + + Range::new(start_position, end_position) }); - let code = message.code.to_string(); - let code_description = - message.url.as_ref().map(|url| CodeDescription { href: Uri::from_str(url).ok().unwrap() }); - let message = match &message.help { + + let code = message.error.code.to_string(); + let code_description = message + .error + .url + .as_ref() + .map(|url| CodeDescription { href: Uri::from_str(url).ok().unwrap() }); + + let diagnostic_message = match &message.error.help { Some(help) => { - let mut msg = String::with_capacity(message.message.len() + help.len() + 7); - msg.push_str(message.message.as_ref()); + let main_msg = &message.error.message; + let mut msg = String::with_capacity(main_msg.len() + help.len() + 7); + msg.push_str(main_msg); msg.push_str("\nhelp: "); - msg.push_str(help.as_ref()); + msg.push_str(help); msg } - None => match message.message { - Cow::Borrowed(s) => s.to_string(), - Cow::Owned(ref s) => s.clone(), - }, + None => message.error.message.to_string(), }; - lsp_types::Diagnostic { + let diagnostic = Diagnostic { range, severity, code: Some(NumberOrString::String(code)), - message, + message: diagnostic_message, source: Some("oxc".into()), code_description, related_information, tags: None, data: None, - } + }; + + // Convert PossibleFixes directly to PossibleFixContent + let fixed_content = match &message.fixes { + PossibleFixes::None => PossibleFixContent::None, + PossibleFixes::Single(fix) => { + PossibleFixContent::Single(fix_to_fixed_content(fix, rope, source_text)) + } + PossibleFixes::Multiple(fixes) => PossibleFixContent::Multiple( + fixes.iter().map(|fix| fix_to_fixed_content(fix, rope, source_text)).collect(), + ), + }; + + // Add ignore fixes + let error_offset = message.span().start; + let section_offset = message.section_offset; + let fixed_content = add_ignore_fixes( + fixed_content, + &message.error.code, + error_offset, + section_offset, + rope, + source_text, + ); + + DiagnosticReport { diagnostic, fixed_content } } -fn fix_with_position_to_fix_content(fix: &FixWithPosition<'_>) -> FixedContent { +fn fix_to_fixed_content(fix: &Fix<'_>, rope: &Rope, source_text: &str) -> FixedContent { + let start_position = offset_to_position(rope, fix.span.start, source_text); + let end_position = offset_to_position(rope, fix.span.end, source_text); + FixedContent { - message: fix.span.message().map(std::string::ToString::to_string), + message: fix.message.as_ref().map(std::string::ToString::to_string), code: fix.content.to_string(), - range: Range { - start: Position { line: fix.span.start().line, character: fix.span.start().character }, - end: Position { line: fix.span.end().line, character: fix.span.end().character }, - }, - } -} - -pub fn message_with_position_to_lsp_diagnostic_report( - message: &MessageWithPosition<'_>, - uri: &Uri, -) -> DiagnosticReport { - DiagnosticReport { - diagnostic: message_with_position_to_lsp_diagnostic(message, uri), - fixed_content: match &message.fixes { - PossibleFixesWithPosition::None => PossibleFixContent::None, - PossibleFixesWithPosition::Single(fix) => { - PossibleFixContent::Single(fix_with_position_to_fix_content(fix)) - } - PossibleFixesWithPosition::Multiple(fixes) => PossibleFixContent::Multiple( - fixes.iter().map(fix_with_position_to_fix_content).collect(), - ), - }, + range: Range::new(start_position, end_position), } } @@ -154,7 +168,7 @@ pub fn generate_inverted_diagnostics( continue; } inverted_diagnostics.push(DiagnosticReport { - diagnostic: lsp_types::Diagnostic { + diagnostic: Diagnostic { range: r.location.range, severity: Some(DiagnosticSeverity::HINT), code: None, @@ -172,195 +186,38 @@ pub fn generate_inverted_diagnostics( inverted_diagnostics } -#[derive(Clone, Debug)] -pub struct SpanPositionMessage<'a> { - /// A brief suggestion message describing the fix. Will be shown in - /// editors via code actions. - message: Option>, - - start: SpanPosition, - end: SpanPosition, -} - -impl<'a> SpanPositionMessage<'a> { - pub fn new(start: SpanPosition, end: SpanPosition) -> Self { - Self { start, end, message: None } - } - - pub fn with_message(mut self, message: Option>) -> Self { - self.message = message; - self - } - - pub fn start(&self) -> &SpanPosition { - &self.start - } - - pub fn end(&self) -> &SpanPosition { - &self.end - } - - pub fn message(&self) -> Option<&Cow<'a, str>> { - self.message.as_ref() - } -} - -#[derive(Clone, Debug, Default)] -pub struct SpanPosition { - pub line: u32, - pub character: u32, -} - -impl SpanPosition { - pub fn new(line: u32, column: u32) -> Self { - Self { line, character: column } - } -} - -pub fn offset_to_position(rope: &Rope, offset: u32, source_text: &str) -> SpanPosition { +pub fn offset_to_position(rope: &Rope, offset: u32, source_text: &str) -> Position { let (line, column) = get_line_column(rope, offset, source_text); - SpanPosition::new(line, column) -} - -#[derive(Debug)] -pub struct MessageWithPosition<'a> { - pub message: Cow<'a, str>, - pub labels: Option>>, - pub help: Option>, - pub severity: Severity, - pub code: OxcCode, - pub url: Option>, - pub fixes: PossibleFixesWithPosition<'a>, -} - -// 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 inner = diagnostic.inner_owned(); - - let labels = inner.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: inner.message, - severity: inner.severity, - help: inner.help, - url: inner.url, - code: inner.code, - labels, - fixes: PossibleFixesWithPosition::None, - } -} - -pub fn message_to_message_with_position<'a>( - message: Message<'a>, - source_text: &str, - rope: &Rope, -) -> MessageWithPosition<'a> { - let code = message.error.code.clone(); - let error_offset = message.span().start; - let section_offset = message.section_offset; - - let mut result = oxc_diagnostic_to_message_with_position(message.error, source_text, rope); - let fixes = match &message.fixes { - PossibleFixes::None => PossibleFixesWithPosition::None, - PossibleFixes::Single(fix) => { - PossibleFixesWithPosition::Single(fix_to_fix_with_position(fix, rope, source_text)) - } - PossibleFixes::Multiple(fixes) => PossibleFixesWithPosition::Multiple( - fixes.iter().map(|fix| fix_to_fix_with_position(fix, rope, source_text)).collect(), - ), - }; - - result.fixes = add_ignore_fixes(fixes, &code, error_offset, section_offset, rope, source_text); - - result -} - -/// Possible fixes with position information. -/// -/// This is similar to `PossibleFixes` but with position information. -/// It also includes "ignore this line" and "ignore this rule" fixes for the Language Server. -/// -/// The struct should be build with `message_to_message_with_position` -/// or `oxc_diagnostic_to_message_with_position` function to ensure the ignore fixes are added correctly. -#[derive(Debug)] -pub enum PossibleFixesWithPosition<'a> { - // No possible fixes. - // This happens on parser/semantic errors. - None, - // A single possible fix. - // This happens when a unused disable directive is reported. - Single(FixWithPosition<'a>), - // Multiple possible fixes. - // This happens when a lint reports a violation, then ignore fixes are added. - Multiple(Vec>), -} - -#[derive(Debug)] -pub struct FixWithPosition<'a> { - pub content: Cow<'a, str>, - pub span: SpanPositionMessage<'a>, -} - -fn fix_to_fix_with_position<'a>( - fix: &Fix<'a>, - rope: &Rope, - source_text: &str, -) -> FixWithPosition<'a> { - let start_position = offset_to_position(rope, fix.span.start, source_text); - let end_position = offset_to_position(rope, fix.span.end, source_text); - FixWithPosition { - content: fix.content.clone(), - span: SpanPositionMessage::new(start_position, end_position) - .with_message(fix.message.as_ref().map(|label| Cow::Owned(label.to_string()))), - } + Position::new(line, column) } /// Add "ignore this line" and "ignore this rule" fixes to the existing fixes. /// These fixes will be added to the end of the existing fixes. /// If the existing fixes already contain an "remove unused disable directive" fix, /// then no ignore fixes will be added. -fn add_ignore_fixes<'a>( - fixes: PossibleFixesWithPosition<'a>, +fn add_ignore_fixes( + fixes: PossibleFixContent, code: &OxcCode, error_offset: u32, section_offset: u32, rope: &Rope, source_text: &str, -) -> PossibleFixesWithPosition<'a> { +) -> PossibleFixContent { // do not append ignore code actions when the error is the ignore action - if matches!(fixes, PossibleFixesWithPosition::Single(ref fix) if fix.span.message.as_ref().is_some_and(|message| message.starts_with("remove unused disable directive"))) + if matches!(fixes, PossibleFixContent::Single(ref fix) if fix.message.as_ref().is_some_and(|message| message.starts_with("remove unused disable directive"))) { return fixes; } - let mut new_fixes: Vec> = vec![]; - if let PossibleFixesWithPosition::Single(fix) = fixes { + let mut new_fixes: Vec = vec![]; + if let PossibleFixContent::Single(fix) = fixes { new_fixes.push(fix); - } else if let PossibleFixesWithPosition::Multiple(existing_fixes) = fixes { + } else if let PossibleFixContent::Multiple(existing_fixes) = fixes { new_fixes.extend(existing_fixes); } if let Some(rule_name) = code.number.as_ref() { - // TODO: doesn't support disabling multiple rules by name for a given line. + // TODO: doesn't support disabling multiple rules by name for a given line. new_fixes.push(disable_for_this_line( rule_name, error_offset, @@ -372,21 +229,21 @@ fn add_ignore_fixes<'a>( } if new_fixes.is_empty() { - PossibleFixesWithPosition::None + PossibleFixContent::None } else if new_fixes.len() == 1 { - PossibleFixesWithPosition::Single(new_fixes.remove(0)) + PossibleFixContent::Single(new_fixes.remove(0)) } else { - PossibleFixesWithPosition::Multiple(new_fixes) + PossibleFixContent::Multiple(new_fixes) } } -fn disable_for_this_line<'a>( +fn disable_for_this_line( rule_name: &str, error_offset: u32, section_offset: u32, rope: &Rope, source_text: &str, -) -> FixWithPosition<'a> { +) -> FixedContent { let bytes = source_text.as_bytes(); // Find the line break before the error let mut line_break_offset = error_offset; @@ -415,33 +272,33 @@ fn disable_for_this_line<'a>( let whitespace_string = String::from_utf8_lossy(whitespace_range); let position = offset_to_position(rope, insert_offset, source_text); - FixWithPosition { - content: Cow::Owned(format!( + FixedContent { + message: Some(format!("Disable {rule_name} for this line")), + code: format!( "{content_prefix}{whitespace_string}// oxlint-disable-next-line {rule_name}\n" - )), - span: SpanPositionMessage::new(position.clone(), position) - .with_message(Some(Cow::Owned(format!("Disable {rule_name} for this line")))), + ), + range: Range::new(position, position), } } -fn disable_for_this_section<'a>( +fn disable_for_this_section( rule_name: &str, section_offset: u32, rope: &Rope, source_text: &str, -) -> FixWithPosition<'a> { +) -> FixedContent { let comment = format!("// oxlint-disable {rule_name}\n"); let (content_prefix, insert_offset) = get_section_insert_position(section_offset, section_offset, source_text.as_bytes()); - let content = Cow::Owned(format!("{content_prefix}{comment}")); + let content = format!("{content_prefix}{comment}"); let position = offset_to_position(rope, insert_offset, source_text); - FixWithPosition { - content, - span: SpanPositionMessage::new(position.clone(), position) - .with_message(Some(Cow::Owned(format!("Disable {rule_name} for this file")))), + FixedContent { + message: Some(format!("Disable {rule_name} for this file")), + code: content, + range: Range::new(position, position), } } @@ -533,9 +390,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_section("no-console", 0, &rope, source); - assert_eq!(fix.content, "// oxlint-disable no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -544,9 +401,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_section("no-console", 8, &rope, source); - assert_eq!(fix.content, "// oxlint-disable no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -555,9 +412,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_section("no-console", 8, &rope, source); - assert_eq!(fix.content, "// oxlint-disable no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -566,9 +423,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_section("no-unused-vars", 6, &rope, source); - assert_eq!(fix.content, "\n// oxlint-disable no-unused-vars\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 6); + assert_eq!(fix.code, "\n// oxlint-disable no-unused-vars\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 6); } #[test] @@ -577,9 +434,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 0, 0, &rope, source); - assert_eq!(fix.content, "// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -588,9 +445,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 10, 0, &rope, source); - assert_eq!(fix.content, " // oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, " // oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -599,9 +456,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 10, 0, &rope, source); - assert_eq!(fix.content, "\t\t// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "\t\t// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -610,9 +467,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 12, 0, &rope, source); - assert_eq!(fix.content, "\t \t// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "\t \t// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -621,9 +478,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 27, 0, &rope, source); - assert_eq!(fix.content, "\t// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "\t// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -632,9 +489,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 30, 0, &rope, source); - assert_eq!(fix.content, " // oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, " // oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -643,9 +500,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 33, 0, &rope, source); - assert_eq!(fix.content, "\t \t // oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "\t \t // oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -654,9 +511,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 26, 0, &rope, source); - assert_eq!(fix.content, "// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -665,9 +522,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 28, 0, &rope, source); - assert_eq!(fix.content, "\t// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "\t// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -676,9 +533,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 40, 0, &rope, source); - assert_eq!(fix.content, "\t\t\t// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 2); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "\t\t\t// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 2); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -687,9 +544,9 @@ mod test { let rope = Rope::from_str(source); let fix = super::disable_for_this_line("no-console", 0, 0, &rope, source); - assert_eq!(fix.content, "// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -701,9 +558,9 @@ mod test { let fix = super::disable_for_this_line("no-console", 21, 0, &rope, source); // Should only capture " \t" at the beginning, not the spaces around "here" - assert_eq!(fix.content, " \t// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, " \t// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -716,9 +573,9 @@ mod test { let fix = super::disable_for_this_line("no-console", error_offset, section_offset, &rope, source); - assert_eq!(fix.content, "// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 1); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, "// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 1); + assert_eq!(fix.range.start.character, 0); } #[test] @@ -731,9 +588,9 @@ mod test { let fix = super::disable_for_this_line("no-console", error_offset, section_offset, &rope, source); - assert_eq!(fix.content, "\n// oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 0); - assert_eq!(fix.span.start.character, 8); + assert_eq!(fix.code, "\n// oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 0); + assert_eq!(fix.range.start.character, 8); } #[test] @@ -746,9 +603,9 @@ mod test { let fix = super::disable_for_this_line("no-console", error_offset, section_offset, &rope, source); - assert_eq!(fix.content, " // oxlint-disable-next-line no-console\n"); - assert_eq!(fix.span.start.line, 3); - assert_eq!(fix.span.start.character, 0); + assert_eq!(fix.code, " // oxlint-disable-next-line no-console\n"); + assert_eq!(fix.range.start.line, 3); + assert_eq!(fix.range.start.character, 0); } fn assert_position(source: &str, offset: u32, expected: (u32, u32)) { diff --git a/crates/oxc_language_server/src/linter/isolated_lint_handler.rs b/crates/oxc_language_server/src/linter/isolated_lint_handler.rs index e8375dea42c9a..932323ca448e6 100644 --- a/crates/oxc_language_server/src/linter/isolated_lint_handler.rs +++ b/crates/oxc_language_server/src/linter/isolated_lint_handler.rs @@ -16,8 +16,7 @@ use oxc_linter::{ }; use super::error_with_position::{ - DiagnosticReport, generate_inverted_diagnostics, message_to_message_with_position, - message_with_position_to_lsp_diagnostic_report, + DiagnosticReport, generate_inverted_diagnostics, message_to_lsp_diagnostic, }; /// smaller subset of LintServiceOptions, which is used by IsolatedLintHandler @@ -123,13 +122,8 @@ impl IsolatedLintHandler { ))) .with_paths(vec![Arc::from(path.as_os_str())]) .run_source(&mut allocator) - .into_iter() - .map(|message| { - message_with_position_to_lsp_diagnostic_report( - &message_to_message_with_position(message, source_text, rope), - uri, - ) - }) + .iter() + .map(|message| message_to_lsp_diagnostic(message, uri, source_text, rope)) .collect(); // Add unused directives if configured @@ -137,14 +131,9 @@ impl IsolatedLintHandler { && let Some(directives) = self.directives_coordinator.get(path) { messages.extend( - self.create_unused_directives_messages(&directives, severity).into_iter().map( - |message| { - message_with_position_to_lsp_diagnostic_report( - &message_to_message_with_position(message, source_text, rope), - uri, - ) - }, - ), + self.create_unused_directives_messages(&directives, severity) + .iter() + .map(|message| message_to_lsp_diagnostic(message, uri, source_text, rope)), ); } diff --git a/crates/oxc_language_server/src/linter/tsgo_linter.rs b/crates/oxc_language_server/src/linter/tsgo_linter.rs index 79c9bcf3b5bf8..8735467755cd9 100644 --- a/crates/oxc_language_server/src/linter/tsgo_linter.rs +++ b/crates/oxc_language_server/src/linter/tsgo_linter.rs @@ -12,8 +12,7 @@ use rustc_hash::FxHashSet; use tower_lsp_server::{UriExt, lsp_types::Uri}; use crate::linter::error_with_position::{ - DiagnosticReport, generate_inverted_diagnostics, message_to_message_with_position, - message_with_position_to_lsp_diagnostic_report, + DiagnosticReport, generate_inverted_diagnostics, message_to_lsp_diagnostic, }; pub struct TsgoLinter { @@ -41,13 +40,8 @@ impl TsgoLinter { self.state.lint_source(&Arc::from(path.as_os_str()), source_text.clone()).ok()?; let mut diagnostics: Vec = messages - .into_iter() - .map(|e| { - message_with_position_to_lsp_diagnostic_report( - &message_to_message_with_position(e, &source_text, &rope), - uri, - ) - }) + .iter() + .map(|e| message_to_lsp_diagnostic(e, uri, &source_text, &rope)) .collect(); let mut inverted_diagnostics = generate_inverted_diagnostics(&diagnostics, uri);