@@ -31,6 +31,12 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
3131/// `Result<User, Error>` -> `User`
3232const WRAPPER_TYPES : & [ & str ] = & [ "Box" , "Arc" , "Rc" , "Option" , "Result" ] ;
3333
34+ /// Generic types replaced by a plural of their first argument.
35+ ///
36+ /// # Examples
37+ /// `Vec<Name>` -> "names"
38+ const SEQUENCE_TYPES : & [ & str ] = & [ "Vec" , "VecDeque" , "LinkedList" ] ;
39+
3440/// Prefixes to strip from methods names
3541///
3642/// # Examples
@@ -378,6 +384,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
378384 return name_of_type ( & inner_ty, db, edition) ;
379385 }
380386
387+ if SEQUENCE_TYPES . contains ( & name. as_str ( ) ) {
388+ let inner_ty = ty. type_arguments ( ) . next ( ) ;
389+ return Some ( sequence_name ( inner_ty. as_ref ( ) , db, edition) ) ;
390+ }
391+
381392 name
382393 } else if let Some ( trait_) = ty. as_dyn_trait ( ) {
383394 trait_name ( & trait_, db, edition) ?
@@ -390,12 +401,32 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
390401 name
391402 } else if let Some ( inner_ty) = ty. remove_ref ( ) {
392403 return name_of_type ( & inner_ty, db, edition) ;
404+ } else if let Some ( inner_ty) = ty. as_slice ( ) {
405+ return Some ( sequence_name ( Some ( & inner_ty) , db, edition) ) ;
393406 } else {
394407 return None ;
395408 } ;
396409 normalize ( & name)
397410}
398411
412+ fn sequence_name ( inner_ty : Option < & hir:: Type > , db : & RootDatabase , edition : Edition ) -> SmolStr {
413+ let items_str = SmolStr :: new_static ( "items" ) ;
414+ let Some ( inner_ty) = inner_ty else {
415+ return items_str;
416+ } ;
417+ let Some ( name) = name_of_type ( inner_ty, db, edition) else {
418+ return items_str;
419+ } ;
420+
421+ if name. ends_with ( [ 's' , 'x' , 'y' ] ) {
422+ // Given a type called e.g. "Boss", "Fox" or "Story", don't try to
423+ // create a plural.
424+ items_str
425+ } else {
426+ SmolStr :: new ( format ! ( "{name}s" ) )
427+ }
428+ }
429+
399430fn trait_name ( trait_ : & hir:: Trait , db : & RootDatabase , edition : Edition ) -> Option < String > {
400431 let name = trait_. name ( db) . display ( db, edition) . to_string ( ) ;
401432 if USELESS_TRAITS . contains ( & name. as_str ( ) ) {
@@ -897,6 +928,58 @@ fn foo() { $0(bar())$0; }
897928 ) ;
898929 }
899930
931+ #[ test]
932+ fn vec_value ( ) {
933+ check (
934+ r#"
935+ struct Vec<T> {};
936+ struct Seed;
937+ fn bar() -> Vec<Seed> {}
938+ fn foo() { $0(bar())$0; }
939+ "# ,
940+ "seeds" ,
941+ ) ;
942+ }
943+
944+ #[ test]
945+ fn vec_value_ends_with_s ( ) {
946+ check (
947+ r#"
948+ struct Vec<T> {};
949+ struct Boss;
950+ fn bar() -> Vec<Boss> {}
951+ fn foo() { $0(bar())$0; }
952+ "# ,
953+ "items" ,
954+ ) ;
955+ }
956+
957+ #[ test]
958+ fn vecdeque_value ( ) {
959+ check (
960+ r#"
961+ struct VecDeque<T> {};
962+ struct Seed;
963+ fn bar() -> VecDeque<Seed> {}
964+ fn foo() { $0(bar())$0; }
965+ "# ,
966+ "seeds" ,
967+ ) ;
968+ }
969+
970+ #[ test]
971+ fn slice_value ( ) {
972+ check (
973+ r#"
974+ struct Vec<T> {};
975+ struct Seed;
976+ fn bar() -> &[Seed] {}
977+ fn foo() { $0(bar())$0; }
978+ "# ,
979+ "seeds" ,
980+ ) ;
981+ }
982+
900983 #[ test]
901984 fn ref_call ( ) {
902985 check (
0 commit comments