Skip to content

Commit 8d19d9e

Browse files
committed
review: updates based on review from Joel
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
1 parent 013a77c commit 8d19d9e

File tree

16 files changed

+131
-118
lines changed

16 files changed

+131
-118
lines changed

docs/linters.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ Naming conventions must have:
318318
- A human-readable message to be included in violation errors.
319319
- A regular expression that will match text within the field name that violates the convention.
320320
- A defined "operation". Allowed operations are `Inform`, `Drop`, `DropField`, and `Replace`.
321+
321322
The `Inform` operation will simply inform when a field name violates the naming convention.
322323
The `Drop` operation will suggest a fix that drops violating text from the field name.
323324
The `DropField` operation will suggest a fix that removes the field in it's entirety.
@@ -374,8 +375,8 @@ linterConfig:
374375
```yaml
375376
linterConfig:
376377
namingconventions:
377-
conventions:
378-
- name: englishcolour
378+
conventions:
379+
- name: BritishEnglishColour
379380
violationMatcher: (?i)color
380381
operation: Replace
381382
replace: colour

pkg/analysis/namingconventions/analyzer.go

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func checkField(pass *analysis.Pass, field *ast.Field, tagInfo extractjsontags.F
9393
case OperationDrop:
9494
reportDrop(pass, field, tagInfo, convention, matcher)
9595

96-
case OperationReplace:
96+
case OperationReplacement:
9797
reportReplace(pass, field, tagInfo, convention, matcher)
9898
}
9999
}
@@ -102,23 +102,24 @@ func checkField(pass *analysis.Pass, field *ast.Field, tagInfo extractjsontags.F
102102
func reportConventionWithSuggestedFixes(pass *analysis.Pass, field *ast.Field, convention Convention, suggestedFixes ...analysis.SuggestedFix) {
103103
pass.Report(analysis.Diagnostic{
104104
Pos: field.Pos(),
105-
Message: fmt.Sprintf("naming convention %q: %s", convention.Name, convention.Message),
105+
Message: fmt.Sprintf("naming convention %q: field %s: %s", convention.Name, utils.FieldName(field), convention.Message),
106106
SuggestedFixes: suggestedFixes,
107107
})
108108
}
109109

110110
func reportDropField(pass *analysis.Pass, field *ast.Field, convention Convention) {
111-
suggestedFixes := []analysis.SuggestedFix{}
112-
suggestedFixes = append(suggestedFixes, analysis.SuggestedFix{
113-
Message: "remove the field",
114-
TextEdits: []analysis.TextEdit{
115-
{
116-
Pos: field.Pos(),
117-
NewText: []byte(""),
118-
End: field.End(),
111+
suggestedFixes := []analysis.SuggestedFix{
112+
{
113+
Message: "remove the field",
114+
TextEdits: []analysis.TextEdit{
115+
{
116+
Pos: field.Pos(),
117+
NewText: []byte(""),
118+
End: field.End(),
119+
},
119120
},
120121
},
121-
})
122+
}
122123

123124
reportConventionWithSuggestedFixes(pass, field, convention, suggestedFixes...)
124125
}
@@ -129,7 +130,7 @@ func reportDrop(pass *analysis.Pass, field *ast.Field, tagInfo extractjsontags.F
129130
}
130131

131132
func reportReplace(pass *analysis.Pass, field *ast.Field, tagInfo extractjsontags.FieldTagInfo, convention Convention, matcher *regexp.Regexp) {
132-
suggestedFixes := suggestedFixesForReplacement(field, tagInfo, matcher, convention.Replace)
133+
suggestedFixes := suggestedFixesForReplacement(field, tagInfo, matcher, convention.Replacement)
133134
reportConventionWithSuggestedFixes(pass, field, convention, suggestedFixes...)
134135
}
135136

@@ -151,8 +152,6 @@ func suggestFixesForSerializedFieldName(tagInfo extractjsontags.FieldTagInfo, ma
151152
return nil
152153
}
153154

154-
suggestedFixes := []analysis.SuggestedFix{}
155-
156155
// This should prevent panics from slice access when the replacement
157156
// string ends up being a length of 1 and still result in a technically
158157
// correct JSON tag name value.
@@ -169,18 +168,18 @@ func suggestFixesForSerializedFieldName(tagInfo extractjsontags.FieldTagInfo, ma
169168
tagReplacementMessage = "remove offending text from serialized field name"
170169
}
171170

172-
suggestedFixes = append(suggestedFixes, analysis.SuggestedFix{
173-
Message: tagReplacementMessage,
174-
TextEdits: []analysis.TextEdit{
175-
{
176-
Pos: tagInfo.Pos,
177-
NewText: []byte(tagReplacement),
178-
End: tagInfo.End,
171+
return []analysis.SuggestedFix{
172+
{
173+
Message: tagReplacementMessage,
174+
TextEdits: []analysis.TextEdit{
175+
{
176+
Pos: tagInfo.Pos,
177+
NewText: []byte(tagReplacement),
178+
End: tagInfo.End,
179+
},
179180
},
180181
},
181-
})
182-
183-
return suggestedFixes
182+
}
184183
}
185184

186185
func suggestFixesForGoFieldName(field *ast.Field, matcher *regexp.Regexp, replacementStr string) []analysis.SuggestedFix {
@@ -193,24 +192,22 @@ func suggestFixesForGoFieldName(field *ast.Field, matcher *regexp.Regexp, replac
193192
return nil
194193
}
195194

196-
suggestedFixes := []analysis.SuggestedFix{}
197-
198195
replacementMessage := fmt.Sprintf("replace offending text in Go type with %q", replacementStr)
199196

200197
if len(replacementStr) == 0 {
201198
replacementMessage = "remove offending text from Go type field"
202199
}
203200

204-
suggestedFixes = append(suggestedFixes, analysis.SuggestedFix{
205-
Message: replacementMessage,
206-
TextEdits: []analysis.TextEdit{
207-
{
208-
Pos: field.Pos(),
209-
NewText: []byte(replacement),
210-
End: field.Pos() + token.Pos(len(fieldName)),
201+
return []analysis.SuggestedFix{
202+
{
203+
Message: replacementMessage,
204+
TextEdits: []analysis.TextEdit{
205+
{
206+
Pos: field.Pos(),
207+
NewText: []byte(replacement),
208+
End: field.Pos() + token.Pos(len(fieldName)),
209+
},
211210
},
212211
},
213-
})
214-
215-
return suggestedFixes
212+
}
216213
}

pkg/analysis/namingconventions/analyzer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ func Test(t *testing.T) {
3636
{
3737
Name: "preferbehaviour",
3838
ViolationMatcher: "(?i)behavior",
39-
Operation: namingconventions.OperationReplace,
39+
Operation: namingconventions.OperationReplacement,
4040
Message: "prefer the use of the word 'behaviour' instead of 'behavior'.",
41-
Replace: "Behaviour",
41+
Replacement: "Behaviour",
4242
},
4343
{
4444
Name: "nounsupported",

pkg/analysis/namingconventions/config.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ type Config struct {
3030
type Convention struct {
3131
// name is a required human-readable name to
3232
// associate with the field naming convention.
33+
// name is case-sensitive.
3334
Name string `json:"name,omitempty"`
3435

35-
// violationMatcher is a required regular expression
36+
// violationMatcher is a required RE2 compliant regular expression
3637
// used to identify violating portions of a field name.
3738
ViolationMatcher string `json:"violationMatcher,omitempty"`
3839

@@ -55,18 +56,18 @@ type Convention struct {
5556
// portion of the field name matched by the violationMatcher
5657
// expression.
5758
//
58-
// When set to Replace, the namingconventions linter will
59+
// When set to Replacement, the namingconventions linter will
5960
// suggest that any fields matching this conventions should
6061
// replace the matched portion of the field name with the value
6162
// specified in the replace field.
6263
Operation Operation `json:"operation,omitempty"`
6364

64-
// replace configures the string that should
65+
// replacement configures the string that should
6566
// replace the matched portion of a field name
6667
// that violates this conventions.
67-
// replace is required when operation is set to Replace
68+
// replacement is required when operation is set to Replacement
6869
// and forbidden otherwise.
69-
Replace string `json:"replace,omitempty,omitzero"`
70+
Replacement string `json:"replacement,omitempty,omitzero"`
7071

7172
// message is a required human-readable message
7273
// to be included in the linter error if a field
@@ -88,10 +89,10 @@ const (
8889
// the naming convention is violated.
8990
OperationDrop Operation = "Drop"
9091

91-
// OperationReplace signals that the offending text
92+
// OperationReplacement signals that the offending text
9293
// should be replaced in the field name when
9394
// the naming convention is violated.
94-
OperationReplace Operation = "Replace"
95+
OperationReplacement Operation = "Replacement"
9596

9697
// OperationInform signals that no action
9798
// should be taken, beyond issuing a linter error

pkg/analysis/namingconventions/doc.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Naming conventions must have:
2626
- A human-readable message to be included in violation errors.
2727
- A regular expression that will match text within the field name that violates the convention.
2828
- A defined "operation". Allowed operations are "Inform", "Drop", "DropField", and "Replace".
29+
2930
The "Inform" operation will simply inform via a linter error when a field name violates the naming convention.
3031
The "Drop" operation will suggest a fix that drops violating text from the field name.
3132
The "DropField" operation will suggest a fix that removes the field in it's entirety.
@@ -78,10 +79,10 @@ linterConfig:
7879
7980
namingconventions:
8081
conventions:
81-
- name: englishcolour
82+
- name: BritishEnglishColour
8283
violationMatcher: (?i)color
83-
operation: Replace
84-
replace: colour
84+
operation: Replacement
85+
replacement: colour
8586
message: prefer 'colour' over 'color' when referring to colours in field names
8687
8788
```

