add 'is_assign_rhs' to avoid weird suggesting 'let'

This commit is contained in:
yukang 2022-11-09 22:00:22 +08:00
parent 5689f9c679
commit c69872bb6c
3 changed files with 41 additions and 29 deletions

View File

@ -527,6 +527,7 @@ struct DiagnosticMetadata<'ast> {
/// Used to detect possible new binding written without `let` and to provide structured suggestion. /// Used to detect possible new binding written without `let` and to provide structured suggestion.
in_assignment: Option<&'ast Expr>, in_assignment: Option<&'ast Expr>,
is_assign_rhs: bool,
/// If we are currently in a trait object definition. Used to point at the bounds when /// If we are currently in a trait object definition. Used to point at the bounds when
/// encountering a struct or enum. /// encountering a struct or enum.
@ -3963,10 +3964,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.resolve_expr(elem, Some(expr)); self.resolve_expr(elem, Some(expr));
self.visit_expr(idx); self.visit_expr(idx);
} }
ExprKind::Assign(..) => { ExprKind::Assign(ref lhs, ref rhs, _) => {
let old = self.diagnostic_metadata.in_assignment.replace(expr); if !self.diagnostic_metadata.is_assign_rhs {
visit::walk_expr(self, expr); self.diagnostic_metadata.in_assignment = Some(expr);
self.diagnostic_metadata.in_assignment = old; }
self.visit_expr(lhs);
self.diagnostic_metadata.is_assign_rhs = true;
self.diagnostic_metadata.in_assignment = None;
self.visit_expr(rhs);
self.diagnostic_metadata.is_assign_rhs = false;
} }
_ => { _ => {
visit::walk_expr(self, expr); visit::walk_expr(self, expr);

View File

@ -1810,36 +1810,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
false false
} }
// try to give a suggestion for this pattern: `name = blah`, which is common in other languages
// suggest `let name = blah` to introduce a new binding
fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool { fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
// try to give a suggestion for this pattern: `name = 1`, which is common in other languages if let Some(Expr { kind: ExprKind::Assign(lhs, .. ), .. }) = self.diagnostic_metadata.in_assignment &&
let mut added_suggestion = false; let ast::ExprKind::Path(None, _) = lhs.kind {
if let Some(Expr { kind: ExprKind::Assign(lhs, rhs, _), .. }) = if !ident_span.from_expansion() {
self.diagnostic_metadata.in_assignment
{
let is_rhs_assign = matches!(rhs.kind, ExprKind::Assign(..));
if let ast::ExprKind::Path(None, _) = lhs.kind && !is_rhs_assign {
let sm = self.r.session.source_map();
let line_span = sm.span_extend_to_line(ident_span);
let ident_name = sm.span_to_snippet(ident_span).unwrap();
// HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros,
// and avoid some special cases like `x = x = x`
if let Ok(line) = sm.span_to_snippet(line_span) &&
let stripped = line.split_whitespace().collect::<String>() &&
stripped.trim().starts_with(&ident_name) &&
stripped.matches(&format!("{}=", &ident_name)).count() == 1
{
err.span_suggestion_verbose( err.span_suggestion_verbose(
ident_span.shrink_to_lo(), ident_span.shrink_to_lo(),
"you might have meant to introduce a new binding", "you might have meant to introduce a new binding",
"let ".to_string(), "let ".to_string(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
added_suggestion = true; return true;
} }
} }
self.diagnostic_metadata.in_assignment = None; false
}
added_suggestion
} }
fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {

View File

@ -2,7 +2,12 @@ error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-104086-suggest-let.rs:2:5 --> $DIR/issue-104086-suggest-let.rs:2:5
| |
LL | x = x = x; LL | x = x = x;
| ^ not found in this scope | ^
|
help: you might have meant to introduce a new binding
|
LL | let x = x = x;
| +++
error[E0425]: cannot find value `x` in this scope error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-104086-suggest-let.rs:2:9 --> $DIR/issue-104086-suggest-let.rs:2:9
@ -20,7 +25,12 @@ error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-104086-suggest-let.rs:7:5 --> $DIR/issue-104086-suggest-let.rs:7:5
| |
LL | x = y = y = y; LL | x = y = y = y;
| ^ not found in this scope | ^
|
help: you might have meant to introduce a new binding
|
LL | let x = y = y = y;
| +++
error[E0425]: cannot find value `y` in this scope error[E0425]: cannot find value `y` in this scope
--> $DIR/issue-104086-suggest-let.rs:7:9 --> $DIR/issue-104086-suggest-let.rs:7:9
@ -44,7 +54,12 @@ error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-104086-suggest-let.rs:13:5 --> $DIR/issue-104086-suggest-let.rs:13:5
| |
LL | x = y = y; LL | x = y = y;
| ^ not found in this scope | ^
|
help: you might have meant to introduce a new binding
|
LL | let x = y = y;
| +++
error[E0425]: cannot find value `y` in this scope error[E0425]: cannot find value `y` in this scope
--> $DIR/issue-104086-suggest-let.rs:13:9 --> $DIR/issue-104086-suggest-let.rs:13:9
@ -62,7 +77,12 @@ error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-104086-suggest-let.rs:18:5 --> $DIR/issue-104086-suggest-let.rs:18:5
| |
LL | x = x = y; LL | x = x = y;
| ^ not found in this scope | ^
|
help: you might have meant to introduce a new binding
|
LL | let x = x = y;
| +++
error[E0425]: cannot find value `x` in this scope error[E0425]: cannot find value `x` in this scope
--> $DIR/issue-104086-suggest-let.rs:18:9 --> $DIR/issue-104086-suggest-let.rs:18:9