Sometimes, we want to create subspans and point at code in the literal
if possible. But this doesn't always make sense, sometimes the literal
may come from macro expanded code and isn't actually there in the
source. Then, we can't really make these suggestions.
This now makes sure that the literal is actually there as we see it so
that we will not run into ICEs on weird literal transformations.
Originally, this was kinda half-allowed. There were some primitive
checks in place that looked at the span to see whether the input was
likely a literal. These "source literal" checks are needed because the
spans created during `format_args` parsing only make sense when it is
indeed a literal that was written in the source code directly.
This is orthogonal to the restriction that the first argument must be a
"direct literal", not being exanpanded from macros. This restriction was
imposed by [RFC 2795] on the basis of being too confusing. But this was
only concerned with the argument of the invocation being a literal, not
whether it was a source literal (maybe in spirit it meant it being a
source literal, this is not clear to me).
Since the original check only really cared about source literals (which
is good enough to deny the `format_args!(concat!())` example), macros
expanding to `format_args` invocations were able to use implicit
captures if they spanned the string in a way that lead back to a source
string.
The "source literal" checks were not strict enough and caused ICEs in
certain cases (see # 106191 (the space is intended to avoid spammy
backreferences)). So I tightened it up in # 106195 to really only work
if it's a direct source literal.
This caused the `indoc` crate to break. `indoc` transformed the source
literal by removing whitespace, which made it not a "source literal"
anymore (which is required to fix the ICE). But since `indoc` spanned
the literal in ways that made the old check think that it's a literal,
it was able to use implicit captures (which is useful and nice for the
users of `indoc`).
This commit properly seperates the previously introduced concepts of
"source literal" and "direct literal" and therefore allows `indoc`
invocations, which don't create "source literals" to use implicit
captures again.
[RFC 2795]: https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html#macro-hygiene
Suggest `{var:?}` when finding `{?:var}` in inline format strings
Link to issue: https://github.com/rust-lang/rust/issues/106572
This is my first PR to this project, so hopefully I can get some good pointers with me from the first PR.
Currently my idea was to test out whether or not this is the correct solution to this issue and then hopefully expand upon the idea to not only work for Debug formatting but for all of them. If this is a valid solution, I will create a new issue to give a better error message to a broader range of wrong-order formatting.
Convert all the crates that have had their diagnostic migration
completed (except save_analysis because that will be deleted soon and
apfloat because of the licensing problem).
Previously, it only checked whether there was _a_ literal at the span of
the first argument, not whether the literal actually matched up. This
caused issues when a proc macro was generating a different literal with
the same span.
This requires an annoying special case for literals ending in `\n`
because otherwise `println` wouldn't give detailed diagnostics anymore
which would be bad.
Fix incorrect span when using byte-escaped rbrace
Fix#103826, a format args span issue introduced in #102214.
The current solution for tracking skipped characters made it so that certain situations were ambiguous enough that the original span couldn't be worked out later. This PR improves on the original solution by keeping track of groups of skipped characters using a map, and fixes the previous bug. See an example of this ambiguity in the [previous PR's discussion](https://github.com/rust-lang/rust/pull/102214#issuecomment-1258711015).
This makes both variants closer together in size (previously they were
different by 208 bytes -- 16 vs 224). This may make things worse, but
it's worth a try.
Until now out-of-range integers in format string literals
were silently ignored. They wrapped around to zero at
usize::MAX, producing unexpected results.
When using debug builds of rustc, such integers in format string
literals even cause an 'attempt to add with overflow' panic in
rustc.
Fix this by producing an error diagnostic for integers in format
string literals which do not fit into usize.
Fixes#102528
Address issue #99265 by checking each positionally used argument
to see if the argument is named and adding a lint to use the name
instead. This way, when named arguments are used positionally in a
different order than their argument order, the suggested lint is
correct.
For example:
```
println!("{b} {}", a=1, b=2);
```
This will now generate the suggestion:
```
println!("{b} {a}", a=1, b=2);
```
Additionally, this check now also correctly replaces or inserts
only where the positional argument is (or would be if implicit).
Also, width and precision are replaced with their argument names
when they exists.
Since the issues were so closely related, this fix for issue #99265
also fixes issue #99266.
Fixes#99265Fixes#99266
format macro argument parsing fix
When the character next to `{}` is "shifted" (when mapping a byte index
in the format string to span) we should avoid shifting the span end
index, so first map the index of `}` to span, then bump the span,
instead of first mapping the next byte index to a span (which causes
bumping the end span too much).
Regression test added.
Fixes#83344
---
r? ```@estebank```
When the character next to `{}` is "shifted" (when mapping a byte index
in the format string to span) we should avoid shifting the span end
index, so first map the index of `}` to span, then bump the span,
instead of first mapping the next byte index to a span (which causes
bumping the end span too much).
Regression test added.
Fixes#83344
use if let instead of single match arm expressions
use if let instead of single match arm expressions to compact code and reduce nesting (clippy::single_match)