pkg/analysis/namingconventions/initializer.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ func validateConventions(fldPath *field.Path, conventions ...Convention) field.E
7676
return fieldErrs
7777
}
7878

79-
// The cyclop linter says this has cyclomatic complexity of 15.
8079
func validateConvention(fldPath *field.Path, convention Convention) field.ErrorList {
8180
fieldErrs := field.ErrorList{}
8281

@@ -98,32 +97,32 @@ func validateConvention(fldPath *field.Path, convention Convention) field.ErrorL
9897
}
9998

10099
fieldErrs = append(fieldErrs, validateOperation(fldPath.Child("operation"), convention.Operation)...)
101-
fieldErrs = append(fieldErrs, validateReplace(fldPath.Child("replace"), convention.Operation, matcher, convention.Replace)...)
100+
fieldErrs = append(fieldErrs, validateReplace(fldPath.Child("replacement"), convention.Operation, matcher, convention.Replacement)...)
102101

103102
return fieldErrs
104103
}
105104

106105
func validateOperation(fldPath *field.Path, operation Operation) field.ErrorList {
107-
allowedOperations := sets.New(OperationDrop, OperationInform, OperationReplace, OperationDropField)
106+
allowedOperations := sets.New(OperationDrop, OperationInform, OperationReplacement, OperationDropField)
108107

109108
if len(operation) == 0 {
110109
return field.ErrorList{field.Required(fldPath, "operation is required")}
111110
}
112111

113112
if len(operation) > 0 && !allowedOperations.Has(operation) {
114-
return field.ErrorList{field.Invalid(fldPath, operation, fmt.Sprintf("operation must be one of %q, %q, %q, or %q", OperationInform, OperationDrop, OperationDropField, OperationReplace))}
113+
return field.ErrorList{field.Invalid(fldPath, operation, fmt.Sprintf("operation must be one of %q, %q, %q, or %q", OperationInform, OperationDrop, OperationDropField, OperationReplacement))}
115114
}
116115

117116
return field.ErrorList{}
118117
}
119118

