Skip to content

Commit

Permalink
Merge pull request #14 from gostaticanalysis/add-result
Browse files Browse the repository at this point in the history
Add result
  • Loading branch information
tenntenn authored Sep 8, 2021
2 parents 4bcb6ff + 0e816e8 commit 477bc01
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 7 deletions.
44 changes: 37 additions & 7 deletions forcetypeassert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package forcetypeassert

import (
"go/ast"
"reflect"

"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
Expand All @@ -15,12 +16,35 @@ var Analyzer = &analysis.Analyzer{
Requires: []*analysis.Analyzer{
inspect.Analyzer,
},
ResultType: reflect.TypeOf((*Panicable)(nil)),
}

const Doc = "forcetypeassert is finds type assertions which did forcely such as below."
// Panicable stores panicable type assertions.
type Panicable struct {
m map[ast.Node]bool
nodes []ast.Node
}

// Check checks whether the node may occur panic or not.
func (p *Panicable) Check(n ast.Node) bool {
return p.m[n]
}

// Len is number of panicable nodes.
func (p *Panicable) Len() int {
return len(p.nodes)
}

// At returns the i-th panicable node.
func (p *Panicable) At(i int) ast.Node {
return p.nodes[i]
}

const Doc = "forcetypeassert is finds type assertions which did forcely"

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

nodeFilter := []ast.Node{
(*ast.AssignStmt)(nil),
Expand All @@ -34,11 +58,13 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
switch n := n.(type) {
case *ast.AssignStmt:
return checkAssignStmt(pass, n)
return checkAssignStmt(pass, result, n)
case *ast.ValueSpec:
return checkValueSpec(pass, n)
return checkValueSpec(pass, result, n)
case *ast.TypeAssertExpr:
if n.Type != nil {
result.m[n] = true
result.nodes = append(result.nodes, n)
pass.Reportf(n.Pos(), "type assertion must be checked")
}
return false
Expand All @@ -47,10 +73,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
return true
})

return nil, nil
return result, nil
}

func checkAssignStmt(pass *analysis.Pass, n *ast.AssignStmt) bool {
func checkAssignStmt(pass *analysis.Pass, result *Panicable, n *ast.AssignStmt) bool {
tae := findTypeAssertion(n.Rhs)
if tae == nil {
return true
Expand All @@ -62,6 +88,8 @@ func checkAssignStmt(pass *analysis.Pass, n *ast.AssignStmt) bool {
pass.Reportf(n.Pos(), "right hand must be only type assertion")
return false
case len(n.Lhs) != 2 && tae.Type != nil:
result.m[n] = true
result.nodes = append(result.nodes, n)
pass.Reportf(n.Pos(), "type assertion must be checked")
return false
case len(n.Lhs) == 2:
Expand All @@ -71,7 +99,7 @@ func checkAssignStmt(pass *analysis.Pass, n *ast.AssignStmt) bool {
return true
}

func checkValueSpec(pass *analysis.Pass, n *ast.ValueSpec) bool {
func checkValueSpec(pass *analysis.Pass, result *Panicable, n *ast.ValueSpec) bool {
tae := findTypeAssertion(n.Values)
if tae == nil {
return true
Expand All @@ -83,6 +111,8 @@ func checkValueSpec(pass *analysis.Pass, n *ast.ValueSpec) bool {
pass.Reportf(n.Pos(), "right hand must be only type assertion")
return false
case len(n.Names) != 2 && tae.Type != nil:
result.m[n] = true
result.nodes = append(result.nodes, n)
pass.Reportf(n.Pos(), "type assertion must be checked")
return false
case len(n.Names) == 2:
Expand Down
22 changes: 22 additions & 0 deletions forcetypeassert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,32 @@ import (
"testing"

"github.com/gostaticanalysis/forcetypeassert"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/analysistest"
)

func Test(t *testing.T) {
testdata := analysistest.TestData()
analysistest.Run(t, testdata, forcetypeassert.Analyzer, "a")
}

func TestResult(t *testing.T) {
testdata := analysistest.TestData()
a := &analysis.Analyzer{
Name: "test",
Doc: "test",
Requires: []*analysis.Analyzer{
forcetypeassert.Analyzer,
},
Run: func(pass *analysis.Pass) (interface{}, error) {
panicable, _ := pass.ResultOf[forcetypeassert.Analyzer].(*forcetypeassert.Panicable)
for i := 0; i < panicable.Len(); i++ {
n := panicable.At(i)
pass.Reportf(n.Pos(), "panicable")
}
return nil, nil
},
}

analysistest.Run(t, testdata, a, "b")
}
47 changes: 47 additions & 0 deletions testdata/src/b/b.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package b

import "fmt"

var _, _ = ((interface{})(nil)).(string) // OK
var _ = ((interface{})(nil)).(string) // want `panicable`
var _, _ = ((interface{})(nil)).(string), true // OK

func f() {
var i interface{} = "hello"

_ = i.(string) // want `panicable`

_, _ = i.(string), "foo" // OK

s, ok := i.(string) // ok
s, _ = i.(string) // ok
fmt.Println(s, ok)

if s, ok := i.(string); ok { // ok
println(s)
}

switch n := i.(type) { // ok
case string:
fmt.Println(n)
}
switch i.(type) { // ok
case string:
}

var _ = i.(string) // want `panicable`

var _ = *i.(*string) // want `panicable`

println(i.(string)) // want `panicable`
println(*i.(*string)) // want `panicable`

_ = func() int {
println(*i.(*string)) // want `panicable`
return 0
}()

func() {
println(*i.(*string)) // want `panicable`
}()
}

0 comments on commit 477bc01

Please sign in to comment.