1
Fork 0

Use multipart_suggestions

This records that the suggestions are mutually-exclusive (i.e., only one
should be applied).
This commit is contained in:
Noah Lev 2022-02-21 18:52:47 -08:00
commit 725cde42d5
3 changed files with 54 additions and 60 deletions

View file

@ -218,6 +218,27 @@ impl std::fmt::Display for UnaryFixity {
} }
} }
struct MultiSugg {
msg: String,
patches: Vec<(Span, String)>,
applicability: Applicability,
}
impl MultiSugg {
fn emit(self, err: &mut DiagnosticBuilder<'_>) {
err.multipart_suggestion(&self.msg, self.patches, self.applicability);
}
/// Overrides individual messages and applicabilities.
fn emit_many(
err: &mut DiagnosticBuilder<'_>,
msg: &str,
applicability: Applicability,
suggestions: impl Iterator<Item = Self>,
) {
err.multipart_suggestions(msg, suggestions.map(|s| s.patches), applicability);
}
}
// SnapshotParser is used to create a snapshot of the parser // SnapshotParser is used to create a snapshot of the parser
// without causing duplicate errors being emitted when the `Parser` // without causing duplicate errors being emitted when the `Parser`
// is dropped. // is dropped.
@ -1281,33 +1302,33 @@ impl<'a> Parser<'a> {
}; };
match kind.standalone { match kind.standalone {
IsStandalone::Standalone => { IsStandalone::Standalone => self.inc_dec_standalone_suggest(kind, spans).emit(&mut err),
self.inc_dec_standalone_recovery(&mut err, kind, spans, false)
}
IsStandalone::Subexpr => { IsStandalone::Subexpr => {
let Ok(base_src) = self.span_to_snippet(base.span) let Ok(base_src) = self.span_to_snippet(base.span)
else { return help_base_case(err, base) }; else { return help_base_case(err, base) };
match kind.fixity { match kind.fixity {
UnaryFixity::Pre => { UnaryFixity::Pre => {
self.prefix_inc_dec_suggest(base_src, &mut err, kind, spans) self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
} }
UnaryFixity::Post => { UnaryFixity::Post => {
self.postfix_inc_dec_suggest(base_src, &mut err, kind, spans) self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
} }
} }
} }
IsStandalone::Maybe => { IsStandalone::Maybe => {
let Ok(base_src) = self.span_to_snippet(base.span) let Ok(base_src) = self.span_to_snippet(base.span)
else { return help_base_case(err, base) }; else { return help_base_case(err, base) };
match kind.fixity { let sugg1 = match kind.fixity {
UnaryFixity::Pre => { UnaryFixity::Pre => self.prefix_inc_dec_suggest(base_src, kind, spans),
self.prefix_inc_dec_suggest(base_src, &mut err, kind, spans) UnaryFixity::Post => self.postfix_inc_dec_suggest(base_src, kind, spans),
} };
UnaryFixity::Post => { let sugg2 = self.inc_dec_standalone_suggest(kind, spans);
self.postfix_inc_dec_suggest(base_src, &mut err, kind, spans) MultiSugg::emit_many(
} &mut err,
} "use `+= 1` instead",
self.inc_dec_standalone_recovery(&mut err, kind, spans, true) Applicability::MaybeIncorrect,
[sugg1, sugg2].into_iter(),
)
} }
} }
Err(err) Err(err)
@ -1316,61 +1337,46 @@ impl<'a> Parser<'a> {
fn prefix_inc_dec_suggest( fn prefix_inc_dec_suggest(
&mut self, &mut self,
base_src: String, base_src: String,
err: &mut DiagnosticBuilder<'a>,
kind: IncDecRecovery, kind: IncDecRecovery,
(pre_span, post_span): (Span, Span), (pre_span, post_span): (Span, Span),
) { ) -> MultiSugg {
err.multipart_suggestion( MultiSugg {
&format!("use `{}= 1` instead", kind.op.chr()), msg: format!("use `{}= 1` instead", kind.op.chr()),
vec![ patches: vec![
(pre_span, "{ ".to_string()), (pre_span, "{ ".to_string()),
(post_span, format!(" {}= 1; {} }}", kind.op.chr(), base_src)), (post_span, format!(" {}= 1; {} }}", kind.op.chr(), base_src)),
], ],
Applicability::MachineApplicable, applicability: Applicability::MachineApplicable,
); }
} }
fn postfix_inc_dec_suggest( fn postfix_inc_dec_suggest(
&mut self, &mut self,
base_src: String, base_src: String,
err: &mut DiagnosticBuilder<'a>,
kind: IncDecRecovery, kind: IncDecRecovery,
(pre_span, post_span): (Span, Span), (pre_span, post_span): (Span, Span),
) { ) -> MultiSugg {
let tmp_var = if base_src.trim() == "tmp" { "tmp_" } else { "tmp" }; let tmp_var = if base_src.trim() == "tmp" { "tmp_" } else { "tmp" };
err.multipart_suggestion( MultiSugg {
&format!("use `{}= 1` instead", kind.op.chr()), msg: format!("use `{}= 1` instead", kind.op.chr()),
vec![ patches: vec![
(pre_span, format!("{{ let {} = ", tmp_var)), (pre_span, format!("{{ let {} = ", tmp_var)),
(post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)), (post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)),
], ],
Applicability::HasPlaceholders, applicability: Applicability::HasPlaceholders,
); }
} }
fn inc_dec_standalone_recovery( fn inc_dec_standalone_suggest(
&mut self, &mut self,
err: &mut DiagnosticBuilder<'a>,
kind: IncDecRecovery, kind: IncDecRecovery,
(pre_span, post_span): (Span, Span), (pre_span, post_span): (Span, Span),
maybe_not_standalone: bool, ) -> MultiSugg {
) { MultiSugg {
let msg = if maybe_not_standalone { msg: format!("use `{}= 1` instead", kind.op.chr()),
"or, if you don't need to use it as an expression, change it to this".to_owned() patches: vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))],
} else { applicability: Applicability::MachineApplicable,
format!("use `{}= 1` instead", kind.op.chr()) }
};
let applicability = if maybe_not_standalone {
// FIXME: Unspecified isn't right, but it's the least wrong option
Applicability::Unspecified
} else {
Applicability::MachineApplicable
};
err.multipart_suggestion(
&msg,
vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))],
applicability,
);
} }
/// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`.