120119
func validateReplace(fldPath *field.Path, operation Operation, matcher *regexp.Regexp, replace string) field.ErrorList {
121-
if (len(replace) > 0 && operation != OperationReplace) || (len(replace) == 0 && operation == OperationReplace) {
122-
return field.ErrorList{field.Invalid(fldPath, replace, "replace must be specified when operation is 'Replace' and is forbidden otherwise")}
120+
if (len(replace) > 0 && operation != OperationReplacement) || (len(replace) == 0 && operation == OperationReplacement) {
121+
return field.ErrorList{field.Invalid(fldPath, replace, "replacement must be specified when operation is 'Replacement' and is forbidden otherwise")}
123122
}
124123

125-
if len(replace) > 0 && operation == OperationReplace && matcher.MatchString(replace) {
126-
return field.ErrorList{field.Invalid(fldPath, replace, "replace must not match violationMatcher")}
124+
if len(replace) > 0 && operation == OperationReplacement && matcher.MatchString(replace) {
125+
return field.ErrorList{field.Invalid(fldPath, replace, "replacement must not be matched by violationMatcher")}
127126
}
128127

129128
return field.ErrorList{}

pkg/analysis/namingconventions/initializer_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -151,48 +151,48 @@ var _ = Describe("namingconventions initializer", func() {
151151
},
152152
},
153153
},
154-
expectedErr: "namingconventions.conventions[0].operation: Invalid value: \"Unknown\": operation must be one of \"Inform\", \"Drop\", \"DropField\", or \"Replace\"",
154+
expectedErr: "namingconventions.conventions[0].operation: Invalid value: \"Unknown\": operation must be one of \"Inform\", \"Drop\", \"DropField\", or \"Replacement\"",
155155
}),
156-
Entry("With an invalid namingconventions configuration with a replace when operation is not 'Replace'", testCase{
156+
Entry("With an invalid namingconventions configuration with a replacement when operation is not 'replacement'", testCase{
157157
config: &namingconventions.Config{
158158
Conventions: []namingconventions.Convention{
159159
{
160160
Name: "nothing",
161161
ViolationMatcher: "(?i)thing",
162162
Operation: namingconventions.OperationDrop,
163163
Message: "no fields should have any variations of the word 'thing' in their name",
164-
Replace: "item",
164+
Replacement: "item",
165165
},
166166
},
167167
},
168-
expectedErr: "namingconventions.conventions[0].replace: Invalid value: \"item\": replace must be specified when operation is 'Replace' and is forbidden otherwise",
168+
expectedErr: "namingconventions.conventions[0].replacement: Invalid value: \"item\": replacement must be specified when operation is 'Replacement' and is forbidden otherwise",
169169
}),
170-
Entry("With an invalid namingconventions configuration with no replace when operation is 'Replace'", testCase{
170+
Entry("With an invalid namingconventions configuration with no replacement when operation is 'replacement'", testCase{
171171
config: &namingconventions.Config{
172172
Conventions: []namingconventions.Convention{
173173
{
174174
Name: "nothing",
175175
ViolationMatcher: "(?i)thing",
176-
Operation: namingconventions.OperationReplace,
176+
Operation: namingconventions.OperationReplacement,
177177
Message: "no fields should have any variations of the word 'thing' in their name",
178178
},
179179
},
180180
},
181-
expectedErr: "namingconventions.conventions[0].replace: Invalid value: \"\": replace must be specified when operation is 'Replace' and is forbidden otherwise",
181+
expectedErr: "namingconventions.conventions[0].replacement: Invalid value: \"\": replacement must be specified when operation is 'Replacement' and is forbidden otherwise",
182182
}),
183183
Entry("With an invalid namingconventions configuration where replacement string matches violationMatcher", testCase{
184184
config: &namingconventions.Config{
185185
Conventions: []namingconventions.Convention{
186186
{
187187
Name: "nothing",
188188
ViolationMatcher: "(?i)thing",
189-
Operation: namingconventions.OperationReplace,
189+
Operation: namingconventions.OperationReplacement,
190190
Message: "no fields should have any variations of the word 'thing' in their name",
191-
Replace: "anotherthing",
191+
Replacement: "anotherthing",
192192
},
193193
},
194194
},
195-
expectedErr: "namingconventions.conventions[0].replace: Invalid value: \"anotherthing\": replace must not match violationMatcher",
195+
expectedErr: "namingconventions.conventions[0].replacement: Invalid value: \"anotherthing\": replacement must not be matched by violationMatcher",
196196
}),
197197
)
198198
})

pkg/analysis/namingconventions/namingconventions_suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
. "github.com/onsi/gomega"
2323
)
2424

