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