Skip to content

Commit 5180baf

Browse files
committed
nophase: wrap namingconventions linter
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
1 parent fcbf6de commit 5180baf

File tree

4 files changed

+39
-73
lines changed

4 files changed

+39
-73
lines changed

pkg/analysis/nophase/analyzer.go

Lines changed: 33 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,81 +16,51 @@ limitations under the License.
1616
package nophase
1717

1818
import (
19-
"go/ast"
20-
"strings"
19+
"errors"
20+
"fmt"
2121

2222
"golang.org/x/tools/go/analysis"
23-
"golang.org/x/tools/go/analysis/passes/inspect"
24-
"golang.org/x/tools/go/ast/inspector"
25-
kalerrors "sigs.k8s.io/kube-api-linter/pkg/analysis/errors"
26-
"sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/extractjsontags"
27-
"sigs.k8s.io/kube-api-linter/pkg/analysis/utils"
23+
"k8s.io/apimachinery/pkg/util/validation/field"
24+
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
25+
"sigs.k8s.io/kube-api-linter/pkg/analysis/namingconventions"
2826
)
2927

30-
const name = "nophase"
31-
32-
// Analyzer is the analyzer for the nophase package.
33-
// It checks that no struct fields named 'phase', or that contain phase as a
34-
// substring are present.
35-
var Analyzer = &analysis.Analyzer{
36-
Name: name,
37-
Doc: "phase fields are deprecated and conditions should be preferred, avoid phase like enum fields",
38-
Run: run,
39-
Requires: []*analysis.Analyzer{inspect.Analyzer, extractjsontags.Analyzer},
40-
}
28+
const (
29+
name = "nophase"
30+
doc = "phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
31+
)
4132

42-
func run(pass *analysis.Pass) (any, error) {
43-
inspect, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
44-
if !ok {
45-
return nil, kalerrors.ErrCouldNotGetInspector
33+
var errUnexpectedInitializerType = errors.New("expected namingconventions.Initializer() to be of type initializer.ConfigurableAnalyzerInitializer, but was not")
34+
35+
func newAnalyzer() *analysis.Analyzer {
36+
cfg := &namingconventions.Config{
37+
Conventions: []namingconventions.Convention{
38+
{
39+
Name: "nophase",
40+
ViolationMatcher: "(?i)phase",
41+
Operation: namingconventions.OperationInform,
42+
Message: "phase fields are deprecated and conditions should be preferred, avoid phase like enum fields",
43+
},
44+
},
4645
}
4746

48-
jsonTags, ok := pass.ResultOf[extractjsontags.Analyzer].(extractjsontags.StructFieldTags)
47+
configInit, ok := namingconventions.Initializer().(initializer.ConfigurableAnalyzerInitializer)
4948
if !ok {
50-
return nil, kalerrors.ErrCouldNotGetJSONTags
49+
panic(fmt.Errorf("getting initializer: %w", errUnexpectedInitializerType))
5150
}
5251

53-
// Filter to fields so that we can iterate over fields in a struct.
54-
nodeFilter := []ast.Node{
55-
(*ast.Field)(nil),
52+
errs := configInit.ValidateConfig(cfg, field.NewPath("nophase"))
53+
if err := errs.ToAggregate(); err != nil {
54+
panic(fmt.Errorf("nophase linter has an invalid namingconventions configuration: %w", err))
5655
}
5756

58-
// Preorder visits all the nodes of the AST in depth-first order. It calls
59-
// f(n) for each node n before it visits n's children.
60-
//
61-
// We use the filter defined above, ensuring we only look at struct fields.
62-
inspect.Preorder(nodeFilter, func(n ast.Node) {
63-
field, ok := n.(*ast.Field)
64-
if !ok {
65-
return
66-
}
67-
68-
if field == nil || len(field.Names) == 0 {
69-
return
70-
}
71-
72-
fieldName := utils.FieldName(field)
73-
74-
// First check if the struct field name contains 'phase'
75-
if strings.Contains(strings.ToLower(fieldName), "phase") {
76-
pass.Reportf(field.Pos(),
77-
"field %s: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields",
78-
fieldName,
79-
)
80-
81-
return
82-
}
83-
84-
// Then check if the json serialization of the field contains 'phase'
85-
tagInfo := jsonTags.FieldTags(field)
57+
analyzer, err := configInit.Init(cfg)
58+
if err != nil {
59+
panic(fmt.Errorf("nophase linter encountered an error initializing wrapped namingconventions analyzer: %w", err))
60+
}
8661

87-
if strings.Contains(strings.ToLower(tagInfo.Name), "phase") {
88-
pass.Reportf(field.Pos(),
89-
"field %s: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields",
90-
fieldName,
91-
)
92-
}
93-
})
62+
analyzer.Name = name
63+
analyzer.Doc = doc
9464

95-
return nil, nil //nolint:nilnil
65+
return analyzer
9666
}

pkg/analysis/nophase/analyzer_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
16-
package nophase_test
16+
package nophase
1717

1818
import (
1919
"testing"
2020

2121
"golang.org/x/tools/go/analysis/analysistest"
22-
"sigs.k8s.io/kube-api-linter/pkg/analysis/nophase"
2322
)
2423

2524
func Test(t *testing.T) {
2625
testdata := analysistest.TestData()
27-
analysistest.RunWithSuggestedFixes(t, testdata, nophase.Analyzer, "a")
26+
analysistest.RunWithSuggestedFixes(t, testdata, newAnalyzer(), "a")
2827
}

pkg/analysis/nophase/initializer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func init() {
2929
func Initializer() initializer.AnalyzerInitializer {
3030
return initializer.NewInitializer(
3131
name,
32-
Analyzer,
32+
newAnalyzer(),
3333
true,
3434
)
3535
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,18 @@ package a
22

33
type NoPhaseTestStruct struct {
44
// +optional
5-
Phase *string `json:"phase,omitempty"` // want "field Phase: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
6-
5+
Phase *string `json:"phase,omitempty"` // want "naming convention \"nophase\": phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
76
}
87

98
// DoNothing is used to check that the analyser doesn't report on methods.
109
func (NoPhaseTestStruct) DoNothing() {}
1110

1211
type NoSubPhaseTestStruct struct {
1312
// +optional
14-
FooPhase *string `json:"fooPhase,omitempty"` // want "field FooPhase: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
15-
13+
FooPhase *string `json:"fooPhase,omitempty"` // want "naming convention \"nophase\": phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
1614
}
1715

1816
type SerializedPhaseTeststruct struct {
1917
// +optional
20-
FooField *string `json:"fooPhase,omitempty"` // want "field FooField: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
21-
18+
FooField *string `json:"fooPhase,omitempty"` // want "naming convention \"nophase\": phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
2219
}

0 commit comments

Comments
 (0)