1use std::{collections::hash_map::Entry, str::FromStr};
4
5use hir::{Semantics, SemanticsScope};
6use itertools::Itertools;
7use rustc_hash::FxHashMap;
8use stdx::to_lower_snake_case;
9use syntax::{
10 AstNode, Edition, SmolStr, SmolStrBuilder, ToSmolStr,
11 ast::{self, HasName},
12 match_ast,
13};
14
15use crate::RootDatabase;
16
17const USELESS_TRAITS: &[&str] = &["Send", "Sync", "Copy", "Clone", "Eq", "PartialEq"];
19
20const USELESS_NAMES: &[&str] =
24 &["new", "default", "option", "some", "none", "ok", "err", "str", "string", "from", "into"];
25
26const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
27
28const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"];
34
35const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"];
40
41const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"];
48
49const USELESS_METHODS: &[&str] = &[
54 "to_string",
55 "as_str",
56 "to_owned",
57 "as_ref",
58 "clone",
59 "cloned",
60 "expect",
61 "expect_none",
62 "unwrap",
63 "unwrap_none",
64 "unwrap_or",
65 "unwrap_or_default",
66 "unwrap_or_else",
67 "unwrap_unchecked",
68 "iter",
69 "into_iter",
70 "iter_mut",
71 "into_future",
72];
73
74#[derive(Debug, Default)]
94pub struct NameGenerator {
95 pool: FxHashMap<SmolStr, usize>,
96}
97
98impl NameGenerator {
99 pub fn new_with_names<'a>(existing_names: impl Iterator<Item = &'a str>) -> Self {
102 let mut generator = Self::default();
103 existing_names.for_each(|name| generator.insert(name));
104 generator
105 }
106
107 pub fn new_from_scope_locals(scope: Option<SemanticsScope<'_>>) -> Self {
108 let mut generator = Self::default();
109 if let Some(scope) = scope {
110 scope.process_all_names(&mut |name, scope| {
111 if let hir::ScopeDef::Local(_) = scope {
112 generator.insert(name.as_str());
113 }
114 });
115 }
116
117 generator
118 }
119
120 pub fn suggest_name(&mut self, name: &str) -> SmolStr {
123 let (prefix, suffix) = Self::split_numeric_suffix(name);
124 let prefix = SmolStr::new(prefix);
125 let suffix = suffix.unwrap_or(0);
126
127 match self.pool.entry(prefix.clone()) {
128 Entry::Vacant(entry) => {
129 entry.insert(suffix);
130 SmolStr::from_str(name).unwrap()
131 }
132 Entry::Occupied(mut entry) => {
133 let count = entry.get_mut();
134 *count = (*count + 1).max(suffix);
135
136 let mut new_name = SmolStrBuilder::new();
137 new_name.push_str(&prefix);
138 new_name.push_str(count.to_string().as_str());
139 new_name.finish()
140 }
141 }
142 }
143
144 pub fn for_type<'db>(
155 &mut self,
156 ty: &hir::Type<'db>,
157 db: &'db RootDatabase,
158 edition: Edition,
159 ) -> Option<SmolStr> {
160 let name = name_of_type(ty, db, edition)?;
161 Some(self.suggest_name(&name))
162 }
163
164 pub fn for_impl_trait_as_generic(&mut self, ty: &ast::ImplTraitType) -> SmolStr {
174 let c = ty
175 .type_bound_list()
176 .and_then(|bounds| bounds.syntax().text().char_at(0.into()))
177 .unwrap_or('T');
178
179 self.suggest_name(&c.to_string())
180 }
181
182 pub fn for_variable(
196 &mut self,
197 expr: &ast::Expr,
198 sema: &Semantics<'_, RootDatabase>,
199 ) -> SmolStr {
200 if let Some(name) = from_param(expr, sema) {
203 return self.suggest_name(&name);
204 }
205
206 let mut next_expr = Some(expr.clone());
207 while let Some(expr) = next_expr {
208 let name = from_call(&expr)
209 .or_else(|| from_type(&expr, sema))
210 .or_else(|| from_field_name(&expr));
211 if let Some(name) = name {
212 return self.suggest_name(&name);
213 }
214
215 match expr {
216 ast::Expr::RefExpr(inner) => next_expr = inner.expr(),
217 ast::Expr::AwaitExpr(inner) => next_expr = inner.expr(),
218 ast::Expr::CastExpr(inner) => next_expr = inner.expr(),
220 ast::Expr::MethodCallExpr(method) if is_useless_method(&method) => {
221 next_expr = method.receiver();
222 }
223 ast::Expr::ParenExpr(inner) => next_expr = inner.expr(),
224 ast::Expr::TryExpr(inner) => next_expr = inner.expr(),
225 ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(ast::UnaryOp::Deref) => {
226 next_expr = prefix.expr()
227 }
228 _ => break,
229 }
230 }
231
232 self.suggest_name("var_name")
233 }
234
235 fn insert(&mut self, name: &str) {
237 let (prefix, suffix) = Self::split_numeric_suffix(name);
238 let prefix = SmolStr::new(prefix);
239 let suffix = suffix.unwrap_or(0);
240
241 match self.pool.entry(prefix) {
242 Entry::Vacant(entry) => {
243 entry.insert(suffix);
244 }
245 Entry::Occupied(mut entry) => {
246 let count = entry.get_mut();
247 *count = (*count).max(suffix);
248 }
249 }
250 }
251
252 fn split_numeric_suffix(name: &str) -> (&str, Option<usize>) {
257 let pos =
258 name.rfind(|c: char| !c.is_numeric()).expect("Name cannot be empty or all-numeric");
259 let (prefix, suffix) = name.split_at(pos + 1);
260 (prefix, suffix.parse().ok())
261 }
262}
263
264fn normalize(name: &str) -> Option<SmolStr> {
265 let name = to_lower_snake_case(name).to_smolstr();
266
267 if USELESS_NAMES.contains(&name.as_str()) {
268 return None;
269 }
270
271 if USELESS_NAME_PREFIXES.iter().any(|prefix| name.starts_with(prefix)) {
272 return None;
273 }
274
275 if !is_valid_name(&name) {
276 return None;
277 }
278
279 Some(name)
280}
281
282fn is_valid_name(name: &str) -> bool {
283 matches!(
284 super::LexedStr::single_token(syntax::Edition::CURRENT_FIXME, name),
285 Some((syntax::SyntaxKind::IDENT, _error))
286 )
287}
288
289fn is_useless_method(method: &ast::MethodCallExpr) -> bool {
290 let ident = method.name_ref().and_then(|it| it.ident_token());
291
292 match ident {
293 Some(ident) => USELESS_METHODS.contains(&ident.text()),
294 None => false,
295 }
296}
297
298fn from_call(expr: &ast::Expr) -> Option<SmolStr> {
299 from_func_call(expr).or_else(|| from_method_call(expr))
300}
301
302fn from_func_call(expr: &ast::Expr) -> Option<SmolStr> {
303 let call = match expr {
304 ast::Expr::CallExpr(call) => call,
305 _ => return None,
306 };
307 let func = match call.expr()? {
308 ast::Expr::PathExpr(path) => path,
309 _ => return None,
310 };
311 let ident = func.path()?.segment()?.name_ref()?.ident_token()?;
312 normalize(ident.text())
313}
314
315fn from_method_call(expr: &ast::Expr) -> Option<SmolStr> {
316 let method = match expr {
317 ast::Expr::MethodCallExpr(call) => call,
318 _ => return None,
319 };
320 let ident = method.name_ref()?.ident_token()?;
321 let mut name = ident.text();
322
323 if USELESS_METHODS.contains(&name) {
324 return None;
325 }
326
327 for prefix in USELESS_METHOD_PREFIXES {
328 if let Some(suffix) = name.strip_prefix(prefix) {
329 name = suffix;
330 break;
331 }
332 }
333
334 normalize(name)
335}
336
337fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<SmolStr> {
338 let arg_list = expr.syntax().parent().and_then(ast::ArgList::cast)?;
339 let args_parent = arg_list.syntax().parent()?;
340 let func = match_ast! {
341 match args_parent {
342 ast::CallExpr(call) => {
343 let func = call.expr()?;
344 let func_ty = sema.type_of_expr(&func)?.adjusted();
345 func_ty.as_callable(sema.db)?
346 },
347 ast::MethodCallExpr(method) => sema.resolve_method_call_as_callable(&method)?,
348 _ => return None,
349 }
350 };
351
352 let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap();
353 let param = func.params().into_iter().nth(idx)?;
354 let pat = sema.source(param)?.value.right()?.pat()?;
355 let name = var_name_from_pat(&pat)?;
356 normalize(&name.to_smolstr())
357}
358
359fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> {
360 match pat {
361 ast::Pat::IdentPat(var) => var.name(),
362 ast::Pat::RefPat(ref_pat) => var_name_from_pat(&ref_pat.pat()?),
363 ast::Pat::BoxPat(box_pat) => var_name_from_pat(&box_pat.pat()?),
364 _ => None,
365 }
366}
367
368fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<SmolStr> {
369 let ty = sema.type_of_expr(expr)?.adjusted();
370 let ty = ty.remove_ref().unwrap_or(ty);
371 let edition = sema.scope(expr.syntax())?.krate().edition(sema.db);
372
373 name_of_type(&ty, sema.db, edition)
374}
375
376fn name_of_type<'db>(
377 ty: &hir::Type<'db>,
378 db: &'db RootDatabase,
379 edition: Edition,
380) -> Option<SmolStr> {
381 let name = if let Some(adt) = ty.as_adt() {
382 let name = adt.name(db).display(db, edition).to_string();
383
384 if WRAPPER_TYPES.contains(&name.as_str()) {
385 let inner_ty = ty.type_arguments().next()?;
386 return name_of_type(&inner_ty, db, edition);
387 }
388
389 if SEQUENCE_TYPES.contains(&name.as_str()) {
390 let inner_ty = ty.type_arguments().next();
391 return Some(sequence_name(inner_ty.as_ref(), db, edition));
392 }
393
394 name
395 } else if let Some(trait_) = ty.as_dyn_trait() {
396 trait_name(&trait_, db, edition)?
397 } else if let Some(traits) = ty.as_impl_traits(db) {
398 let mut iter = traits.filter_map(|t| trait_name(&t, db, edition));
399 let name = iter.next()?;
400 if iter.next().is_some() {
401 return None;
402 }
403 name
404 } else if let Some(inner_ty) = ty.remove_ref() {
405 return name_of_type(&inner_ty, db, edition);
406 } else if let Some(inner_ty) = ty.as_slice() {
407 return Some(sequence_name(Some(&inner_ty), db, edition));
408 } else {
409 return None;
410 };
411 normalize(&name)
412}
413
414fn sequence_name<'db>(
415 inner_ty: Option<&hir::Type<'db>>,
416 db: &'db RootDatabase,
417 edition: Edition,
418) -> SmolStr {
419 let items_str = SmolStr::new_static("items");
420 let Some(inner_ty) = inner_ty else {
421 return items_str;
422 };
423 let Some(name) = name_of_type(inner_ty, db, edition) else {
424 return items_str;
425 };
426
427 if name.ends_with(['s', 'x', 'y']) {
428 items_str
431 } else {
432 SmolStr::new(format!("{name}s"))
433 }
434}
435
436fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option<String> {
437 let name = trait_.name(db).display(db, edition).to_string();
438 if USELESS_TRAITS.contains(&name.as_str()) {
439 return None;
440 }
441 Some(name)
442}
443
444fn from_field_name(expr: &ast::Expr) -> Option<SmolStr> {
445 let field = match expr {
446 ast::Expr::FieldExpr(field) => field,
447 _ => return None,
448 };
449 let ident = field.name_ref()?.ident_token()?;
450 normalize(ident.text())
451}
452
453#[cfg(test)]
454mod tests {
455 use hir::FileRange;
456 use test_fixture::WithFixture;
457
458 use super::*;
459
460 #[track_caller]
461 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &str) {
462 let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
463 let frange = FileRange { file_id, range: range_or_offset.into() };
464 let sema = Semantics::new(&db);
465
466 let source_file = sema.parse(frange.file_id);
467
468 let element = source_file.syntax().covering_element(frange.range);
469 let expr =
470 element.ancestors().find_map(ast::Expr::cast).expect("selection is not an expression");
471 assert_eq!(
472 expr.syntax().text_range(),
473 frange.range,
474 "selection is not an expression(yet contained in one)"
475 );
476 let name = NameGenerator::default().for_variable(&expr, &sema);
477 assert_eq!(&name, expected);
478 }
479
480 #[test]
481 fn no_args() {
482 check(r#"fn foo() { $0bar()$0 }"#, "bar");
483 check(r#"fn foo() { $0bar.frobnicate()$0 }"#, "frobnicate");
484 }
485
486 #[test]
487 fn single_arg() {
488 check(r#"fn foo() { $0bar(1)$0 }"#, "bar");
489 }
490
491 #[test]
492 fn many_args() {
493 check(r#"fn foo() { $0bar(1, 2, 3)$0 }"#, "bar");
494 }
495
496 #[test]
497 fn path() {
498 check(r#"fn foo() { $0i32::bar(1, 2, 3)$0 }"#, "bar");
499 }
500
501 #[test]
502 fn generic_params() {
503 check(r#"fn foo() { $0bar::<i32>(1, 2, 3)$0 }"#, "bar");
504 check(r#"fn foo() { $0bar.frobnicate::<i32, u32>()$0 }"#, "frobnicate");
505 }
506
507 #[test]
508 fn to_name() {
509 check(
510 r#"
511struct Args;
512struct Config;
513impl Args {
514 fn to_config(&self) -> Config {}
515}
516fn foo() {
517 $0Args.to_config()$0;
518}
519"#,
520 "config",
521 );
522 }
523
524 #[test]
525 fn plain_func() {
526 check(
527 r#"
528fn bar(n: i32, m: u32);
529fn foo() { bar($01$0, 2) }
530"#,
531 "n",
532 );
533 }
534
535 #[test]
536 fn mut_param() {
537 check(
538 r#"
539fn bar(mut n: i32, m: u32);
540fn foo() { bar($01$0, 2) }
541"#,
542 "n",
543 );
544 }
545
546 #[test]
547 fn func_does_not_exist() {
548 check(r#"fn foo() { bar($01$0, 2) }"#, "var_name");
549 }
550
551 #[test]
552 fn unnamed_param() {
553 check(
554 r#"
555fn bar(_: i32, m: u32);
556fn foo() { bar($01$0, 2) }
557"#,
558 "var_name",
559 );
560 }
561
562 #[test]
563 fn tuple_pat() {
564 check(
565 r#"
566fn bar((n, k): (i32, i32), m: u32);
567fn foo() {
568 bar($0(1, 2)$0, 3)
569}
570"#,
571 "var_name",
572 );
573 }
574
575 #[test]
576 fn ref_pat() {
577 check(
578 r#"
579fn bar(&n: &i32, m: u32);
580fn foo() { bar($0&1$0, 3) }
581"#,
582 "n",
583 );
584 }
585
586 #[test]
587 fn box_pat() {
588 check(
589 r#"
590fn bar(box n: &i32, m: u32);
591fn foo() { bar($01$0, 3) }
592"#,
593 "n",
594 );
595 }
596
597 #[test]
598 fn param_out_of_index() {
599 check(
600 r#"
601fn bar(n: i32, m: u32);
602fn foo() { bar(1, 2, $03$0) }
603"#,
604 "var_name",
605 );
606 }
607
608 #[test]
609 fn generic_param_resolved() {
610 check(
611 r#"
612fn bar<T>(n: T, m: u32);
613fn foo() { bar($01$0, 2) }
614"#,
615 "n",
616 );
617 }
618
619 #[test]
620 fn generic_param_unresolved() {
621 check(
622 r#"
623fn bar<T>(n: T, m: u32);
624fn foo<T>(x: T) { bar($0x$0, 2) }
625"#,
626 "n",
627 );
628 }
629
630 #[test]
631 fn method() {
632 check(
633 r#"
634struct S;
635impl S { fn bar(&self, n: i32, m: u32); }
636fn foo() { S.bar($01$0, 2) }
637"#,
638 "n",
639 );
640 }
641
642 #[test]
643 fn method_on_impl_trait() {
644 check(
645 r#"
646struct S;
647trait T {
648 fn bar(&self, n: i32, m: u32);
649}
650impl T for S { fn bar(&self, n: i32, m: u32); }
651fn foo() { S.bar($01$0, 2) }
652"#,
653 "n",
654 );
655 }
656
657 #[test]
658 fn method_ufcs() {
659 check(
660 r#"
661struct S;
662impl S { fn bar(&self, n: i32, m: u32); }
663fn foo() { S::bar(&S, $01$0, 2) }
664"#,
665 "n",
666 );
667 }
668
669 #[test]
670 fn method_self() {
671 check(
672 r#"
673struct S;
674impl S { fn bar(&self, n: i32, m: u32); }
675fn foo() { S::bar($0&S$0, 1, 2) }
676"#,
677 "s",
678 );
679 }
680
681 #[test]
682 fn method_self_named() {
683 check(
684 r#"
685struct S;
686impl S { fn bar(strukt: &Self, n: i32, m: u32); }
687fn foo() { S::bar($0&S$0, 1, 2) }
688"#,
689 "strukt",
690 );
691 }
692
693 #[test]
694 fn i32() {
695 check(r#"fn foo() { let _: i32 = $01$0; }"#, "var_name");
696 }
697
698 #[test]
699 fn u64() {
700 check(r#"fn foo() { let _: u64 = $01$0; }"#, "var_name");
701 }
702
703 #[test]
704 fn bool() {
705 check(r#"fn foo() { let _: bool = $0true$0; }"#, "var_name");
706 }
707
708 #[test]
709 fn struct_unit() {
710 check(
711 r#"
712struct Seed;
713fn foo() { let _ = $0Seed$0; }
714"#,
715 "seed",
716 );
717 }
718
719 #[test]
720 fn struct_unit_to_snake() {
721 check(
722 r#"
723struct SeedState;
724fn foo() { let _ = $0SeedState$0; }
725"#,
726 "seed_state",
727 );
728 }
729
730 #[test]
731 fn struct_single_arg() {
732 check(
733 r#"
734struct Seed(u32);
735fn foo() { let _ = $0Seed(0)$0; }
736"#,
737 "seed",
738 );
739 }
740
741 #[test]
742 fn struct_with_fields() {
743 check(
744 r#"
745struct Seed { value: u32 }
746fn foo() { let _ = $0Seed { value: 0 }$0; }
747"#,
748 "seed",
749 );
750 }
751
752 #[test]
753 fn enum_() {
754 check(
755 r#"
756enum Kind { A, B }
757fn foo() { let _ = $0Kind::A$0; }
758"#,
759 "kind",
760 );
761 }
762
763 #[test]
764 fn enum_generic_resolved() {
765 check(
766 r#"
767enum Kind<T> { A { x: T }, B }
768fn foo() { let _ = $0Kind::A { x:1 }$0; }
769"#,
770 "kind",
771 );
772 }
773
774 #[test]
775 fn enum_generic_unresolved() {
776 check(
777 r#"
778enum Kind<T> { A { x: T }, B }
779fn foo<T>(x: T) { let _ = $0Kind::A { x }$0; }
780"#,
781 "kind",
782 );
783 }
784
785 #[test]
786 fn dyn_trait() {
787 check(
788 r#"
789trait DynHandler {}
790fn bar() -> dyn DynHandler {}
791fn foo() { $0(bar())$0; }
792"#,
793 "dyn_handler",
794 );
795 }
796
797 #[test]
798 fn impl_trait() {
799 check(
800 r#"
801trait StaticHandler {}
802fn bar() -> impl StaticHandler {}
803fn foo() { $0(bar())$0; }
804"#,
805 "static_handler",
806 );
807 }
808
809 #[test]
810 fn impl_trait_plus_clone() {
811 check(
812 r#"
813trait StaticHandler {}
814trait Clone {}
815fn bar() -> impl StaticHandler + Clone {}
816fn foo() { $0(bar())$0; }
817"#,
818 "static_handler",
819 );
820 }
821
822 #[test]
823 fn impl_trait_plus_lifetime() {
824 check(
825 r#"
826trait StaticHandler {}
827trait Clone {}
828fn bar<'a>(&'a i32) -> impl StaticHandler + 'a {}
829fn foo() { $0(bar(&1))$0; }
830"#,
831 "static_handler",
832 );
833 }
834
835 #[test]
836 fn impl_trait_plus_trait() {
837 check(
838 r#"
839trait Handler {}
840trait StaticHandler {}
841fn bar() -> impl StaticHandler + Handler {}
842fn foo() { $0(bar())$0; }
843"#,
844 "bar",
845 );
846 }
847
848 #[test]
849 fn ref_value() {
850 check(
851 r#"
852struct Seed;
853fn bar() -> &Seed {}
854fn foo() { $0(bar())$0; }
855"#,
856 "seed",
857 );
858 }
859
860 #[test]
861 fn box_value() {
862 check(
863 r#"
864struct Box<T>(*const T);
865struct Seed;
866fn bar() -> Box<Seed> {}
867fn foo() { $0(bar())$0; }
868"#,
869 "seed",
870 );
871 }
872
873 #[test]
874 fn box_generic() {
875 check(
876 r#"
877struct Box<T>(*const T);
878fn bar<T>() -> Box<T> {}
879fn foo<T>() { $0(bar::<T>())$0; }
880"#,
881 "bar",
882 );
883 }
884
885 #[test]
886 fn option_value() {
887 check(
888 r#"
889enum Option<T> { Some(T) }
890struct Seed;
891fn bar() -> Option<Seed> {}
892fn foo() { $0(bar())$0; }
893"#,
894 "seed",
895 );
896 }
897
898 #[test]
899 fn result_value() {
900 check(
901 r#"
902enum Result<T, E> { Ok(T), Err(E) }
903struct Seed;
904struct Error;
905fn bar() -> Result<Seed, Error> {}
906fn foo() { $0(bar())$0; }
907"#,
908 "seed",
909 );
910 }
911
912 #[test]
913 fn arc_value() {
914 check(
915 r#"
916struct Arc<T>(*const T);
917struct Seed;
918fn bar() -> Arc<Seed> {}
919fn foo() { $0(bar())$0; }
920"#,
921 "seed",
922 );
923 }
924
925 #[test]
926 fn rc_value() {
927 check(
928 r#"
929struct Rc<T>(*const T);
930struct Seed;
931fn bar() -> Rc<Seed> {}
932fn foo() { $0(bar())$0; }
933"#,
934 "seed",
935 );
936 }
937
938 #[test]
939 fn vec_value() {
940 check(
941 r#"
942struct Vec<T> {};
943struct Seed;
944fn bar() -> Vec<Seed> {}
945fn foo() { $0(bar())$0; }
946"#,
947 "seeds",
948 );
949 }
950
951 #[test]
952 fn vec_value_ends_with_s() {
953 check(
954 r#"
955struct Vec<T> {};
956struct Boss;
957fn bar() -> Vec<Boss> {}
958fn foo() { $0(bar())$0; }
959"#,
960 "items",
961 );
962 }
963
964 #[test]
965 fn vecdeque_value() {
966 check(
967 r#"
968struct VecDeque<T> {};
969struct Seed;
970fn bar() -> VecDeque<Seed> {}
971fn foo() { $0(bar())$0; }
972"#,
973 "seeds",
974 );
975 }
976
977 #[test]
978 fn slice_value() {
979 check(
980 r#"
981struct Vec<T> {};
982struct Seed;
983fn bar() -> &[Seed] {}
984fn foo() { $0(bar())$0; }
985"#,
986 "seeds",
987 );
988 }
989
990 #[test]
991 fn ref_call() {
992 check(
993 r#"
994fn foo() { $0&bar(1, 3)$0 }
995"#,
996 "bar",
997 );
998 }
999
1000 #[test]
1001 fn name_to_string() {
1002 check(
1003 r#"
1004fn foo() { $0function.name().to_string()$0 }
1005"#,
1006 "name",
1007 );
1008 }
1009
1010 #[test]
1011 fn nested_useless_method() {
1012 check(
1013 r#"
1014fn foo() { $0function.name().as_ref().unwrap().to_string()$0 }
1015"#,
1016 "name",
1017 );
1018 }
1019
1020 #[test]
1021 fn struct_field_name() {
1022 check(
1023 r#"
1024struct S<T> {
1025 some_field: T;
1026}
1027fn foo<T>(some_struct: S<T>) { $0some_struct.some_field$0 }
1028"#,
1029 "some_field",
1030 );
1031 }
1032
1033 #[test]
1034 fn from_and_to_func() {
1035 check(
1036 r#"
1037//- minicore: from
1038struct Foo;
1039struct Bar;
1040
1041impl From<Foo> for Bar {
1042 fn from(_: Foo) -> Self {
1043 Bar;
1044 }
1045}
1046
1047fn f(_: Bar) {}
1048
1049fn main() {
1050 let foo = Foo {};
1051 f($0Bar::from(foo)$0);
1052}
1053"#,
1054 "bar",
1055 );
1056
1057 check(
1058 r#"
1059//- minicore: from
1060struct Foo;
1061struct Bar;
1062
1063impl From<Foo> for Bar {
1064 fn from(_: Foo) -> Self {
1065 Bar;
1066 }
1067}
1068
1069fn f(_: Bar) {}
1070
1071fn main() {
1072 let foo = Foo {};
1073 f($0Into::<Bar>::into(foo)$0);
1074}
1075"#,
1076 "bar",
1077 );
1078 }
1079
1080 #[test]
1081 fn useless_name_prefix() {
1082 check(
1083 r#"
1084struct Foo;
1085struct Bar;
1086
1087impl Bar {
1088 fn from_foo(_: Foo) -> Self {
1089 Foo {}
1090 }
1091}
1092
1093fn main() {
1094 let foo = Foo {};
1095 let _ = $0Bar::from_foo(foo)$0;
1096}
1097"#,
1098 "bar",
1099 );
1100
1101 check(
1102 r#"
1103struct Foo;
1104struct Bar;
1105
1106impl Bar {
1107 fn with_foo(_: Foo) -> Self {
1108 Bar {}
1109 }
1110}
1111
1112fn main() {
1113 let foo = Foo {};
1114 let _ = $0Bar::with_foo(foo)$0;
1115}
1116"#,
1117 "bar",
1118 );
1119 }
1120
1121 #[test]
1122 fn conflicts_with_existing_names() {
1123 let mut generator = NameGenerator::default();
1124 assert_eq!(generator.suggest_name("a"), "a");
1125 assert_eq!(generator.suggest_name("a"), "a1");
1126 assert_eq!(generator.suggest_name("a"), "a2");
1127 assert_eq!(generator.suggest_name("a"), "a3");
1128
1129 assert_eq!(generator.suggest_name("b"), "b");
1130 assert_eq!(generator.suggest_name("b2"), "b2");
1131 assert_eq!(generator.suggest_name("b"), "b3");
1132 assert_eq!(generator.suggest_name("b"), "b4");
1133 assert_eq!(generator.suggest_name("b3"), "b5");
1134
1135 let mut generator = NameGenerator::new_with_names(["a", "b", "b2", "c4"].into_iter());
1137 assert_eq!(generator.suggest_name("a"), "a1");
1138 assert_eq!(generator.suggest_name("a"), "a2");
1139
1140 assert_eq!(generator.suggest_name("b"), "b3");
1141 assert_eq!(generator.suggest_name("b2"), "b4");
1142
1143 assert_eq!(generator.suggest_name("c"), "c5");
1144 }
1145}