diff options
| author | Philipp Krones <hello@philkrones.com> | 2024-06-13 12:18:48 +0200 |
|---|---|---|
| committer | Philipp Krones <hello@philkrones.com> | 2024-06-13 12:24:08 +0200 |
| commit | cc63143bbf5ae28daae127902090492560313ca1 (patch) | |
| tree | 3cf8901da2767e0e330b32ef8a1f8a3bf75adc0c /clippy_utils/src/source.rs | |
| parent | 35f54fd439432f56c749fbb34f1326e34ed1fc42 (diff) | |
| parent | aaade2d12d3cf78fd9eb24bf7973e86433d6373d (diff) | |
Merge remote-tracking branch 'upstream/master' into rustup
Diffstat (limited to 'clippy_utils/src/source.rs')
| -rw-r--r-- | clippy_utils/src/source.rs | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index fd67e039c29..b7ff7ebe910 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -2,13 +2,14 @@ #![allow(clippy::module_name_repetitions)] +use rustc_ast::{LitKind, StrStyle}; use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; use rustc_span::source_map::{original_sp, SourceMap}; -use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP}; +use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; use std::ops::Range; @@ -500,6 +501,50 @@ pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { extended.with_lo(extended.lo() - BytePos(1)) } +/// Converts `expr` to a `char` literal if it's a `str` literal containing a single +/// character (or a single byte with `ascii_only`) +pub fn str_literal_to_char_literal( + cx: &LateContext<'_>, + expr: &Expr<'_>, + applicability: &mut Applicability, + ascii_only: bool, +) -> Option<String> { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(r, style) = lit.node + && let string = r.as_str() + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 + { + let snip = snippet_with_applicability(cx, expr.span, string, applicability); + let ch = if let StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; + + let hint = format!( + "'{}'", + match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + } + ); + + Some(hint) + } else { + None + } +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; |
