-
Notifications
You must be signed in to change notification settings - Fork 20
/
analyzer.go
118 lines (96 loc) · 3.04 KB
/
analyzer.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package magic_numbers
import (
"flag"
"go/ast"
"strings"
"github.com/tommy-muehle/go-mnd/v2/checks"
"github.com/tommy-muehle/go-mnd/v2/config"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
const Doc = `magic number detector`
var Analyzer = &analysis.Analyzer{
Name: "mnd",
Doc: Doc,
Run: run,
Flags: options(),
Requires: []*analysis.Analyzer{inspect.Analyzer},
RunDespiteErrors: true,
}
type Checker interface {
NodeFilter() []ast.Node
Check(n ast.Node)
}
func options() flag.FlagSet {
options := flag.NewFlagSet("", flag.ExitOnError)
options.String("excludes", "", "deprecated: use ignored-files instead")
options.String("ignored-files", "", "comma separated list of file patterns to exclude from analysis")
options.String("ignored-functions", "", "comma separated list of function patterns to exclude from analysis")
options.String("ignored-numbers", "", "comma separated list of numbers to exclude from analysis")
options.String(
"checks",
checks.ArgumentCheck+","+
checks.CaseCheck+","+
checks.ConditionCheck+","+
checks.OperationCheck+","+
checks.ReturnCheck+","+
checks.AssignCheck,
"comma separated list of checks",
)
return *options
}
func run(pass *analysis.Pass) (interface{}, error) {
var ignoredFiles string
ignoredFiles = strings.Join(
[]string{
pass.Analyzer.Flags.Lookup("excludes").Value.String(), // is deprecated
pass.Analyzer.Flags.Lookup("ignored-files").Value.String(),
},
",",
)
if ignoredFiles == "," {
ignoredFiles = ""
}
conf := config.WithOptions(
config.WithCustomChecks(pass.Analyzer.Flags.Lookup("checks").Value.String()),
config.WithIgnoredFiles(ignoredFiles),
config.WithIgnoredFunctions(pass.Analyzer.Flags.Lookup("ignored-functions").Value.String()),
config.WithIgnoredNumbers(pass.Analyzer.Flags.Lookup("ignored-numbers").Value.String()),
)
var checker []Checker
if conf.IsCheckEnabled(checks.ArgumentCheck) {
checker = append(checker, checks.NewArgumentAnalyzer(pass, conf))
}
if conf.IsCheckEnabled(checks.CaseCheck) {
checker = append(checker, checks.NewCaseAnalyzer(pass, conf))
}
if conf.IsCheckEnabled(checks.ConditionCheck) {
checker = append(checker, checks.NewConditionAnalyzer(pass, conf))
}
if conf.IsCheckEnabled(checks.OperationCheck) {
checker = append(checker, checks.NewOperationAnalyzer(pass, conf))
}
if conf.IsCheckEnabled(checks.ReturnCheck) {
checker = append(checker, checks.NewReturnAnalyzer(pass, conf))
}
if conf.IsCheckEnabled(checks.AssignCheck) {
checker = append(checker, checks.NewAssignAnalyzer(pass, conf))
}
i := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
for _, c := range checker {
c := c
i.Preorder(c.NodeFilter(), func(node ast.Node) {
for _, exclude := range conf.IgnoredFiles {
if exclude.String() == "" {
continue
}
if exclude.MatchString(pass.Fset.Position(node.Pos()).Filename) {
return
}
}
c.Check(node)
})
}
return nil, nil
}