@@ -1039,40 +1039,75 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
10391039 }
10401040}
10411041
1042- pub ( crate ) fn allowed_targets_applied ( allowed_targets : Vec < Target > , target : Target ) -> String {
1043- if allowed_targets. len ( ) == 1 {
1044- return allowed_targets[ 0 ] . singular_name ( ) . to_string ( ) ;
1045- }
1046-
1042+ /// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to.
1043+ /// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string
1044+ pub ( crate ) fn allowed_targets_applied ( mut allowed_targets : Vec < Target > , target : Target ) -> String {
1045+ // We define groups of "similar" targets.
1046+ // If at least two of the targets are allowed, and the `target` is not in the group,
1047+ // we collapse the entire group to a single entry to simplify the target list
10471048 const FUNCTION_LIKE : & [ Target ] = & [
10481049 Target :: Fn ,
10491050 Target :: Closure ,
1051+ Target :: ForeignFn ,
10501052 Target :: Method ( MethodKind :: Inherent ) ,
10511053 Target :: Method ( MethodKind :: Trait { body : false } ) ,
10521054 Target :: Method ( MethodKind :: Trait { body : true } ) ,
10531055 Target :: Method ( MethodKind :: TraitImpl ) ,
1054- Target :: ForeignFn ,
10551056 ] ;
10561057 const METHOD_LIKE : & [ Target ] = & [
10571058 Target :: Method ( MethodKind :: Inherent ) ,
10581059 Target :: Method ( MethodKind :: Trait { body : false } ) ,
10591060 Target :: Method ( MethodKind :: Trait { body : true } ) ,
10601061 Target :: Method ( MethodKind :: TraitImpl ) ,
10611062 ] ;
1062- const IMPL_LIKE : & [ Target ] = & [ Target :: Impl { of_trait : false } , Target :: Impl { of_trait : true } ] ;
1063-
1064-
1065-
1063+ const IMPL_LIKE : & [ Target ] =
1064+ & [ Target :: Impl { of_trait : false } , Target :: Impl { of_trait : true } ] ;
1065+ const ADT_LIKE : & [ Target ] = & [ Target :: Struct , Target :: Enum ] ;
1066+
1067+ let mut added_fake_targets = Vec :: new ( ) ;
1068+ filter_targets (
1069+ & mut allowed_targets,
1070+ FUNCTION_LIKE ,
1071+ "functions" ,
1072+ target,
1073+ & mut added_fake_targets,
1074+ ) ;
1075+ filter_targets ( & mut allowed_targets, METHOD_LIKE , "methods" , target, & mut added_fake_targets) ;
1076+ filter_targets ( & mut allowed_targets, IMPL_LIKE , "impl blocks" , target, & mut added_fake_targets) ;
1077+ filter_targets ( & mut allowed_targets, ADT_LIKE , "data types" , target, & mut added_fake_targets) ;
1078+
1079+ // If there is now only 1 target left, show that as the only possible target
1080+ if allowed_targets. len ( ) + added_fake_targets. len ( ) == 1 {
1081+ return allowed_targets
1082+ . get ( 0 )
1083+ . map ( |t| t. singular_name ( ) )
1084+ . or ( added_fake_targets. get ( 0 ) . copied ( ) )
1085+ . unwrap ( )
1086+ . to_string ( ) ;
1087+ }
10661088
1067- allowed_targets. iter ( ) . map ( |t| t. plural_name ( ) ) . join ( ", " )
1089+ added_fake_targets
1090+ . iter ( )
1091+ . copied ( )
1092+ . chain ( allowed_targets. iter ( ) . map ( |t| t. plural_name ( ) ) )
1093+ . join ( ", " )
10681094}
10691095
1070- fn filter_targets ( allowed_targets : & mut Vec < Target > , target_group : & ' static [ Target ] , target_group_name : & ' static str , target : Target ) {
1096+ fn filter_targets (
1097+ allowed_targets : & mut Vec < Target > ,
1098+ target_group : & ' static [ Target ] ,
1099+ target_group_name : & ' static str ,
1100+ target : Target ,
1101+ added_fake_targets : & mut Vec < & ' static str > ,
1102+ ) {
10711103 if target_group. contains ( & target) {
1072- return
1104+ return ;
1105+ }
1106+ if allowed_targets. iter ( ) . filter ( |at| target_group. contains ( at) ) . count ( ) < 2 {
1107+ return ;
10731108 }
10741109 allowed_targets. retain ( |t| !target_group. contains ( t) ) ;
1075-
1110+ added_fake_targets . push ( target_group_name ) ;
10761111}
10771112
10781113/// Parse a single integer.
0 commit comments