Skip to content

Commit

Permalink
all: improve test coverage, update dsl package to v0.3.1 (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
quasilyte authored Feb 11, 2021
1 parent 343aa8f commit 13cc12e
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 51 deletions.
45 changes: 42 additions & 3 deletions analyzer/testdata/src/filtertest/f1.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ func _() {
fileTest("f1.go") // want `YES`
}

func convertibleTo() {
type myInt2Array [2]int
typeTest([2]int{}, "convertible to ([2]int)") // want `YES`
typeTest(myInt2Array{}, "convertible to ([2]int)") // want `YES`
typeTest([3]int{}, "convertible to ([2]int)")

type myIntSlice2 [][]int
typeTest([][]int{{1}}, "convertible to [][]int") // want `YES`
typeTest(myIntSlice2(nil), "convertible to [][]int") // want `YES`
typeTest([]int{}, "convertible to [][]int")
}

func assignableTo() {
typeTest(map[*string]error{}, "assignable to map[*string]error") // want `YES`
typeTest(map[*string]int{}, "assignable to map[*string]error")

typeTest(0, "assignable to interface{}") // want `YES`
typeTest(5.6, "assignable to interface{}") // want `YES`
typeTest("", "assignable to interface{}") // want `YES`
}

func detectType() {
{
type withNamedTime struct {
Expand Down Expand Up @@ -157,9 +178,27 @@ func detectType() {

}

func detectPure(x int) {
pureTest(random()) // want `!pure`
pureTest(x * x) // want `pure`
func detectPure(x int, xs []int) {
var foo struct {
a int
}

xptr := &x

pureTest(random()) // want `!pure`
pureTest([]int{random()}) // want `!pure`

pureTest(*xptr) // want `pure`
pureTest(int(x)) // want `pure`
pureTest((*int)(&x)) // want `pure`
pureTest((func())(func() {})) // want `pure`
pureTest(foo.a) // want `pure`
pureTest(x * x) // want `pure`
pureTest((x * x)) // want `pure`
pureTest(+x) // want `pure`
pureTest(xs[0]) // want `pure`
pureTest(xs[x]) // want `pure`
pureTest([]int{0}) // want `pure`
}

func detectText(foo, bar int) {
Expand Down
16 changes: 16 additions & 0 deletions analyzer/testdata/src/filtertest/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,20 @@ func testRules(m dsl.Matcher) {
m.Match(`nodeTest($x, "Ident")`).Where(m["x"].Node.Is(`Ident`)).Report(`YES`)
m.Match(`nodeTest($x, "!Ident")`).Where(!m["x"].Node.Is(`Ident`)).Report(`YES`)
m.Match(`nodeTest($x, "IndexExpr")`).Where(m["x"].Node.Is(`IndexExpr`)).Report(`YES`)

m.Match(`typeTest($x, "convertible to ([2]int)")`).
Where(m["x"].Type.ConvertibleTo(`([2]int)`)).
Report(`YES`)

m.Match(`typeTest($x, "convertible to [][]int")`).
Where(m["x"].Type.ConvertibleTo(`[][]int`)).
Report(`YES`)

m.Match(`typeTest($x, "assignable to map[*string]error")`).
Where(m["x"].Type.AssignableTo(`map[*string]error`)).
Report(`YES`)

m.Match(`typeTest($x, "assignable to interface{}")`).
Where(m["x"].Type.AssignableTo(`interface{}`)).
Report(`YES`)
}
30 changes: 30 additions & 0 deletions analyzer/testdata/src/quasigo/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,37 @@ func ptrElemSmallerThanUintptr(ctx *dsl.VarFilterContext) bool {
return elemSize < uintptrSize
}

func isIntArray3(ctx *dsl.VarFilterContext) bool {
arr3 := types.NewArray(ctx.GetType(`int`), 3)
return types.Identical(ctx.Type, arr3)
}

func isIntArray(ctx *dsl.VarFilterContext) bool {
arr := types.AsArray(ctx.Type)
if arr != nil {
return types.Identical(ctx.GetType(`int`), arr.Elem())
}
return false
}

func isIntSlice(ctx *dsl.VarFilterContext) bool {
intSlice := types.NewSlice(ctx.GetType(`int`))
return types.Identical(ctx.Type, intSlice)
}

func testRules(m dsl.Matcher) {
m.Match(`test($x, "is [3]int")`).
Where(m["x"].Filter(isIntArray3)).
Report(`true`)

m.Match(`test($x, "is int array")`).
Where(m["x"].Filter(isIntArray)).
Report(`true`)

m.Match(`test($x, "is int slice")`).
Where(m["x"].Filter(isIntSlice)).
Report(`true`)

m.Match(`test($x, "underlying type is string")`).
Where(m["x"].Filter(stringUnderlying)).
Report(`true`)
Expand Down
14 changes: 14 additions & 0 deletions analyzer/testdata/src/quasigo/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ func f() {
var stringer fmt.Stringer
var err error

test([3]int{}, "is [3]int") // want `true`
test([2]int{}, "is [3]int")
test(0, "is [3]int")

test([1]int{}, "is int array") // want `true`
test([3]int{}, "is int array") // want `true`
test([3]string{}, "is int array")
test([]int{}, "is int array")
test(1, "is int array")

test([]int{}, "is int slice") // want `true`
test([2]int{}, "is int slice")
test([]string{}, "is int slice")

test("foo", "underlying type is string") // want `true`
test(myString("123"), "underlying type is string") // want `true`
test(0, "underlying type is string")
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.15

require (
github.com/google/go-cmp v0.5.2
github.com/quasilyte/go-ruleguard/dsl v0.3.0
github.com/quasilyte/go-ruleguard/dsl v0.3.1
github.com/quasilyte/go-ruleguard/rules v0.0.0-20210203162857-b223e0831f88
golang.org/x/tools v0.0.0-20201230224404-63754364767c
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/quasilyte/go-ruleguard/dsl v0.0.0-20210123094332-040a225e8dae h1:YFZ7
github.com/quasilyte/go-ruleguard/dsl v0.0.0-20210123094332-040a225e8dae/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.0 h1:+KRgVKXGdkhPCJdHD3rszyiuFHmMy/avI+FaLxVJ3gw=
github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.1 h1:CHGOKP2LDz35P49TjW4Bx4BCfFI6ZZU/8zcneECD0q4=
github.com/quasilyte/go-ruleguard/dsl v0.3.1/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1 h1:PX/E0GYUnSV8vwVfpOUEIBKnPG3KmYunmNOBlL+zDko=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20210203162857-b223e0831f88 h1:PeTrJiH/dSeruL/Z9Db39NRMwI/yoA3oHCdCkg+Wh8A=
Expand Down
32 changes: 6 additions & 26 deletions ruleguard/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,32 +78,12 @@ type engineState struct {
func newEngineState() *engineState {
env := quasigo.NewEnv()
state := &engineState{
env: env,
pkgCache: make(map[string]*types.Package),
typeByFQN: map[string]types.Type{
// Predeclared types.
`error`: types.Universe.Lookup("error").Type(),
`bool`: types.Typ[types.Bool],
`int`: types.Typ[types.Int],
`int8`: types.Typ[types.Int8],
`int16`: types.Typ[types.Int16],
`int32`: types.Typ[types.Int32],
`int64`: types.Typ[types.Int64],
`uint`: types.Typ[types.Uint],
`uint8`: types.Typ[types.Uint8],
`uint16`: types.Typ[types.Uint16],
`uint32`: types.Typ[types.Uint32],
`uint64`: types.Typ[types.Uint64],
`uintptr`: types.Typ[types.Uintptr],
`string`: types.Typ[types.String],
`float32`: types.Typ[types.Float32],
`float64`: types.Typ[types.Float64],
`complex64`: types.Typ[types.Complex64],
`complex128`: types.Typ[types.Complex128],
// Predeclared aliases (provided for convenience).
`byte`: types.Typ[types.Uint8],
`rune`: types.Typ[types.Int32],
},
env: env,
pkgCache: make(map[string]*types.Package),
typeByFQN: map[string]types.Type{},
}
for key, typ := range typeByName {
state.typeByFQN[key] = typ
}
initEnv(state, env)
return state
Expand Down
48 changes: 27 additions & 21 deletions ruleguard/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,30 @@ func findDependency(pkg *types.Package, path string) *types.Package {
return nil
}

var basicTypeByName = map[string]types.Type{
"bool": types.Typ[types.Bool],
"int": types.Typ[types.Int],
"int8": types.Typ[types.Int8],
"int16": types.Typ[types.Int16],
"int32": types.Typ[types.Int32],
"int64": types.Typ[types.Int64],
"uint": types.Typ[types.Uint],
"uint8": types.Typ[types.Uint8],
"uint16": types.Typ[types.Uint16],
"uint32": types.Typ[types.Uint32],
"uint64": types.Typ[types.Uint64],
"uintptr": types.Typ[types.Uintptr],
"float32": types.Typ[types.Float32],
"float64": types.Typ[types.Float64],
"complex64": types.Typ[types.Complex64],
"complex128": types.Typ[types.Complex128],
"string": types.Typ[types.String],
var typeByName = map[string]types.Type{
// Predeclared types.
`error`: types.Universe.Lookup("error").Type(),
`bool`: types.Typ[types.Bool],
`int`: types.Typ[types.Int],
`int8`: types.Typ[types.Int8],
`int16`: types.Typ[types.Int16],
`int32`: types.Typ[types.Int32],
`int64`: types.Typ[types.Int64],
`uint`: types.Typ[types.Uint],
`uint8`: types.Typ[types.Uint8],
`uint16`: types.Typ[types.Uint16],
`uint32`: types.Typ[types.Uint32],
`uint64`: types.Typ[types.Uint64],
`uintptr`: types.Typ[types.Uintptr],
`string`: types.Typ[types.String],
`float32`: types.Typ[types.Float32],
`float64`: types.Typ[types.Float64],
`complex64`: types.Typ[types.Complex64],
`complex128`: types.Typ[types.Complex128],

// Predeclared aliases (provided for convenience).
`byte`: types.Typ[types.Uint8],
`rune`: types.Typ[types.Int32],
}

func typeFromString(s string) (types.Type, error) {
Expand All @@ -57,9 +63,9 @@ func typeFromString(s string) (types.Type, error) {
func typeFromNode(e ast.Expr) types.Type {
switch e := e.(type) {
case *ast.Ident:
basic, ok := basicTypeByName[e.Name]
typ, ok := typeByName[e.Name]
if ok {
return basic
return typ
}

case *ast.ArrayType:
Expand All @@ -78,7 +84,7 @@ func typeFromNode(e ast.Expr) types.Type {
if err != nil {
return nil
}
types.NewArray(elem, int64(length))
return types.NewArray(elem, int64(length))

case *ast.MapType:
keyType := typeFromNode(e.Key)
Expand Down

0 comments on commit 13cc12e

Please sign in to comment.