25-
func TestConditions(t *testing.T) {
25+
func TestNamingConventions(t *testing.T) {
2626
RegisterFailHandler(Fail)
2727
RunSpecs(t, "namingconventions")
2828
}

pkg/analysis/namingconventions/testdata/src/a/a.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package a
22

33
// Shouldn't care about Go types
44
type BasketOfFruit struct {
5-
RedFruit []string `json:"redFruit,omitempty"` // want `naming convention "nofruit": no fields should contain any variations of the word 'fruit' in their name`
6-
OrangeFruit []string `json:"orangeFruit,omitempty"` // want `naming convention "nofruit": no fields should contain any variations of the word 'fruit' in their name`
7-
GreenFruit []string `json:"greenFruit,omitempty"` // want `naming convention "nofruit": no fields should contain any variations of the word 'fruit' in their name`
8-
FruitBlue []string `json:"fruitBlue,omitempty"` // want `naming convention "nofruit": no fields should contain any variations of the word 'fruit' in their name`
9-
Fruit []string `json:"fruit,omitempty"` // want `naming convention "nofruit": no fields should contain any variations of the word 'fruit' in their name`
10-
AFruit string `json:"aFruit,omitempty"` // want `naming convention "nofruit": no fields should contain any variations of the word 'fruit' in their name`
5+
RedFruit []string `json:"redFruit,omitempty"` // want `naming convention "nofruit": field RedFruit: no fields should contain any variations of the word 'fruit' in their name`
6+
OrangeFruit []string `json:"orangeFruit,omitempty"` // want `naming convention "nofruit": field OrangeFruit: no fields should contain any variations of the word 'fruit' in their name`
7+
GreenFruit []string `json:"greenFruit,omitempty"` // want `naming convention "nofruit": field GreenFruit: no fields should contain any variations of the word 'fruit' in their name`
8+
FruitBlue []string `json:"fruitBlue,omitempty"` // want `naming convention "nofruit": field FruitBlue: no fields should contain any variations of the word 'fruit' in their name`
9+
Fruit []string `json:"fruit,omitempty"` // want `naming convention "nofruit": field Fruit: no fields should contain any variations of the word 'fruit' in their name`
10+
AFruit string `json:"aFruit,omitempty"` // want `naming convention "nofruit": field AFruit: no fields should contain any variations of the word 'fruit' in their name`
1111
}
1212

1313
// Shouldn't care about methods
@@ -21,16 +21,16 @@ func IsFruit(in string) {
2121
}
2222

2323
type SpecialBehaviors struct {
24-
SomethingBehavior string `json:"somethingBehavior,omitempty"` // want `naming convention "preferbehaviour": prefer the use of the word 'behaviour' instead of 'behavior'.`
25-
BehaviorCrazy bool `json:"behaviorCrazy,omitempty"` // want `naming convention "preferbehaviour": prefer the use of the word 'behaviour' instead of 'behavior'.`
24+
SomethingBehavior string `json:"somethingBehavior,omitempty"` // want `naming convention "preferbehaviour": field SomethingBehavior: prefer the use of the word 'behaviour' instead of 'behavior'.`
25+
BehaviorCrazy bool `json:"behaviorCrazy,omitempty"` // want `naming convention "preferbehaviour": field BehaviorCrazy: prefer the use of the word 'behaviour' instead of 'behavior'.`
2626
}
2727

2828
type Configurations struct {
2929
SomeSupportedThingy string `json:"someSupportedThingy,omitempty"`
30-
UnsupportedThingy string `json:"unsupportedThingy,omitempty"` // want `naming convention "nounsupported": no fields allowing for unsupported behaviors allowed`
30+
UnsupportedThingy string `json:"unsupportedThingy,omitempty"` // want `naming convention "nounsupported": field UnsupportedThingy: no fields allowing for unsupported behaviors allowed`
3131
}
3232

3333
type TestSet struct {
34-
TestName string `json:"testName,omitempty"` // want `naming convention "notest": no temporary test fields`
35-
Other string `json:"otherTest,omitempty"` // want `naming convention "notest": no temporary test fields`
34+
TestName string `json:"testName,omitempty"` // want `naming convention "notest": field TestName: no temporary test fields`
35+
Other string `json:"otherTest,omitempty"` // want `naming convention "notest": field Other: no temporary test fields`
3636
}

0 commit comments

Comments
 (0)