Skip to content

Commit b3bcc7c

Browse files
committed
go/analysis/passes/initflagparse: add check for avoid flag.Parse at init
1 parent 61798d6 commit b3bcc7c

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2014 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package initflagparse defines an Analyzer that checks for invalid
6+
// conversions of uintptr to unsafe.Pointer.
7+
package initflagparse
8+
9+
import (
10+
"go/ast"
11+
12+
"golang.org/x/tools/go/analysis"
13+
"golang.org/x/tools/go/analysis/passes/inspect"
14+
"golang.org/x/tools/go/ast/inspector"
15+
)
16+
17+
const Doc = `check for usage of flag.Parse during modules init
18+
19+
The initflagparse analyzer reports incorrect uses of flag.Parse during
20+
the init of the modules.`
21+
22+
var Analyzer = &analysis.Analyzer{
23+
Name: "initflagparse",
24+
Doc: Doc,
25+
Requires: []*analysis.Analyzer{inspect.Analyzer},
26+
Run: run,
27+
}
28+
29+
func run(pass *analysis.Pass) (interface{}, error) {
30+
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
31+
32+
nodeFilter := []ast.Node{
33+
(*ast.FuncDecl)(nil),
34+
}
35+
inspect.Preorder(nodeFilter, func(n ast.Node) {
36+
x := n.(*ast.FuncDecl)
37+
if x.Recv == nil && x.Name.Name == "init" {
38+
checkForFlagParse(pass, x)
39+
}
40+
})
41+
return nil, nil
42+
}
43+
44+
// checkForFlagParse check the code inside a node and fail if it finds a
45+
// flag.Parse call
46+
func checkForFlagParse(pass *analysis.Pass, x ast.Node) {
47+
ast.Inspect(x, func(n ast.Node) bool {
48+
x, ok := n.(*ast.CallExpr)
49+
if !ok {
50+
return true
51+
}
52+
fun, ok := x.Fun.(*ast.SelectorExpr)
53+
if !ok {
54+
return true
55+
}
56+
57+
module, ok := fun.X.(*ast.Ident)
58+
if !ok {
59+
return true
60+
}
61+
62+
if ok && module.Name == "flag" && fun.Sel.Name == "Parse" {
63+
pass.ReportRangef(x, "flag.Parse usage during module initialization")
64+
return false
65+
}
66+
return true
67+
})
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package initflagparse_test
6+
7+
import (
8+
"testing"
9+
10+
"golang.org/x/tools/go/analysis/analysistest"
11+
"golang.org/x/tools/go/analysis/passes/initflagparse"
12+
)
13+
14+
func Test(t *testing.T) {
15+
testdata := analysistest.TestData()
16+
analysistest.Run(t, testdata, initflagparse.Analyzer, "a")
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package a
6+
7+
import "flag"
8+
9+
func init() {
10+
flag.Parse() // want `flag.Parse usage during module initialization`
11+
}
12+
13+
type Test struct{}
14+
15+
func (_ *Test) init() {
16+
flag.Parse()
17+
}
18+
19+
func main() {
20+
flag.Parse()
21+
}

go/analysis/unitchecker/main.go

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"golang.org/x/tools/go/analysis/passes/copylock"
2525
"golang.org/x/tools/go/analysis/passes/errorsas"
2626
"golang.org/x/tools/go/analysis/passes/httpresponse"
27+
"golang.org/x/tools/go/analysis/passes/initflagparse"
2728
"golang.org/x/tools/go/analysis/passes/loopclosure"
2829
"golang.org/x/tools/go/analysis/passes/lostcancel"
2930
"golang.org/x/tools/go/analysis/passes/nilfunc"
@@ -62,5 +63,6 @@ func main() {
6263
unreachable.Analyzer,
6364
unsafeptr.Analyzer,
6465
unusedresult.Analyzer,
66+
initflagparse.Analyzer,
6567
)
6668
}

0 commit comments

Comments
 (0)