@@ -19,12 +19,13 @@ type ExcludeRule struct {
1919
2020// compiledExcludeRule is a pre-compiled version of PathExcludeRule for efficient matching
2121type compiledExcludeRule struct {
22- pathRegex * regexp.Regexp
23- keyRegexes []* regexp.Regexp
24- valueRegexes []* regexp.Regexp
25- ruleSet map [string ]bool // Set of rule IDs to exclude
26- excludeAll bool // True if "*" was specified in rules
27- original ExcludeRule // Keep original for error messages
22+ pathRegex * regexp.Regexp
23+ keyRegexes []* regexp.Regexp
24+ valueRegexes []* regexp.Regexp
25+ ruleSet map [string ]bool // Set of rule IDs to exclude
26+ excludeAll bool // True if "*" was specified in rules
27+ noAddendaExcludes bool // True if no keyRegexes or valueRegexes
28+ original ExcludeRule // Keep original for error messages
2829}
2930
3031// ExclusionFilter handles filtering of issues based on path and rule combinations
@@ -97,33 +98,74 @@ func NewExclusionFilter(rules []ExcludeRule) (*ExclusionFilter, error) {
9798 return nil , fmt .Errorf ("exclude-rules[%d].values: %w" , i , err )
9899 }
99100
101+ noAddendaExcludes := len (keyRegexes ) == 0 && len (valueRegexes ) == 0
102+
100103 ruleSet := make (map [string ]bool )
101104 excludeAll := false
102105
103106 for _ , ruleID := range rule .Rules {
104107 ruleID = strings .TrimSpace (ruleID )
105- if ruleID == "*" {
108+ if ruleID == "*" && noAddendaExcludes {
106109 excludeAll = true
107110 } else if ruleID != "" {
108111 ruleSet [ruleID ] = true
109112 }
110113 }
111114
112115 compiled = append (compiled , compiledExcludeRule {
113- pathRegex : regex ,
114- keyRegexes : keyRegexes ,
115- valueRegexes : valueRegexes ,
116- ruleSet : ruleSet ,
117- excludeAll : excludeAll ,
118- original : rule ,
116+ pathRegex : regex ,
117+ keyRegexes : keyRegexes ,
118+ valueRegexes : valueRegexes ,
119+ ruleSet : ruleSet ,
120+ excludeAll : excludeAll ,
121+ noAddendaExcludes : noAddendaExcludes ,
122+ original : rule ,
119123 })
120124 }
121125
122126 return & ExclusionFilter {rules : compiled }, nil
123127}
124128
129+ // ExcludesAddenda returns whether an issue containing addenda
130+ // should be excluded from the results, assuming all of the following:
131+ // - The issue's path matches the exclude rule.
132+ // - The issue's ruleID matches the exclude rule.
133+ //
134+ // In other words, this method will further limit the exlude rule's scope,
135+ // if the issue has addenda matching either keys or values
136+ // which were specified in the rule.
137+ func (r * compiledExcludeRule ) ExcludesAddenda (addenda any ) bool {
138+ if addenda == nil {
139+ return false
140+ }
141+
142+ if len (r .keyRegexes ) > 0 {
143+ if keyer , ok := addenda .(Keyer ); ok {
144+ key := keyer .Key ()
145+ for _ , regex := range r .keyRegexes {
146+ if RegexMatchWithCache (regex , key ) {
147+ return true
148+ }
149+ }
150+ }
151+ }
152+
153+ if len (r .valueRegexes ) > 0 {
154+ if valuer , ok := addenda .(Valuer ); ok {
155+ value := valuer .Value ()
156+ for _ , regex := range r .valueRegexes {
157+ if RegexMatchWithCache (regex , value ) {
158+ return true
159+ }
160+ }
161+ }
162+ }
163+
164+ return false
165+ }
166+
125167// ShouldExclude returns true if the given issue should be excluded based on
126- // its file path, rule ID, and addenda
168+ // its file path, rule ID, and addenda.
127169func (f * ExclusionFilter ) ShouldExclude (filePath , ruleID string , addenda any ) bool {
128170 if f == nil || len (f .rules ) == 0 {
129171 return false
@@ -138,7 +180,7 @@ func (f *ExclusionFilter) ShouldExclude(filePath, ruleID string, addenda any) bo
138180 return true
139181 }
140182 if rule .ruleSet [ruleID ] {
141- return true
183+ return rule . noAddendaExcludes || rule . ExcludesAddenda ( addenda )
142184 }
143185 }
144186 }
0 commit comments