-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix literal_string_with_formatting_args
lint emitted when it should not
#13953
base: master
Are you sure you want to change the base?
Fix literal_string_with_formatting_args
lint emitted when it should not
#13953
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, with the addition of a non-formatting true positive macro test case.
You should reroll the dice as I don't have the privilege to approve this patch.
r?
); | ||
let value = 0; | ||
assert!(format!("{value}").is_ascii()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also add another true positive test such as
} | |
assert!("{value}".is_ascii()); | |
} |
so that we can check that the lint properly triggers in non-formatting-macro arguments?
1 similar comment
r? clippy |
It still triggers for me indeed:
|
9515896
to
a7fb37c
Compare
Indeed. Sadly, @profetia, your fix doesn't lint with: assert!("{y}".is_ascii()); So I have a not so great middle-ground solution but I think it'll do the trick for the time being: I simply check if the string is part of the snippet in the user code. If not, then I skip the lint. What do you think? |
Nominating for beta backport because the lint is on beta now and the false positive leads to pretty confusing warnings. @rustbot label +beta-nominated |
Changelog CI also passed. :) |
r? @y21 |
|
||
fn another_bad() { | ||
let literal_string_with_formatting_args = 0; | ||
dbg!("something"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised that the expr.span.from_expansion()
check doesn't already prevent this. Looking at -Zunpretty=hir-tree
output it does seem like the span of the string with the file name is properly marked as being from the non-root context
Lit(
Spanned {
node: Str(
"[/app/example.rs:2:5] \"something\" = ",
Cooked,
),
span: /rustc/eb54a50837ad4bcc9842924f27e7287ca66e294c/library/std/src/macros.rs:365:35: 365:58 (#4),
},
),
Odd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see what's happening. Clippy sets -Zflatten_format_args=no
, which changes the default behavior of how format args are lowered and only that one has this non-macro span. Adding the flag makes it repro on godbolt and shows a root context span for the file name string.
Lit(
Spanned {
node: Str(
"/app/example.rs",
Cooked,
),
span: /app/example.rs:2:5: 2:22 (#0),
},
)
Maybe add to the comment that clippy sets this flag and only with that flag does it have a non-macro span which gets around the from_expansion
check, in case anyone wants to look into this in the future and doesn't have to go down this rabbit hole?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into it but couldn't figure out why it didn't work. Thanks a lot for the detailed explanations! Adding it as a comment.
let Some(snippet) = snippet_opt(cx, expr.span) else { | ||
return; | ||
}; | ||
let fmt_str = symbol.as_str(); | ||
// If the literal has been generated by the macro, the snippet should not contain it, | ||
// allowing us to skip it. | ||
if !snippet.contains(fmt_str) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will add false negatives for escaped strings (eg "{foo} \n bar"
) and similar, but as a temporary solution to fix FPs it's probably fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth trying to use is_from_proc_macro
here instead, because that also solves the same issue of a node not matching up with its snippet. It seems like it should also fix the FP while not running into this FN since it doesn't actually check the string contents.
(If we do go with the current approach, a small nit: it might be a good use for the newer SpanRange
API with if !expr.span.check_source_text(|snippet| snippet.contains(fmt_str)) { return; }
. Slightly simpler and avoids allocating a temporary string)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why is_from_proc_macro
didn't work last time I tried but this time it behaves as expected, so switching back to it.
@rustbot ready |
As it is currently, this does not fix #14007. |
Fixed #14007 as well. |
Fixes #13885.
Fixes #14007.
Problem was that I forgot to check whether or not the
span
was a "real" one. Because if not, then it starts pointing to pretty much only wrong content, hence the problems we saw with clippy linting onclippy.toml
.changelog: Fix
literal_string_with_formatting_args
lint emitted when it should notr? @samueltardieu