/
nested-structs.go
77 lines (65 loc) 路 1.47 KB
/
nested-structs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package rule
import (
"go/ast"
"github.com/mgechev/revive/lint"
)
// NestedStructs lints nested structs.
type NestedStructs struct{}
// Apply applies the rule to given file.
func (*NestedStructs) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
walker := &lintNestedStructs{
fileAST: file.AST,
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
}
ast.Walk(walker, file.AST)
return failures
}
// Name returns the rule name.
func (*NestedStructs) Name() string {
return "nested-structs"
}
type lintNestedStructs struct {
fileAST *ast.File
onFailure func(lint.Failure)
}
func (l *lintNestedStructs) Visit(n ast.Node) ast.Visitor {
switch v := n.(type) {
case *ast.TypeSpec:
_, isInterface := v.Type.(*ast.InterfaceType)
if isInterface {
return nil // do not analyze interface declarations
}
case *ast.FuncDecl:
if v.Body != nil {
ast.Walk(l, v.Body)
}
return nil
case *ast.Field:
_, isChannelField := v.Type.(*ast.ChanType)
if isChannelField {
return nil
}
filter := func(n ast.Node) bool {
switch n.(type) {
case *ast.StructType:
return true
default:
return false
}
}
structs := pick(v, filter, nil)
for _, s := range structs {
l.onFailure(lint.Failure{
Failure: "no nested structs are allowed",
Category: "style",
Node: s,
Confidence: 1,
})
}
return nil // no need to visit (again) the field
}
return l
}