summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/regex.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/regex.rs')
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs89
1 files changed, 44 insertions, 45 deletions
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 1fda58fa5..9e6c6c73d 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,5 +1,8 @@
+use std::fmt::Display;
+
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::source::snippet_opt;
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::{LitKind, StrStyle};
@@ -77,13 +80,45 @@ impl<'tcx> LateLintPass<'tcx> for Regex {
}
}
-#[must_use]
-fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u8) -> Span {
- let offset = u32::from(offset);
- let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
- let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset);
- assert!(start <= end);
- Span::new(start, end, base.ctxt(), base.parent())
+fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescaped: &str, base: Span, offset: u8) {
+ let parts: Option<(_, _, &dyn Display)> = match &error {
+ regex_syntax::Error::Parse(e) => Some((e.span(), e.auxiliary_span(), e.kind())),
+ regex_syntax::Error::Translate(e) => Some((e.span(), None, e.kind())),
+ _ => None,
+ };
+
+ let convert_span = |regex_span: &regex_syntax::ast::Span| {
+ let offset = u32::from(offset);
+ let start = base.lo() + BytePos(u32::try_from(regex_span.start.offset).expect("offset too large") + offset);
+ let end = base.lo() + BytePos(u32::try_from(regex_span.end.offset).expect("offset too large") + offset);
+
+ Span::new(start, end, base.ctxt(), base.parent())
+ };
+
+ if let Some((primary, auxiliary, kind)) = parts
+ && let Some(literal_snippet) = snippet_opt(cx, base)
+ && let Some(inner) = literal_snippet.get(offset as usize..)
+ // Only convert to native rustc spans if the parsed regex matches the
+ // source snippet exactly, to ensure the span offsets are correct
+ && inner.get(..unescaped.len()) == Some(unescaped)
+ {
+ let spans = if let Some(auxiliary) = auxiliary {
+ vec![convert_span(primary), convert_span(auxiliary)]
+ } else {
+ vec![convert_span(primary)]
+ };
+
+ span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}"));
+ } else {
+ span_lint_and_help(
+ cx,
+ INVALID_REGEX,
+ base,
+ &error.to_string(),
+ None,
+ "consider using a raw string literal: `r\"..\"`",
+ );
+ }
}
fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
@@ -155,25 +190,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
}
},
- Err(regex_syntax::Error::Parse(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- str_span(expr.span, *e.span(), offset),
- &format!("regex syntax error: {}", e.kind()),
- );
- },
- Err(regex_syntax::Error::Translate(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- str_span(expr.span, *e.span(), offset),
- &format!("regex syntax error: {}", e.kind()),
- );
- },
- Err(e) => {
- span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
- },
+ Err(e) => lint_syntax_error(cx, &e, r, expr.span, offset),
}
}
} else if let Some(r) = const_str(cx, expr) {
@@ -183,25 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
}
},
- Err(regex_syntax::Error::Parse(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- expr.span,
- &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()),
- );
- },
- Err(regex_syntax::Error::Translate(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- expr.span,
- &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()),
- );
- },
- Err(e) => {
- span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
- },
+ Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()),
}
}
}