From 1599c5a82175485bdebbb231fba1cedcac742868 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 11 Jul 2022 02:19:45 +0900 Subject: [PATCH] remove a string matching about methods --- .../src/check/fn_ctxt/suggestions.rs | 101 ++++++++++-------- src/test/ui/suggestions/issue-52820.fixed | 15 +++ src/test/ui/suggestions/issue-52820.rs | 3 + src/test/ui/suggestions/issue-52820.stderr | 10 +- src/test/ui/suggestions/issue-53692.fixed | 20 ++++ src/test/ui/suggestions/issue-53692.rs | 27 ++--- src/test/ui/suggestions/issue-53692.stderr | 28 ++--- 7 files changed, 126 insertions(+), 78 deletions(-) create mode 100644 src/test/ui/suggestions/issue-52820.fixed create mode 100644 src/test/ui/suggestions/issue-53692.fixed diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 863a981134f..721fc8c5681 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -14,7 +14,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -187,55 +187,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(self.tcx.def_span(def_id), &format!("{} defined here", found)); } } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { - let is_struct_pat_shorthand_field = - self.maybe_get_struct_pattern_shorthand_field(expr).is_some(); + let struct_pat_shorthand_field = self.maybe_get_struct_pattern_shorthand_field(expr); let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); if !methods.is_empty() { - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) - .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.name); - if receiver.ends_with(&method_call) { - None // do not suggest code that is already there (#53348) - } else { - let method_call_list = [".to_vec()", ".to_string()"]; - let mut sugg = if receiver.ends_with(".clone()") - && method_call_list.contains(&method_call.as_str()) - { - let max_len = receiver.rfind('.').unwrap(); - vec![( - expr.span, - format!("{}{}", &receiver[..max_len], method_call), - )] - } else { - if expr.precedence().order() - < ExprPrecedence::MethodCall.order() - { - vec![ - (expr.span.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), format!("){}", method_call)), - ] - } else { - vec![(expr.span.shrink_to_hi(), method_call)] - } - }; - if is_struct_pat_shorthand_field { - sugg.insert( - 0, - (expr.span.shrink_to_lo(), format!("{}: ", receiver)), - ); - } - Some(sugg) + let mut suggestions = iter::zip(iter::repeat(&expr), &methods) + .filter_map(|(receiver_expr, method)| { + let method_call = format!(".{}()", method.name); + fn method_ident(expr: &hir::Expr<'_>) -> Option { + match expr.kind { + ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), + ExprKind::Unary(_, expr) | ExprKind::AddrOf(.., expr) => method_ident(expr), + _ => None } - }) - .peekable(); - if suggestions.peek().is_some() { - err.multipart_suggestions( - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); - } + } + let method_ident = method_ident(&receiver_expr); + if let Some(method_ident) = method_ident + && method_ident.name == method.name + { + None // do not suggest code that is already there (#53348) + } else { + let method_call_list = [".to_vec()", ".to_string()"]; + let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = receiver_expr.kind + && receiver_method.ident.name == sym::clone + && method_call_list.contains(&method_call.as_str()) + { + vec![( + receiver_method.ident.span, + method.name.to_string() + )] + } else { + if expr.precedence().order() + < ExprPrecedence::MethodCall.order() + { + vec![ + (expr.span.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), format!("){}", method_call)), + ] + } else { + vec![(expr.span.shrink_to_hi(), method_call)] + } + }; + if let Some(name) = struct_pat_shorthand_field { + sugg.insert( + 0, + (expr.span.shrink_to_lo(), format!("{}: ", name)), + ); + } + Some(sugg) + } + }) + .peekable(); + if suggestions.peek().is_some() { + err.multipart_suggestions( + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); } } else if let ty::Adt(found_adt, found_substs) = found.kind() && self.tcx.is_diagnostic_item(sym::Option, found_adt.did()) diff --git a/src/test/ui/suggestions/issue-52820.fixed b/src/test/ui/suggestions/issue-52820.fixed new file mode 100644 index 00000000000..514690de4d0 --- /dev/null +++ b/src/test/ui/suggestions/issue-52820.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(dead_code)] + +struct Bravery { + guts: String, + brains: String, +} + +fn main() { + let guts = "mettle"; + let _ = Bravery { + guts: guts.to_string(), //~ ERROR mismatched types + brains: guts.to_string(), //~ ERROR mismatched types + }; +} diff --git a/src/test/ui/suggestions/issue-52820.rs b/src/test/ui/suggestions/issue-52820.rs index 075b07f5652..17cd9224c57 100644 --- a/src/test/ui/suggestions/issue-52820.rs +++ b/src/test/ui/suggestions/issue-52820.rs @@ -1,3 +1,6 @@ +// run-rustfix +#![allow(dead_code)] + struct Bravery { guts: String, brains: String, diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr index 7b465844501..09269ed4eee 100644 --- a/src/test/ui/suggestions/issue-52820.stderr +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-52820.rs:9:9 + --> $DIR/issue-52820.rs:12:9 | LL | guts, | ^^^^ expected struct `String`, found `&str` @@ -10,13 +10,13 @@ LL | guts: guts.to_string(), | +++++ ++++++++++++ error[E0308]: mismatched types - --> $DIR/issue-52820.rs:10:17 + --> $DIR/issue-52820.rs:13:17 | LL | brains: guts.clone(), - | ^^^^^^^^^^^^ - | | + | ^^^^^-----^^ + | | | + | | help: try using a conversion method: `to_string` | expected struct `String`, found `&str` - | help: try using a conversion method: `guts.to_string()` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-53692.fixed b/src/test/ui/suggestions/issue-53692.fixed new file mode 100644 index 00000000000..35a677b4761 --- /dev/null +++ b/src/test/ui/suggestions/issue-53692.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused_variables)] + +fn main() { + let items = vec![1, 2, 3]; + let ref_items: &[i32] = &items; + let items_clone: Vec = ref_items.to_vec(); + //~^ ERROR mismatched types + + // in that case no suggestion will be triggered + let items_clone_2: Vec = items.clone(); + + let s = "hi"; + let string: String = s.to_string(); + //~^ ERROR mismatched types + + // in that case no suggestion will be triggered + let s2 = "hi"; + let string_2: String = s2.to_string(); +} diff --git a/src/test/ui/suggestions/issue-53692.rs b/src/test/ui/suggestions/issue-53692.rs index 30f344e4282..6f6707be5f6 100644 --- a/src/test/ui/suggestions/issue-53692.rs +++ b/src/test/ui/suggestions/issue-53692.rs @@ -1,17 +1,20 @@ +// run-rustfix +#![allow(unused_variables)] + fn main() { - let items = vec![1, 2, 3]; - let ref_items: &[i32] = &items; - let items_clone: Vec = ref_items.clone(); -//~^ ERROR mismatched types + let items = vec![1, 2, 3]; + let ref_items: &[i32] = &items; + let items_clone: Vec = ref_items.clone(); + //~^ ERROR mismatched types - // in that case no suggestion will be triggered - let items_clone_2:Vec = items.clone(); + // in that case no suggestion will be triggered + let items_clone_2: Vec = items.clone(); - let s = "hi"; - let string: String = s.clone(); -//~^ ERROR mismatched types + let s = "hi"; + let string: String = s.clone(); + //~^ ERROR mismatched types - // in that case no suggestion will be triggered - let s2 = "hi"; - let string_2: String = s2.to_string(); + // in that case no suggestion will be triggered + let s2 = "hi"; + let string_2: String = s2.to_string(); } diff --git a/src/test/ui/suggestions/issue-53692.stderr b/src/test/ui/suggestions/issue-53692.stderr index 09c78da54bc..3a1b624f402 100644 --- a/src/test/ui/suggestions/issue-53692.stderr +++ b/src/test/ui/suggestions/issue-53692.stderr @@ -1,25 +1,25 @@ error[E0308]: mismatched types - --> $DIR/issue-53692.rs:4:37 + --> $DIR/issue-53692.rs:7:33 | -LL | let items_clone: Vec = ref_items.clone(); - | -------- ^^^^^^^^^^^^^^^^^ - | | | - | | expected struct `Vec`, found `&[i32]` - | | help: try using a conversion method: `ref_items.to_vec()` - | expected due to this +LL | let items_clone: Vec = ref_items.clone(); + | -------- ^^^^^^^^^^-----^^ + | | | | + | | | help: try using a conversion method: `to_vec` + | | expected struct `Vec`, found `&[i32]` + | expected due to this | = note: expected struct `Vec` found reference `&[i32]` error[E0308]: mismatched types - --> $DIR/issue-53692.rs:11:30 + --> $DIR/issue-53692.rs:14:26 | -LL | let string: String = s.clone(); - | ------ ^^^^^^^^^ - | | | - | | expected struct `String`, found `&str` - | | help: try using a conversion method: `s.to_string()` - | expected due to this +LL | let string: String = s.clone(); + | ------ ^^-----^^ + | | | | + | | | help: try using a conversion method: `to_string` + | | expected struct `String`, found `&str` + | expected due to this error: aborting due to 2 previous errors