Skip to content

Commit 24f0e14

Browse files
authored
Rollup merge of rust-lang#99119 - TaKO8Ki:remove-string-matching-about-methods, r=cjgillot
Refactor: remove a string matching about methods This patch remove a string matching about methods and adds some rustfix tests.
2 parents e0e6f1d + 45b88af commit 24f0e14

File tree

9 files changed

+130
-80
lines changed

9 files changed

+130
-80
lines changed

compiler/rustc_hir/src/hir.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,14 @@ impl Expr<'_> {
18241824
_ => false,
18251825
}
18261826
}
1827+
1828+
pub fn method_ident(&self) -> Option<Ident> {
1829+
match self.kind {
1830+
ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident),
1831+
ExprKind::Unary(_, expr) | ExprKind::AddrOf(.., expr) => expr.method_ident(),
1832+
_ => None,
1833+
}
1834+
}
18271835
}
18281836

18291837
/// Checks if the specified expression is a built-in range literal.

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,8 @@ symbols! {
14351435
thumb2,
14361436
thumb_mode: "thumb-mode",
14371437
tmm_reg,
1438+
to_string,
1439+
to_vec,
14381440
todo_macro,
14391441
tool_attributes,
14401442
tool_lints,

compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

+48-49
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ use rustc_span::symbol::sym;
1818
use rustc_span::Span;
1919
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
2020

21-
use std::iter;
22-
2321
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2422
pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
2523
err.span_suggestion_short(
@@ -187,55 +185,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
187185
err.span_label(sp, format!("{found} defined here"));
188186
}
189187
} else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
190-
let is_struct_pat_shorthand_field =
191-
self.maybe_get_struct_pattern_shorthand_field(expr).is_some();
192188
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
193189
if !methods.is_empty() {
194-
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
195-
let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
196-
.filter_map(|(receiver, method)| {
197-
let method_call = format!(".{}()", method.name);
198-
if receiver.ends_with(&method_call) {
199-
None // do not suggest code that is already there (#53348)
200-
} else {
201-
let method_call_list = [".to_vec()", ".to_string()"];
202-
let mut sugg = if receiver.ends_with(".clone()")
203-
&& method_call_list.contains(&method_call.as_str())
204-
{
205-
let max_len = receiver.rfind('.').unwrap();
206-
vec![(
207-
expr.span,
208-
format!("{}{}", &receiver[..max_len], method_call),
209-
)]
210-
} else {
211-
if expr.precedence().order()
212-
< ExprPrecedence::MethodCall.order()
213-
{
214-
vec![
215-
(expr.span.shrink_to_lo(), "(".to_string()),
216-
(expr.span.shrink_to_hi(), format!("){}", method_call)),
217-
]
218-
} else {
219-
vec![(expr.span.shrink_to_hi(), method_call)]
220-
}
221-
};
222-
if is_struct_pat_shorthand_field {
223-
sugg.insert(
224-
0,
225-
(expr.span.shrink_to_lo(), format!("{}: ", receiver)),
226-
);
227-
}
228-
Some(sugg)
229-
}
230-
})
231-
.peekable();
232-
if suggestions.peek().is_some() {
233-
err.multipart_suggestions(
234-
"try using a conversion method",
235-
suggestions,
236-
Applicability::MaybeIncorrect,
237-
);
238-
}
190+
let mut suggestions = methods.iter()
191+
.filter_map(|conversion_method| {
192+
let receiver_method_ident = expr.method_ident();
193+
if let Some(method_ident) = receiver_method_ident
194+
&& method_ident.name == conversion_method.name
195+
{
196+
return None // do not suggest code that is already there (#53348)
197+
}
198+
199+
let method_call_list = [sym::to_vec, sym::to_string];
200+
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
201+
&& receiver_method.ident.name == sym::clone
202+
&& method_call_list.contains(&conversion_method.name)
203+
// If receiver is `.clone()` and found type has one of those methods,
204+
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
205+
// to an owned type (`Vec` or `String`). These conversions clone internally,
206+
// so we remove the user's `clone` call.
207+
{
208+
vec![(
209+
receiver_method.ident.span,
210+
conversion_method.name.to_string()
211+
)]
212+
} else if expr.precedence().order()
213+
< ExprPrecedence::MethodCall.order()
214+
{
215+
vec![
216+
(expr.span.shrink_to_lo(), "(".to_string()),
217+
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
218+
]
219+
} else {
220+
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
221+
};
222+
let struct_pat_shorthand_field = self.maybe_get_struct_pattern_shorthand_field(expr);
223+
if let Some(name) = struct_pat_shorthand_field {
224+
sugg.insert(
225+
0,
226+
(expr.span.shrink_to_lo(), format!("{}: ", name)),
227+
);
228+
}
229+
Some(sugg)
230+
})
231+
.peekable();
232+
if suggestions.peek().is_some() {
233+
err.multipart_suggestions(
234+
"try using a conversion method",
235+
suggestions,
236+
Applicability::MaybeIncorrect,
237+
);
239238
}
240239
} else if let ty::Adt(found_adt, found_substs) = found.kind()
241240
&& self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
4+
struct Bravery {
5+
guts: String,
6+
brains: String,
7+
}
8+
9+
fn main() {
10+
let guts = "mettle";
11+
let _ = Bravery {
12+
guts: guts.to_string(), //~ ERROR mismatched types
13+
brains: guts.to_string(), //~ ERROR mismatched types
14+
};
15+
}

