Auto merge of #10573 - Alexendoo:print-literal-file-macro, r=Jarcho

Ignore `file!()` macro in `print_literal`, `write_literal`

changelog: [`print_literal`], [`write_literal`]: Ignore the `file!()` macro

`file!()` expands to a string literal with its span set to that of the `file!()` callsite, but isn't marked as coming from an expansion. To fix this we make sure we actually find a string/char literal instead of assuming it's one and slicing

It would also ignore any other macros that result in the same situation, but that shouldn't be common as `proc_macro::Span::call_site()` returns a span that is marked as from expansion

Fixes #10544
This commit is contained in:
bors 2023-03-30 16:38:50 +00:00
commit d43714a101
3 changed files with 15 additions and 5 deletions

View file

@ -463,12 +463,18 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
{
let (replacement, replace_raw) = match lit.kind {
LitKind::Str | LitKind::StrRaw(_) => extract_str_literal(&value_string),
LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
Some(extracted) => extracted,
None => return,
},
LitKind::Char => (
match lit.symbol.as_str() {
"\"" => "\\\"",
"\\'" => "'",
_ => &value_string[1..value_string.len() - 1],
_ => match value_string.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) {
Some(stripped) => stripped,
None => return,
},
}
.to_string(),
false,
@ -533,13 +539,13 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
/// `r#"a"#` -> (`a`, true)
///
/// `"b"` -> (`b`, false)
fn extract_str_literal(literal: &str) -> (String, bool) {
fn extract_str_literal(literal: &str) -> Option<(String, bool)> {
let (literal, raw) = match literal.strip_prefix('r') {
Some(stripped) => (stripped.trim_matches('#'), true),
None => (literal, false),
};
(literal[1..literal.len() - 1].to_string(), raw)
Some((literal.strip_prefix('"')?.strip_suffix('"')?.to_string(), raw))
}
enum UnescapeErr {

View file

@ -63,7 +63,7 @@ fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Gro
/// Token used to escape the following token from the macro's span rules.
const ESCAPE_CHAR: char = '$';
/// Takes a single token followed by a sequence tokens. Returns the sequence of tokens with their
/// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their
/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`.
#[proc_macro]
pub fn with_span(input: TokenStream) -> TokenStream {

View file

@ -38,4 +38,8 @@ fn main() {
// named args shouldn't change anything either
println!("{foo} {bar}", foo = "hello", bar = "world");
println!("{bar} {foo}", foo = "hello", bar = "world");
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
// expansion
println!("file: {}", file!());
}