diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-08-02 23:07:45 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-02 23:07:45 +0200 |
| commit | 82feb4996cb9195b0979ab6ab1dac379ade7f500 (patch) | |
| tree | d19ae51411569a4c33809e82922be24dc1e15cc6 /compiler/rustc_builtin_macros/src | |
| parent | 63cd10154dac82503c446baf8eb1b2abd3dac3ff (diff) | |
| parent | 298acef30730ee676fdbc9e731370cd7ccedd431 (diff) | |
| download | rust-82feb4996cb9195b0979ab6ab1dac379ade7f500.tar.gz rust-82feb4996cb9195b0979ab6ab1dac379ade7f500.zip | |
Rollup merge of #99958 - PrestonFrom:issue_99907, r=compiler-errors
Improve position named arguments lint underline and formatting names
For named arguments used as implicit position arguments, underline both
the opening curly brace and either:
* if there is formatting, the next character (which will either be the
closing curl brace or the `:` denoting the start of formatting args)
* if there is no formatting, the entire arg span (important if there is
whitespace like `{ }`)
This should make it more obvious where the named argument should be.
Additionally, in the lint message, emit the formatting argument names
without a dollar sign to avoid potentially confusion.
Fixes #99907
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
| -rw-r--r-- | compiler/rustc_builtin_macros/src/format.rs | 84 |
1 files changed, 59 insertions, 25 deletions
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index f536d0b5900..cec574e38c5 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -16,6 +16,7 @@ use smallvec::SmallVec; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; +use rustc_parse_format::Count; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -57,26 +58,45 @@ struct PositionalNamedArg { replacement: Symbol, /// The span for the positional named argument (so the lint can point a message to it) positional_named_arg_span: Span, + has_formatting: bool, } impl PositionalNamedArg { - /// Determines what span to replace with the name of the named argument - fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> { + /// Determines: + /// 1) span to be replaced with the name of the named argument and + /// 2) span to be underlined for error messages + fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) { if let Some(inner_span) = &self.inner_span_to_replace { - return Some( - cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }), - ); + let span = + cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }); + (Some(span), Some(span)) } else if self.ty == PositionalNamedArgType::Arg { - // In the case of a named argument whose position is implicit, there will not be a span - // to replace. Instead, we insert the name after the `{`, which is the first character - // of arg_span. - return cx - .arg_spans - .get(self.cur_piece) - .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()); + // In the case of a named argument whose position is implicit, if the argument *has* + // formatting, there will not be a span to replace. Instead, we insert the name after + // the `{`, which will be the first character of arg_span. If the argument does *not* + // have formatting, there may or may not be a span to replace. This is because + // whitespace is allowed in arguments without formatting (such as `format!("{ }", 1);`) + // but is not allowed in arguments with formatting (an error will be generated in cases + // like `format!("{ :1.1}", 1.0f32);`. + // For the message span, if there is formatting, we want to use the opening `{` and the + // next character, which will the `:` indicating the start of formatting. If there is + // not any formatting, we want to underline the entire span. + cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| { + if self.has_formatting { + ( + Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()), + Some(arg_span.with_hi(arg_span.lo() + BytePos(2))), + ) + } else { + let replace_start = arg_span.lo() + BytePos(1); + let replace_end = arg_span.hi() - BytePos(1); + let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end); + (Some(to_replace), Some(*arg_span)) + } + }) + } else { + (None, None) } - - None } } @@ -117,10 +137,18 @@ impl PositionalNamedArgsLint { cur_piece: usize, inner_span_to_replace: Option<rustc_parse_format::InnerSpan>, names: &FxHashMap<Symbol, (usize, Span)>, + has_formatting: bool, ) { let start_of_named_args = total_args_length - names.len(); if current_positional_arg >= start_of_named_args { - self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names) + self.maybe_push( + format_argument_index, + ty, + cur_piece, + inner_span_to_replace, + names, + has_formatting, + ) } } @@ -134,6 +162,7 @@ impl PositionalNamedArgsLint { cur_piece: usize, inner_span_to_replace: Option<rustc_parse_format::InnerSpan>, names: &FxHashMap<Symbol, (usize, Span)>, + has_formatting: bool, ) { let named_arg = names .iter() @@ -156,6 +185,7 @@ impl PositionalNamedArgsLint { inner_span_to_replace, replacement, positional_named_arg_span, + has_formatting, }); } } @@ -414,6 +444,9 @@ impl<'a, 'b> Context<'a, 'b> { PositionalNamedArgType::Precision, ); + let has_precision = arg.format.precision != Count::CountImplied; + let has_width = arg.format.width != Count::CountImplied; + // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { @@ -426,6 +459,7 @@ impl<'a, 'b> Context<'a, 'b> { self.curpiece, Some(arg.position_span), &self.names, + has_precision || has_width, ); Exact(i) @@ -439,6 +473,7 @@ impl<'a, 'b> Context<'a, 'b> { self.curpiece, None, &self.names, + has_precision || has_width, ); Exact(i) } @@ -530,6 +565,7 @@ impl<'a, 'b> Context<'a, 'b> { self.curpiece, *inner_span, &self.names, + true, ); self.verify_arg_type(Exact(i), Count); } @@ -1152,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>( fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) { for named_arg in &cx.unused_names_lint.positional_named_args { - let arg_span = named_arg.get_span_to_replace(cx); + let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx); let msg = format!("named argument `{}` is not used by name", named_arg.replacement); - let replacement = match named_arg.ty { - PositionalNamedArgType::Arg => named_arg.replacement.to_string(), - _ => named_arg.replacement.to_string() + "$", - }; cx.ecx.buffered_early_lint.push(BufferedEarlyLint { span: MultiSpan::from_span(named_arg.positional_named_arg_span), msg: msg.clone(), node_id: ast::CRATE_NODE_ID, lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), - diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( - arg_span, - named_arg.positional_named_arg_span, - replacement, - ), + diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally { + position_sp_to_replace, + position_sp_for_msg, + named_arg_sp: named_arg.positional_named_arg_span, + named_arg_name: named_arg.replacement.to_string(), + is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg, + }, }); } } |
