Skip to content
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

Add new literal_string_with_formatting_args lint #13410

Merged

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented Sep 17, 2024

Fixes #10195.

changelog: Added new [literal_string_with_formatting_args] pedantic lint
#13410

@rustbot
Copy link
Collaborator

rustbot commented Sep 17, 2024

r? @Jarcho

rustbot has assigned @Jarcho.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Sep 17, 2024
@GuillaumeGomez GuillaumeGomez changed the title Literal string with formatting arg Add new literal_string_with_formatting_arg lint Sep 17, 2024
@GuillaumeGomez GuillaumeGomez changed the title Add new literal_string_with_formatting_arg lint Add new literal_string_with_formatting_arg lint Sep 17, 2024
})
.collect::<Vec<_>>();
if spans.len() == 1 {
span_lint(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could emit a suggestion for both cases by wrapping the literal into &format!(). Not sure if it's a good idea since it could be wrong in a lot of cases so for now I didn't do it.

@matthiaskrgr
Copy link
Member

Would like to see a test for malformed fmt attemps such as {y:?}} or "{y:?} y:?}" to make sure we don't lint there by accident

@emilk
Copy link

emilk commented Sep 18, 2024

I did a little bit of testing, and it seems to work like it should! ❤️ A few more unit tests would be nice though

@GuillaumeGomez
Copy link
Member Author

I just found a much better idea: using the rustc format parser directly. :3

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch 3 times, most recently from d720088 to 2356854 Compare September 18, 2024 21:59
@GuillaumeGomez
Copy link
Member Author

So it now uses the rustc format parser, making things much better overall: no more regex, less false positive, simpler code.

I also added all suggested test cases and some more.

@y21
Copy link
Member

y21 commented Sep 18, 2024

What does the lint do for the empty JSON object {} which is also a valid formatting specifier? Would probably be a good to have as a negative test too.

cx,
LITERAL_STRING_WITH_FORMATTING_ARG,
spans,
"this is a formatting argument but it is not part of a formatting macro",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a less strong wording would be good, e.g. "this looks like a formatting argument…" ? Just in case of false positives

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch from 2356854 to c662397 Compare September 19, 2024 10:11
@GuillaumeGomez
Copy link
Member Author

What does the lint do for the empty JSON object {} which is also a valid formatting specifier? Would probably be a good to have as a negative test too.

It lints (as expected 😄). There was a test for that with other characters but created a new one with just {} just in case.

Maybe a less strong wording would be good, e.g. "this looks like a formatting argument…" ? Just in case of false positives

Good idea! I changed the wording.

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch 2 times, most recently from 6a3f320 to c027b98 Compare September 19, 2024 13:55
@y21
Copy link
Member

y21 commented Sep 19, 2024

It lints (as expected 😄).

Realistically speaking, I feel like {} would run into more false positives than true positives if we decide to lint that.

{foo}/{foo:?} etc. all make sense since they can work with format! alone (that is, format!("{foo}") works), but you can't make that argument for just {}. Not only is it missing the format macro, but it's also missing a formatting argument.

If someone writes let foo = "{}";, it seems fairly unlikely to me that they actually meant to use a formatting macro there, because there is nothing to format.

@GuillaumeGomez
Copy link
Member Author

Good point. Should I only lint against non-empty {} like {y}/{:?}/{y:?} and eventually we can add an option to look for everything?

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch 3 times, most recently from 2d7c05d to 852f1e3 Compare September 19, 2024 16:05
@GuillaumeGomez
Copy link
Member Author

I removed the check for {} for the time being.

@bors
Copy link
Contributor

bors commented Sep 22, 2024

☔ The latest upstream changes (presumably #13322) made this pull request unmergeable. Please resolve the merge conflicts.

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch from 852f1e3 to d9c9ad4 Compare September 22, 2024 15:10
@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch 5 times, most recently from ffce1c1 to 076d9ca Compare November 19, 2024 17:51
@GuillaumeGomez
Copy link
Member Author

Implemented the limitation as asked. The ui test file is a good summary of what's emitting the lint or not. Please tell me if you need more restrictions.

Copy link
Member

@xFrednet xFrednet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superficial NITs the rest looks good :D

|
LL | x.expect(r##" {y:?} {y:?} "##);
| ^^^^^ ^^^^^

error: this looks like a formatting argument but it is not part of a formatting macro
--> tests/ui/literal_string_with_formatting_args.rs:17:18
--> tests/ui/literal_string_with_formatting_arg.rs:18:18
|
LL | x.expect("———{:?}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this still being linted after restricting the lint to idents in the current scope?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as there is a valid formatter with :, then it's highly likely that it's actually something the user intended. I don't know any language where {:?} or {:#} or {:.2} would make sense (doesn't mean they don't exist) so I think it's pretty safe to keep these cases. I can remove them if preferred but I think it's not cases that could trigger issues.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, I'm happy to keep it like this :D

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeay! \o/

}

if fmt_str[start + 1..].trim_start().starts_with('}') {
// For now, we ignore `{}`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: The "For now" sounds like an open TODO

Suggested change
// For now, we ignore `{}`.
We ignore `{}` and `{:?}` since they can't refer to anything

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -1,5 +1,5 @@
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
#![allow(unused_imports, clippy::literal_string_with_formatting_args)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is no longer needed since 4 in {4} isn't a valid identifier

Same for other tests. Could you remove them to make sure those FPs are resolved?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let me go through them. 👍

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch 2 times, most recently from ade93b2 to 3c30d61 Compare November 22, 2024 13:55
@@ -3,6 +3,7 @@
//@[edition2021] edition:2021

#![warn(clippy::uninlined_format_args)]
#![allow(clippy::literal_string_with_formatting_args)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one uses panic!("p4 {var}");, so we need to allow the lint.

@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch from 3c30d61 to 0930c94 Compare November 22, 2024 13:57
@GuillaumeGomez GuillaumeGomez force-pushed the literal_string_with_formatting_arg branch from 0930c94 to cfc6444 Compare November 22, 2024 13:59
@GuillaumeGomez
Copy link
Member Author

Removed the allow attributes where possible. I still think that things like {:?} should be linted but if you prefer, I can remove it as well (and open a follow-up so it can be discussed if it wasn't already 😆 ).

@xFrednet xFrednet changed the title Add new literal_string_with_formatting_arg lint Add new literal_string_with_formatting_args lint Nov 23, 2024
Copy link
Member

@xFrednet xFrednet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xFrednet xFrednet added S-final-comment-period Status: final comment period it will be merged unless new objections are raised (~1 week) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Nov 23, 2024
@GuillaumeGomez
Copy link
Member Author

Thanks!

@xFrednet xFrednet removed the S-final-comment-period Status: final comment period it will be merged unless new objections are raised (~1 week) label Dec 1, 2024
@xFrednet
Copy link
Member

xFrednet commented Dec 1, 2024

Alright, let's get this merged.

Roses are {:#?}
Violets are {color2}
this would be horrible formatting,
lets lint this

@xFrednet xFrednet added this pull request to the merge queue Dec 1, 2024
Merged via the queue into rust-lang:master with commit 1f966e9 Dec 1, 2024
9 checks passed
@GuillaumeGomez GuillaumeGomez deleted the literal_string_with_formatting_arg branch December 1, 2024 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

warn on strings that look like inline format strings but aren't
9 participants