@@ -31,6 +31,12 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
31
31
/// `Result<User, Error>` -> `User`
32
32
const WRAPPER_TYPES : & [ & str ] = & [ "Box" , "Arc" , "Rc" , "Option" , "Result" ] ;
33
33
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
+
34
40
/// Prefixes to strip from methods names
35
41
///
36
42
/// # Examples
@@ -378,6 +384,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
378
384
return name_of_type ( & inner_ty, db, edition) ;
379
385
}
380
386
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
+
381
392
name
382
393
} else if let Some ( trait_) = ty. as_dyn_trait ( ) {
383
394
trait_name ( & trait_, db, edition) ?
@@ -390,12 +401,32 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
390
401
name
391
402
} else if let Some ( inner_ty) = ty. remove_ref ( ) {
392
403
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) ) ;
393
406
} else {
394
407
return None ;
395
408
} ;
396
409
normalize ( & name)
397
410
}
398
411
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
+
399
430
fn trait_name ( trait_ : & hir:: Trait , db : & RootDatabase , edition : Edition ) -> Option < String > {
400
431
let name = trait_. name ( db) . display ( db, edition) . to_string ( ) ;
401
432
if USELESS_TRAITS . contains ( & name. as_str ( ) ) {
@@ -897,6 +928,58 @@ fn foo() { $0(bar())$0; }
897
928
) ;
898
929
}
899
930
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
+
900
983
#[ test]
901
984
fn ref_call ( ) {
902
985
check (
0 commit comments