View file

@ -8,8 +8,6 @@ help: use `+= 1` instead
| |
LL | { let tmp = i; i += 1; tmp }; LL | { let tmp = i; i += 1; tmp };
| +++++++++++ ~~~~~~~~~~~~~~~ | +++++++++++ ~~~~~~~~~~~~~~~
help: or, if you don't need to use it as an expression, change it to this
|
LL - i++; LL - i++;
LL + i += 1; LL + i += 1;
| |
@ -24,8 +22,6 @@ help: use `+= 1` instead
| |
LL | while { let tmp = i; i += 1; tmp } < 5 { LL | while { let tmp = i; i += 1; tmp } < 5 {
| +++++++++++ ~~~~~~~~~~~~~~~ | +++++++++++ ~~~~~~~~~~~~~~~
help: or, if you don't need to use it as an expression, change it to this
|
LL - while i++ < 5 { LL - while i++ < 5 {
LL + while i += 1 < 5 { LL + while i += 1 < 5 {
| |
@ -40,8 +36,6 @@ help: use `+= 1` instead
| |
LL | { let tmp_ = tmp; tmp += 1; tmp_ }; LL | { let tmp_ = tmp; tmp += 1; tmp_ };
| ++++++++++++ ~~~~~~~~~~~~~~~~~~ | ++++++++++++ ~~~~~~~~~~~~~~~~~~
help: or, if you don't need to use it as an expression, change it to this
|
LL - tmp++; LL - tmp++;
LL + tmp += 1; LL + tmp += 1;
| |
@ -56,8 +50,6 @@ help: use `+= 1` instead
| |
LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 { LL | while { let tmp_ = tmp; tmp += 1; tmp_ } < 5 {
| ++++++++++++ ~~~~~~~~~~~~~~~~~~ | ++++++++++++ ~~~~~~~~~~~~~~~~~~
help: or, if you don't need to use it as an expression, change it to this
|
LL - while tmp++ < 5 { LL - while tmp++ < 5 {
LL + while tmp += 1 < 5 { LL + while tmp += 1 < 5 {
| |

View file

@ -8,8 +8,6 @@ help: use `+= 1` instead
| |
LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp }; LL | { let tmp = foo.bar.qux; foo.bar.qux += 1; tmp };
| +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~ | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~
help: or, if you don't need to use it as an expression, change it to this
|
LL - foo.bar.qux++; LL - foo.bar.qux++;
LL + foo.bar.qux += 1; LL + foo.bar.qux += 1;
| |
@ -24,8 +22,6 @@ help: use `+= 1` instead
| |
LL | { let tmp = s.tmp; s.tmp += 1; tmp }; LL | { let tmp = s.tmp; s.tmp += 1; tmp };
| +++++++++++ ~~~~~~~~~~~~~~~~~~~ | +++++++++++ ~~~~~~~~~~~~~~~~~~~
help: or, if you don't need to use it as an expression, change it to this
|
LL - s.tmp++; LL - s.tmp++;
LL + s.tmp += 1; LL + s.tmp += 1;
| |