Skip to content

Commit 477bc01

Browse files
authored
Merge pull request #14 from gostaticanalysis/add-result
Add result
2 parents 4bcb6ff + 0e816e8 commit 477bc01

File tree

3 files changed

+106
-7
lines changed

3 files changed

+106
-7
lines changed

forcetypeassert.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package forcetypeassert
22

33
import (
44
"go/ast"
5+
"reflect"
56

67
"golang.org/x/tools/go/analysis"
78
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -15,12 +16,35 @@ var Analyzer = &analysis.Analyzer{
1516
Requires: []*analysis.Analyzer{
1617
inspect.Analyzer,
1718
},
19+
ResultType: reflect.TypeOf((*Panicable)(nil)),
1820
}
1921

20-
const Doc = "forcetypeassert is finds type assertions which did forcely such as below."
22+
// Panicable stores panicable type assertions.
23+
type Panicable struct {
24+
m map[ast.Node]bool
25+
nodes []ast.Node
26+
}
27+
28+
// Check checks whether the node may occur panic or not.
29+
func (p *Panicable) Check(n ast.Node) bool {
30+
return p.m[n]
31+
}
32+
33+
// Len is number of panicable nodes.
34+
func (p *Panicable) Len() int {
35+
return len(p.nodes)
36+
}
37+
38+
// At returns the i-th panicable node.
39+
func (p *Panicable) At(i int) ast.Node {
40+
return p.nodes[i]
41+
}
42+
43+
const Doc = "forcetypeassert is finds type assertions which did forcely"
2144

2245
func run(pass *analysis.Pass) (interface{}, error) {
23-
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
46+
inspect, _ := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
47+
result := &Panicable{m: make(map[ast.Node]bool)}
2448

2549
nodeFilter := []ast.Node{
2650
(*ast.AssignStmt)(nil),
@@ -34,11 +58,13 @@ func run(pass *analysis.Pass) (interface{}, error) {
3458
}
3559
switch n := n.(type) {
3660
case *ast.AssignStmt:
37-
return checkAssignStmt(pass, n)
61+
return checkAssignStmt(pass, result, n)
3862
case *ast.ValueSpec:
39-
return checkValueSpec(pass, n)
63+
return checkValueSpec(pass, result, n)
4064
case *ast.TypeAssertExpr:
4165
if n.Type != nil {
66+
result.m[n] = true
67+
result.nodes = append(result.nodes, n)
4268
pass.Reportf(n.Pos(), "type assertion must be checked")
4369
}
4470
return false
@@ -47,10 +73,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
4773
return true
4874
})
4975

50-
return nil, nil
76+
return result, nil
5177
}
5278

53-
func checkAssignStmt(pass *analysis.Pass, n *ast.AssignStmt) bool {
79+
func checkAssignStmt(pass *analysis.Pass, result *Panicable, n *ast.AssignStmt) bool {
5480
tae := findTypeAssertion(n.Rhs)
5581
if tae == nil {
5682
return true
@@ -62,6 +88,8 @@ func checkAssignStmt(pass *analysis.Pass, n *ast.AssignStmt) bool {
6288
pass.Reportf(n.Pos(), "right hand must be only type assertion")
6389
return false
6490
case len(n.Lhs) != 2 && tae.Type != nil:
91+
result.m[n] = true
92+
result.nodes = append(result.nodes, n)
6593
pass.Reportf(n.Pos(), "type assertion must be checked")
6694
return false
6795
case len(n.Lhs) == 2:
@@ -71,7 +99,7 @@ func checkAssignStmt(pass *analysis.Pass, n *ast.AssignStmt) bool {
7199
return true
72100
}
73101

74-
func checkValueSpec(pass *analysis.Pass, n *ast.ValueSpec) bool {
102+
func checkValueSpec(pass *analysis.Pass, result *Panicable, n *ast.ValueSpec) bool {
75103
tae := findTypeAssertion(n.Values)
76104
if tae == nil {
77105
return true
@@ -83,6 +111,8 @@ func checkValueSpec(pass *analysis.Pass, n *ast.ValueSpec) bool {
83111
pass.Reportf(n.Pos(), "right hand must be only type assertion")
84112
return false
85113
case len(n.Names) != 2 && tae.Type != nil:
114+
result.m[n] = true
115+
result.nodes = append(result.nodes, n)
86116
pass.Reportf(n.Pos(), "type assertion must be checked")
87117
return false
88118
case len(n.Names) == 2:

forcetypeassert_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,32 @@ import (
44
"testing"
55

66
"github.com/gostaticanalysis/forcetypeassert"
7+
"golang.org/x/tools/go/analysis"
78
"golang.org/x/tools/go/analysis/analysistest"
89
)
910

1011
func Test(t *testing.T) {
1112
testdata := analysistest.TestData()
1213
analysistest.Run(t, testdata, forcetypeassert.Analyzer, "a")
1314
}
15+
16+
func TestResult(t *testing.T) {
17+
testdata := analysistest.TestData()
18+
a := &analysis.Analyzer{
19+
Name: "test",
20+
Doc: "test",
21+
Requires: []*analysis.Analyzer{
22+
forcetypeassert.Analyzer,
23+
},
24+
Run: func(pass *analysis.Pass) (interface{}, error) {
25+
panicable, _ := pass.ResultOf[forcetypeassert.Analyzer].(*forcetypeassert.Panicable)
26+
for i := 0; i < panicable.Len(); i++ {
27+
n := panicable.At(i)
28+
pass.Reportf(n.Pos(), "panicable")
29+
}
30+
return nil, nil
31+
},
32+
}
33+
34+
analysistest.Run(t, testdata, a, "b")
35+
}

testdata/src/b/b.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package b
2+
3+
import "fmt"
4+
5+
var _, _ = ((interface{})(nil)).(string) // OK
6+
var _ = ((interface{})(nil)).(string) // want `panicable`
7+
var _, _ = ((interface{})(nil)).(string), true // OK
8+
9+
func f() {
10+
var i interface{} = "hello"
11+
12+
_ = i.(string) // want `panicable`
13+
14+
_, _ = i.(string), "foo" // OK
15+
16+
s, ok := i.(string) // ok
17+
s, _ = i.(string) // ok
18+
fmt.Println(s, ok)
19+
20+
if s, ok := i.(string); ok { // ok
21+
println(s)
22+
}
23+
24+
switch n := i.(type) { // ok
25+
case string:
26+
fmt.Println(n)
27+
}
28+
switch i.(type) { // ok
29+
case string:
30+
}
31+
32+
var _ = i.(string) // want `panicable`
33+
34+
var _ = *i.(*string) // want `panicable`
35+
36+
println(i.(string)) // want `panicable`
37+
println(*i.(*string)) // want `panicable`
38+
39+
_ = func() int {
40+
println(*i.(*string)) // want `panicable`
41+
return 0
42+
}()
43+
44+
func() {
45+
println(*i.(*string)) // want `panicable`
46+
}()
47+
}

0 commit comments

Comments
 (0)