@@ -7,31 +7,44 @@ use rustc_middle::{
77} ;
88use rustc_span:: Symbol ;
99
10- use common :: { log_info , log_warn } ;
10+ use core :: ops :: Deref ;
1111
12- use crate :: utils :: mir :: TyCtxtExt ;
12+ use common :: { log_debug , log_info , log_warn } ;
1313
14- pub ( super ) const TAG_INSTR_DECISION : & str = concatcp ! ( super :: TAG_INSTRUMENTATION , "::skip" ) ;
14+ use crate :: { config:: InstrumentationRules , utils:: mir:: TyCtxtExt } ;
15+
16+ pub ( super ) const TAG_INSTR_DECISION : & str = concatcp ! ( super :: TAG_INSTRUMENTATION , "::decision" ) ;
1517
1618const TOOL_NAME : & str = crate :: constants:: TOOL_LEAF ;
1719const ATTR_NAME : & str = "instrument" ;
20+ pub ( super ) const KEY_RULES : & str = "instr_rules" ;
21+ const KEY_BAKED_RULES : & str = "instr_rules_baked" ;
1822
19- pub ( super ) fn should_instrument < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) -> bool {
23+ pub ( super ) fn should_instrument < ' tcx > (
24+ tcx : TyCtxt < ' tcx > ,
25+ body : & mut Body < ' tcx > ,
26+ storage : & mut dyn Storage ,
27+ ) -> bool {
2028 let def_id = body. source . def_id ( ) ;
2129
2230 if !decide_instance_kind ( & body. source . instance ) {
2331 return false ;
2432 }
2533
26- if let Some ( ( explicit, item) ) = opt_instrument_attr_inheritable ( tcx, def_id) {
27- log_info ! (
34+ let rules = storage. get_or_insert_with_acc ( KEY_BAKED_RULES . to_owned ( ) , |storage| {
35+ let rules = storage. get_or_default :: < InstrumentationRules > ( KEY_RULES . to_owned ( ) ) ;
36+ rules. to_baked ( )
37+ } ) ;
38+
39+ if let Some ( ( decision, item) ) = find_inheritable_first_filtered ( tcx, def_id, rules. deref ( ) ) {
40+ log_debug ! (
2841 target: TAG_INSTR_DECISION ,
29- "Found explicit instrumentation attribute for {:?} on {:?} with value : {}" ,
42+ "Found a rule for instrumentation of {:?} on {:?} with decision : {}" ,
3043 def_id,
3144 item,
32- explicit
45+ decision
3346 ) ;
34- return explicit ;
47+ return decision ;
3548 }
3649
3750 if is_lang_start_item ( tcx, def_id) {
@@ -81,16 +94,27 @@ fn decide_instance_kind(kind: &InstanceKind) -> bool {
8194 }
8295}
8396
84- /// Returns the value of the `instrument` attribute if it is placed on the item or one of its ancestors.
85- fn opt_instrument_attr_inheritable < ' tcx > (
97+ fn find_inheritable_first_filtered < ' tcx > (
8698 tcx : TyCtxt < ' tcx > ,
8799 def_id : DefId ,
100+ rules : & dyn Fn ( TyCtxt < ' tcx > , DefId ) -> Option < bool > ,
88101) -> Option < ( bool , DefId ) > {
89102 let mut current = def_id;
90103 loop {
91- let attr = opt_instrument_attr ( tcx, current) ;
92- if attr. is_some ( ) {
93- return attr. map ( |v| ( v, current) ) ;
104+ // Attributes take precedence over filters.
105+ if let Some ( explicit) = opt_instrument_attr ( tcx, current) {
106+ log_info ! (
107+ target: TAG_INSTR_DECISION ,
108+ "Found explicit instrumentation attribute for {:?} on {:?} with value: {}" ,
109+ def_id,
110+ current,
111+ explicit
112+ ) ;
113+ return Some ( ( explicit, current) ) ;
114+ }
115+
116+ if let Some ( include) = rules ( tcx, current) {
117+ return Some ( ( include, current) ) ;
94118 }
95119
96120 let parent = tcx. opt_parent ( current) ;
@@ -817,3 +841,91 @@ mod intrinsics {
817841 }
818842}
819843pub ( super ) use intrinsics:: { decide_intrinsic_call, AtomicIntrinsicKind , IntrinsicDecision } ;
844+
845+ use super :: { Storage , StorageExt } ;
846+
847+ mod rules {
848+ use super :: * ;
849+
850+ use crate :: config:: {
851+ AllFormula , AnyFormula , CrateFilter , EntityFilter , EntityLocationFilter ,
852+ InstrumentationRules , LogicFormula , NotFormula ,
853+ } ;
854+
855+ type Predicate = Box < dyn Fn ( TyCtxt < ' _ > , DefId ) -> bool > ;
856+
857+ trait ToPredicate {
858+ fn to_predicate < ' tcx > ( & self ) -> Predicate ;
859+ }
860+
861+ impl InstrumentationRules {
862+ pub ( super ) fn to_baked < ' tcx > ( & self ) -> impl Fn ( TyCtxt < ' _ > , DefId ) -> Option < bool > {
863+ fn to_predicate ( filters : & [ EntityFilter ] ) -> Predicate {
864+ let preds = filters
865+ . iter ( )
866+ . filter_map ( |f| match & f {
867+ EntityFilter :: WholeBody ( formula) => Some ( formula) ,
868+ } )
869+ . map ( |f| f. to_predicate ( ) )
870+ . collect :: < Vec < _ > > ( ) ;
871+ Box :: new ( move |tcx, def_id| preds. iter ( ) . any ( |p| p ( tcx, def_id) ) )
872+ }
873+
874+ let include = to_predicate ( & self . include ) ;
875+ let exclude = to_predicate ( & self . exclude ) ;
876+
877+ move |tcx, def_id| {
878+ if include ( tcx, def_id) {
879+ Some ( true )
880+ } else if exclude ( tcx, def_id) {
881+ Some ( false )
882+ } else {
883+ None
884+ }
885+ }
886+ }
887+ }
888+
889+ impl < T : ToPredicate > ToPredicate for LogicFormula < T > {
890+ fn to_predicate < ' tcx > ( & self ) -> Predicate {
891+ match self {
892+ LogicFormula :: None { } => Box :: new ( |_, _| false ) ,
893+ LogicFormula :: Atom ( f) => f. to_predicate ( ) ,
894+ LogicFormula :: Not ( NotFormula { of } ) => {
895+ let pred = of. to_predicate ( ) ;
896+ Box :: new ( move |tcx, def_id| !pred ( tcx, def_id) )
897+ }
898+ LogicFormula :: Any ( AnyFormula { of } ) => {
899+ let preds = of. iter ( ) . map ( |f| f. to_predicate ( ) ) . collect :: < Vec < _ > > ( ) ;
900+ Box :: new ( move |tcx, def_id| preds. iter ( ) . any ( |p| p ( tcx, def_id) ) )
901+ }
902+ LogicFormula :: All ( AllFormula { of } ) => {
903+ let preds = of. iter ( ) . map ( |f| f. to_predicate ( ) ) . collect :: < Vec < _ > > ( ) ;
904+ Box :: new ( move |tcx, def_id| preds. iter ( ) . all ( |p| p ( tcx, def_id) ) )
905+ }
906+ }
907+ }
908+ }
909+
910+ impl ToPredicate for EntityLocationFilter {
911+ fn to_predicate < ' tcx > ( & self ) -> Predicate {
912+ match self {
913+ EntityLocationFilter :: Crate ( crate_filter) => match crate_filter. clone ( ) {
914+ CrateFilter :: Externality ( is_external) => {
915+ Box :: new ( move |_, def_id| def_id. is_local ( ) != is_external)
916+ }
917+ CrateFilter :: Name ( name) => {
918+ Box :: new ( move |tcx, def_id| tcx. crate_name ( def_id. krate ) . as_str ( ) == name)
919+ }
920+ } ,
921+ EntityLocationFilter :: DefPathMatch ( pattern) => {
922+ let regex = regex_lite:: Regex :: new ( & pattern) . expect ( "Invalid regex pattern" ) ;
923+ Box :: new ( move |tcx, def_id| {
924+ let def_path = tcx. def_path_str ( def_id) ;
925+ regex. is_match ( & def_path)
926+ } )
927+ }
928+ }
929+ }
930+ }
931+ }
0 commit comments