From 94d3e28aac2ef09457e3295432f472d4d7b67f6d Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 26 Oct 2023 08:40:45 +0100 Subject: [PATCH] fix(linter) fix incorrect reporting for no_useless_escape (#1062) --- crates/oxc_ast/src/ast_kind.rs | 4 ++++ crates/oxc_ast/src/visit.rs | 3 +++ .../src/rules/eslint/no_useless_escape.rs | 22 +++++++++++++++---- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/crates/oxc_ast/src/ast_kind.rs b/crates/oxc_ast/src/ast_kind.rs index 98bd3b26b..ba22b7e2b 100644 --- a/crates/oxc_ast/src/ast_kind.rs +++ b/crates/oxc_ast/src/ast_kind.rs @@ -113,6 +113,7 @@ pub enum AstKind<'a> { JSXFragment(&'a JSXFragment<'a>), JSXOpeningElement(&'a JSXOpeningElement<'a>), JSXElementName(&'a JSXElementName<'a>), + JSXExpressionContainer(&'a JSXExpressionContainer<'a>), JSXAttributeItem(&'a JSXAttributeItem<'a>), JSXText(&'a JSXText), @@ -242,6 +243,7 @@ impl<'a> AstKind<'a> { | Self::JSXFragment(_) | Self::JSXAttributeItem(_) | Self::JSXText(_) + | Self::JSXExpressionContainer(_) ) } @@ -364,6 +366,7 @@ impl<'a> GetSpan for AstKind<'a> { Self::JSXFragment(x) => x.span, Self::JSXAttributeItem(x) => x.span(), Self::JSXText(x) => x.span, + Self::JSXExpressionContainer(x) => x.span, Self::TSModuleBlock(x) => x.span, @@ -530,6 +533,7 @@ impl<'a> AstKind<'a> { Self::JSXFragment(_) => "JSXFragment".into(), Self::JSXAttributeItem(_) => "JSXAttributeItem".into(), Self::JSXText(_) => "JSXText".into(), + Self::JSXExpressionContainer(_) => "JSXExpressionContainer".into(), Self::TSModuleBlock(_) => "TSModuleBlock".into(), diff --git a/crates/oxc_ast/src/visit.rs b/crates/oxc_ast/src/visit.rs index 8108350cd..d7491f7c3 100644 --- a/crates/oxc_ast/src/visit.rs +++ b/crates/oxc_ast/src/visit.rs @@ -1069,7 +1069,10 @@ pub trait Visit<'a>: Sized { } fn visit_jsx_expression_container(&mut self, expr: &JSXExpressionContainer<'a>) { + let kind = AstKind::JSXExpressionContainer(self.alloc(expr)); + self.enter_node(kind); self.visit_jsx_expression(&expr.expression); + self.leave_node(kind); } fn visit_jsx_expression(&mut self, expr: &JSXExpression<'a>) { diff --git a/crates/oxc_linter/src/rules/eslint/no_useless_escape.rs b/crates/oxc_linter/src/rules/eslint/no_useless_escape.rs index f2a94af0e..db3953d48 100644 --- a/crates/oxc_linter/src/rules/eslint/no_useless_escape.rs +++ b/crates/oxc_linter/src/rules/eslint/no_useless_escape.rs @@ -4,6 +4,7 @@ use oxc_diagnostics::{ thiserror::Error, }; use oxc_macros::declare_oxc_lint; +use oxc_semantic::AstNodeId; use oxc_span::Span; use crate::{context::LintContext, rule::Rule, AstNode}; @@ -39,12 +40,14 @@ impl Rule for NoUselessEscape { { check( ctx, + node.id(), literal.span.start, &check_regexp(literal.span.source_text(ctx.source_text())), ); } AstKind::StringLiteral(literal) => check( ctx, + node.id(), literal.span.start, &check_string(literal.span.source_text(ctx.source_text())), ), @@ -52,6 +55,7 @@ impl Rule for NoUselessEscape { for template_element in &literal.quasis { check( ctx, + node.id(), template_element.span.start - 1, &check_template(template_element.span.source_text(ctx.source_text())), ); @@ -62,15 +66,25 @@ impl Rule for NoUselessEscape { } } +fn is_within_jsx_attribute_item(id: AstNodeId, ctx: &LintContext) -> bool { + if matches!(ctx.nodes().parent_kind(id), Some(AstKind::JSXAttributeItem(_))) { + return true; + } + false +} + #[allow(clippy::cast_possible_truncation)] -fn check(ctx: &LintContext<'_>, start: u32, offsets: &[usize]) { +fn check(ctx: &LintContext<'_>, node_id: AstNodeId, start: u32, offsets: &[usize]) { let source_text = ctx.source_text(); for offset in offsets { let offset = start as usize + offset; let c = source_text[offset..].chars().next().unwrap(); let offset = offset as u32; let len = c.len_utf8() as u32; - ctx.diagnostic(NoUselessEscapeDiagnostic(c, Span::new(offset - 1, offset + len))); + + if !is_within_jsx_attribute_item(node_id, ctx) { + ctx.diagnostic(NoUselessEscapeDiagnostic(c, Span::new(offset - 1, offset + len))); + } } } @@ -230,10 +244,10 @@ fn test() { "var foo = '\\f';", "var foo = '\\\n';", "var foo = '\\\r\n';", - // "", + "", "
Testing: \\
", "
Testing: \
", - // "", + "", "<> Testing: \\ ", "<> Testing: \ ", "var foo = `\\x123`",