src/test/ui/suggestions/issue-52820.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
14
struct Bravery {
25
guts: String,
36
brains: String,

src/test/ui/suggestions/issue-52820.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-52820.rs:9:9
2+
--> $DIR/issue-52820.rs:12:9
33
|
44
LL | guts,
55
| ^^^^ expected struct `String`, found `&str`
@@ -10,13 +10,13 @@ LL | guts: guts.to_string(),
1010
| +++++ ++++++++++++
1111

1212
error[E0308]: mismatched types
13-
--> $DIR/issue-52820.rs:10:17
13+
--> $DIR/issue-52820.rs:13:17
1414
|
1515
LL | brains: guts.clone(),
16-
| ^^^^^^^^^^^^
17-
| |
16+
| ^^^^^-----^^
17+
| | |
18+
| | help: try using a conversion method: `to_string`
1819
| expected struct `String`, found `&str`
19-
| help: try using a conversion method: `guts.to_string()`
2020

2121
error: aborting due to 2 previous errors
2222

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-rustfix
2+
#![allow(unused_variables)]
3+
4+
fn main() {
5+
let items = vec![1, 2, 3];
6+
let ref_items: &[i32] = &items;
7+
let items_clone: Vec<i32> = ref_items.to_vec();
8+
//~^ ERROR mismatched types
9+
10+
// in that case no suggestion will be triggered
11+
let items_clone_2: Vec<i32> = items.clone();
12+
13+
let s = "hi";
14+
let string: String = s.to_string();
15+
//~^ ERROR mismatched types
16+
17+
// in that case no suggestion will be triggered
18+
let s2 = "hi";
19+
let string_2: String = s2.to_string();
20+
}
+15-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1+
// run-rustfix
2+
#![allow(unused_variables)]
3+
14
fn main() {
2-
let items = vec![1, 2, 3];
3-
let ref_items: &[i32] = &items;
4-
let items_clone: Vec<i32> = ref_items.clone();
5-
//~^ ERROR mismatched types
5+
let items = vec![1, 2, 3];
6+
let ref_items: &[i32] = &items;
7+
let items_clone: Vec<i32> = ref_items.clone();
8+
//~^ ERROR mismatched types
69

7-
// in that case no suggestion will be triggered
8-
let items_clone_2:Vec<i32> = items.clone();
10+
// in that case no suggestion will be triggered
11+
let items_clone_2: Vec<i32> = items.clone();
912

10-
let s = "hi";
11-
let string: String = s.clone();
12-
//~^ ERROR mismatched types
13+
let s = "hi";
14+
let string: String = s.clone();
15+
//~^ ERROR mismatched types
1316

14-
// in that case no suggestion will be triggered
15-
let s2 = "hi";
16-
let string_2: String = s2.to_string();
17+
// in that case no suggestion will be triggered
18+
let s2 = "hi";
19+
let string_2: String = s2.to_string();
1720
}

src/test/ui/suggestions/issue-53692.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-53692.rs:4:37
2+
--> $DIR/issue-53692.rs:7:33
33
|
4-
LL | let items_clone: Vec<i32> = ref_items.clone();
5-
| -------- ^^^^^^^^^^^^^^^^^
6-
| | |
7-
| | expected struct `Vec`, found `&[i32]`
8-
| | help: try using a conversion method: `ref_items.to_vec()`
9-
| expected due to this
4+
LL | let items_clone: Vec<i32> = ref_items.clone();
5+
| -------- ^^^^^^^^^^-----^^
6+
| | | |
7+
| | | help: try using a conversion method: `to_vec`
8+
| | expected struct `Vec`, found `&[i32]`
9+
| expected due to this
1010
|
1111
= note: expected struct `Vec<i32>`
1212
found reference `&[i32]`
1313

1414
error[E0308]: mismatched types
15-
--> $DIR/issue-53692.rs:11:30
15+
--> $DIR/issue-53692.rs:14:26
1616
|
17-
LL | let string: String = s.clone();
18-
| ------ ^^^^^^^^^
19-
| | |
20-
| | expected struct `String`, found `&str`
21-
| | help: try using a conversion method: `s.to_string()`
22-
| expected due to this
17+
LL | let string: String = s.clone();
18+
| ------ ^^-----^^
19+
| | | |
20+
| | | help: try using a conversion method: `to_string`
21+
| | expected struct `String`, found `&str`
22+
| expected due to this
2323

2424
error: aborting due to 2 previous errors
2525

0 commit comments

Comments
 (0)