@@ -31,22 +31,46 @@ import (
31
31
const name = "forbiddenmarkers"
32
32
33
33
type analyzer struct {
34
- forbiddenMarkers []string
34
+ forbiddenMarkers []config.ForbiddenMarker
35
+ }
36
+
37
+ // ForbiddenMarkersOptions is a function that configures the
38
+ // forbiddenmarkers analysis.Analyzer
39
+ type ForbiddenMarkersOption func (a * analysis.Analyzer )
40
+
41
+ // WithName sets the name of the forbiddenmarkers analysis.Analyzer
42
+ func WithName (name string ) ForbiddenMarkersOption {
43
+ return func (a * analysis.Analyzer ) {
44
+ a .Name = name
45
+ }
46
+ }
47
+
48
+ // WithDoc sets the doc string of the forbiddenmarkers analysis.Analyzer
49
+ func WithDoc (doc string ) ForbiddenMarkersOption {
50
+ return func (a * analysis.Analyzer ) {
51
+ a .Doc = doc
52
+ }
35
53
}
36
54
37
55
// NewAnalyzer creates a new analysis.Analyzer for the forbiddenmarkers
38
56
// linter based on the provided config.ForbiddenMarkersConfig.
39
- func NewAnalyzer (cfg config.ForbiddenMarkersConfig ) * analysis.Analyzer {
57
+ func NewAnalyzer (cfg config.ForbiddenMarkersConfig , opts ... ForbiddenMarkersOption ) * analysis.Analyzer {
40
58
a := & analyzer {
41
59
forbiddenMarkers : cfg .Markers ,
42
60
}
43
61
44
- return & analysis.Analyzer {
62
+ analyzer := & analysis.Analyzer {
45
63
Name : name ,
46
64
Doc : "Check that no forbidden markers are present on types and fields." ,
47
65
Run : a .run ,
48
66
Requires : []* analysis.Analyzer {inspector .Analyzer },
49
67
}
68
+
69
+ for _ , opt := range opts {
70
+ opt (analyzer )
71
+ }
72
+
73
+ return analyzer
50
74
}
51
75
52
76
func (a * analyzer ) run (pass * analysis.Pass ) (any , error ) {
@@ -66,7 +90,7 @@ func (a *analyzer) run(pass *analysis.Pass) (any, error) {
66
90
return nil , nil //nolint:nilnil
67
91
}
68
92
69
- func checkField (pass * analysis.Pass , field * ast.Field , markersAccess markers.Markers , forbiddenMarkers []string ) {
93
+ func checkField (pass * analysis.Pass , field * ast.Field , markersAccess markers.Markers , forbiddenMarkers []config. ForbiddenMarker ) {
70
94
if field == nil || len (field .Names ) == 0 {
71
95
return
72
96
}
@@ -75,7 +99,7 @@ func checkField(pass *analysis.Pass, field *ast.Field, markersAccess markers.Mar
75
99
check (markers , forbiddenMarkers , reportField (pass , field ))
76
100
}
77
101
78
- func checkType (pass * analysis.Pass , typeSpec * ast.TypeSpec , markersAccess markers.Markers , forbiddenMarkers []string ) {
102
+ func checkType (pass * analysis.Pass , typeSpec * ast.TypeSpec , markersAccess markers.Markers , forbiddenMarkers []config. ForbiddenMarker ) {
79
103
if typeSpec == nil {
80
104
return
81
105
}
@@ -84,15 +108,52 @@ func checkType(pass *analysis.Pass, typeSpec *ast.TypeSpec, markersAccess marker
84
108
check (markers , forbiddenMarkers , reportType (pass , typeSpec ))
85
109
}
86
110
87
- func check (markerSet markers.MarkerSet , forbiddenMarkers []string , reportFunc func (marker markers.Marker )) {
111
+ func check (markerSet markers.MarkerSet , forbiddenMarkers []config. ForbiddenMarker , reportFunc func (marker markers.Marker )) {
88
112
for _ , marker := range forbiddenMarkers {
89
- marks := markerSet .Get (marker )
113
+ marks := markerSet .Get (marker . Identifier )
90
114
for _ , mark := range marks {
91
- reportFunc (mark )
115
+ if markerMatchesAttributeRules (mark , marker .Attributes ... ) {
116
+ reportFunc (mark )
117
+ }
92
118
}
93
119
}
94
120
}
95
121
122
+ // TODO: this should probably return some representation of the marker that is failing the
123
+ // attribute rules so that it can be returned to users helpfully.
124
+ func markerMatchesAttributeRules (marker markers.Marker , attrRules ... config.ForbiddenMarkerAttribute ) bool {
125
+ matchesAll := true
126
+ for _ , attrRule := range attrRules {
127
+ if val , ok := marker .Expressions [attrRule .Attribute ]; ok {
128
+ // if no values are specified, that means the existence match is enough
129
+ // and we can continue to the next rule
130
+ if len (attrRule .Values ) == 0 {
131
+ continue
132
+ }
133
+
134
+ // if the value doesn't match one of the forbidden ones, this marker is not forbidden
135
+ matchesOneValue := false
136
+ for _ , value := range attrRule .Values {
137
+ if val == value {
138
+ matchesOneValue = true
139
+ break
140
+ }
141
+ }
142
+
143
+ if ! matchesOneValue {
144
+ matchesAll = false
145
+ break
146
+ }
147
+ }
148
+ // if the marker doesn't contain the attribute for a specified rule it fails the AND
149
+ // operation.
150
+ matchesAll = false
151
+ break
152
+ }
153
+
154
+ return matchesAll
155
+ }
156
+
96
157
func reportField (pass * analysis.Pass , field * ast.Field ) func (marker markers.Marker ) {
97
158
return func (marker markers.Marker ) {
98
159
pass .Report (analysis.Diagnostic {
0 commit comments