Skip to content

Commit af7865e

Browse files
Nophase linter
Initial commit of a nophase linter. Phases, much like capes simply won't do! https://i.redd.it/84209d3ydns91.jpg
1 parent 2774b4c commit af7865e

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed

pkg/analysis/nophase/analyzer.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package nophase
2+
3+
import (
4+
"errors"
5+
"go/ast"
6+
"strings"
7+
8+
"golang.org/x/tools/go/analysis"
9+
"golang.org/x/tools/go/analysis/passes/inspect"
10+
"golang.org/x/tools/go/ast/inspector"
11+
)
12+
13+
const name = "nophase"
14+
15+
var errCouldNotGetInspector = errors.New("could not get inspector")
16+
17+
var Analyzer = &analysis.Analyzer{
18+
Name: name,
19+
Doc: "phase fields are deprecated and conditions should be preferred, avoid phase like enum fields",
20+
Run: run,
21+
Requires: []*analysis.Analyzer{inspect.Analyzer},
22+
}
23+
24+
func run(pass *analysis.Pass) (interface{}, error) {
25+
inspect, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
26+
if !ok {
27+
return nil, errCouldNotGetInspector
28+
}
29+
30+
// Filter to structs so that we can iterate over fields in a struct.
31+
nodeFilter := []ast.Node{
32+
(*ast.StructType)(nil),
33+
}
34+
35+
// Preorder visits all the nodes of the AST in depth-first order. It calls
36+
// f(n) for each node n before it visits n's children.
37+
//
38+
// We use the filter defined above, ensuring we only look at struct fields.
39+
inspect.Preorder(nodeFilter, func(n ast.Node) {
40+
sTyp, ok := n.(*ast.StructType)
41+
if !ok {
42+
return
43+
}
44+
45+
if sTyp.Fields == nil {
46+
return
47+
}
48+
49+
for _, field := range sTyp.Fields.List {
50+
fieldName := field.Names[0].Name
51+
52+
if strings.Contains(strings.ToLower(fieldName), "phase") {
53+
pass.Reportf(field.Pos(),
54+
"field %s: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields",
55+
fieldName,
56+
)
57+
}
58+
}
59+
})
60+
61+
return nil, nil //nolint:nilnil
62+
}

pkg/analysis/nophase/analyzer_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package nophase_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/JoelSpeed/kal/pkg/analysis/nophase"
7+
"golang.org/x/tools/go/analysis/analysistest"
8+
)
9+
10+
func Test(t *testing.T) {
11+
testdata := analysistest.TestData()
12+
analysistest.RunWithSuggestedFixes(t, testdata, nophase.Analyzer, "a")
13+
}

pkg/analysis/nophase/doc.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
nophase provides a linter to ensure that structs do not contain a Phase field.
3+
4+
Phase fields are deprecated and conditions should be preferred. Avoid phase like enum
5+
fields.
6+
7+
The linter will flag any struct field containing the substring 'phase'. This means both
8+
Phase and FooPhase will be flagged.
9+
*/
10+
11+
package nophase

pkg/analysis/nophase/initializer.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package nophase
2+
3+
import (
4+
"github.com/JoelSpeed/kal/pkg/config"
5+
"golang.org/x/tools/go/analysis"
6+
)
7+
8+
// Initializer returns the AnalyzerInitializer for this
9+
// Analyzer so that it can be added to the registry.
10+
func Initializer() initializer {
11+
return initializer{}
12+
}
13+
14+
// intializer implements the AnalyzerInitializer interface.
15+
type initializer struct{}
16+
17+
// Name returns the name of the Analyzer.
18+
func (initializer) Name() string {
19+
return name
20+
}
21+
22+
// Init returns the intialized Analyzer.
23+
func (initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
24+
return Analyzer, nil
25+
}
26+
27+
// Default determines whether this Analyzer is on by default, or not.
28+
func (initializer) Default() bool {
29+
return true
30+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package a
2+
3+
type NoPhaseTestStruct struct {
4+
// +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+
7+
}
8+
9+
type NoSubPhaseTestStruct struct {
10+
// +optional
11+
FooPhase *string `json:"phase,omitempty"` // want "field FooPhase: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields"
12+
13+
}

pkg/analysis/registry.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/JoelSpeed/kal/pkg/analysis/commentstart"
77
"github.com/JoelSpeed/kal/pkg/analysis/jsontags"
8+
"github.com/JoelSpeed/kal/pkg/analysis/nophase"
89
"github.com/JoelSpeed/kal/pkg/analysis/optionalorrequired"
910
"github.com/JoelSpeed/kal/pkg/analysis/requiredfields"
1011
"github.com/JoelSpeed/kal/pkg/config"
@@ -53,6 +54,7 @@ func NewRegistry() Registry {
5354
jsontags.Initializer(),
5455
optionalorrequired.Initializer(),
5556
requiredfields.Initializer(),
57+
nophase.Initializer(),
5658
},
5759
}
5860
}

0 commit comments

Comments
 (0)