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