Skip to content

Commit c57998e

Browse files
authored
ruleguard: implement Type.IdenticalTo method (#365)
1 parent fdceb55 commit c57998e

File tree

9 files changed

+105
-23
lines changed

9 files changed

+105
-23
lines changed

analyzer/testdata/src/filtertest/f1.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,47 @@ func detectConvertibleTo(x int, xs []int) {
674674
typeTest("", xs[:], "variadic convertible to string") // want `false`
675675
}
676676

677+
func detectIdenticalTypes() {
678+
{
679+
typeTest(1, 1, "identical types") // want `true`
680+
typeTest("a", "b", "identical types") // want `true`
681+
typeTest([]int{}, []int{1}, "identical types") // want `true`
682+
typeTest([]int32{}, []int32{1}, "identical types") // want `true`
683+
typeTest([]int32{}, []rune{}, "identical types") // want `true`
684+
typeTest([4]int{}, [4]int{}, "identical types") // want `true`
685+
686+
typeTest(1, 1.5, "identical types")
687+
typeTest("ok", 1.5, "identical types")
688+
typeTest([]int{}, []int32{1}, "identical types")
689+
typeTest([4]int{}, [3]int{}, "identical types")
690+
691+
type point struct {
692+
x, y float64
693+
}
694+
type myString string
695+
var s string
696+
var myStr myString
697+
var pt point
698+
ppt := &point{}
699+
var eface interface{}
700+
var i int
701+
typeTest([]point{}, []point{}, "identical types") // want `true`
702+
typeTest(s, s, "identical types") // want `true`
703+
typeTest(myStr, myStr, "identical types") // want `true`
704+
typeTest(pt, pt, "identical types") // want `true`
705+
typeTest(&pt, ppt, "identical types") // want `true`
706+
typeTest(eface, eface, "identical types") // want `true`
707+
typeTest([]point{}, [1]point{}, "identical types")
708+
typeTest(myStr, s, "identical types")
709+
typeTest(s, myStr, "identical types")
710+
typeTest(ppt, pt, "identical types")
711+
typeTest(eface, pt, "identical types")
712+
typeTest(eface, ppt, "identical types")
713+
typeTest(i, eface, "identical types")
714+
typeTest(eface, i, "identical types")
715+
}
716+
}
717+
677718
func detectAssignableTo(x int, xs []int) {
678719
type newString string
679720
type stringAlias = string

analyzer/testdata/src/filtertest/rules.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,8 @@ func testRules(m dsl.Matcher) {
259259
m.Match(`typeTest($x, "is func")`).
260260
Where(m["x"].Type.Is(`func ($*_) $*_`)).
261261
Report(`true`)
262+
263+
m.Match(`typeTest($x, $y, "identical types")`).
264+
Where(m["x"].Type.IdenticalTo(m["y"])).
265+
Report(`true`)
262266
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.17
55
require (
66
github.com/go-toolsmith/astcopy v1.0.0
77
github.com/google/go-cmp v0.5.6
8-
github.com/quasilyte/go-ruleguard/dsl v0.3.14
8+
github.com/quasilyte/go-ruleguard/dsl v0.3.15
99
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71
1010
github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5
1111
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ github.com/quasilyte/go-ruleguard/dsl v0.3.13 h1:WmtzUkp28TMarzfBCogPf7plyI/2gsN
1414
github.com/quasilyte/go-ruleguard/dsl v0.3.13/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
1515
github.com/quasilyte/go-ruleguard/dsl v0.3.14 h1:diesHrFHZ6rxuFltuwiW7NRQaqUIypuSSmUulRCNuqM=
1616
github.com/quasilyte/go-ruleguard/dsl v0.3.14/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
17+
github.com/quasilyte/go-ruleguard/dsl v0.3.15 h1:rClYn6lk8wUV5kXnQG4JVsRQjZhSetaNtwml5wkFp5g=
18+
github.com/quasilyte/go-ruleguard/dsl v0.3.15/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
1719
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
1820
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CNooiryw5aisadVfzneSZPswRWvnVW8hF1bS/vo8ReI=
1921
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=

ruleguard/filters.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,17 @@ func makeTypeOfKindFilter(src, varname string, underlying bool, kind types.Basic
278278
}
279279
}
280280

281+
func makeTypesIdenticalFilter(src, lhsVarname, rhsVarname string) filterFunc {
282+
return func(params *filterParams) matchFilterResult {
283+
lhsType := params.typeofNode(params.subNode(lhsVarname))
284+
rhsType := params.typeofNode(params.subNode(rhsVarname))
285+
if xtypes.Identical(lhsType, rhsType) {
286+
return filterSuccess
287+
}
288+
return filterFailure(src)
289+
}
290+
}
291+
281292
func makeTypeIsFilter(src, varname string, underlying bool, pat *typematch.Pattern) filterFunc {
282293
if underlying {
283294
return func(params *filterParams) matchFilterResult {

ruleguard/ir/filter_op.gen.go

Lines changed: 28 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ruleguard/ir/gen_filter_op.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func main() {
5353
{name: "VarNodeIs", comment: "m[$Value].Node.Is($Args[0])", valueType: "string", flags: flagHasVar},
5454
{name: "VarObjectIs", comment: "m[$Value].Object.Is($Args[0])", valueType: "string", flags: flagHasVar},
5555
{name: "VarTypeIs", comment: "m[$Value].Type.Is($Args[0])", valueType: "string", flags: flagHasVar},
56+
{name: "VarTypeIdenticalTo", comment: "m[$Value].Type.IdenticalTo($Args[0])", valueType: "string", flags: flagHasVar},
5657
{name: "VarTypeUnderlyingIs", comment: "m[$Value].Type.Underlying().Is($Args[0])", valueType: "string", flags: flagHasVar},
5758
{name: "VarTypeOfKind", comment: "m[$Value].Type.OfKind($Args[0])", valueType: "string", flags: flagHasVar},
5859
{name: "VarTypeUnderlyingOfKind", comment: "m[$Value].Type.Underlying().OfKind($Args[0])", valueType: "string", flags: flagHasVar},

ruleguard/ir_loader.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,11 @@ func (l *irLoader) newFilter(filter ir.FilterExpr, info *filterInfo) (matchFilte
622622
result.fn = makeTypeOfKindFilter(result.src, filter.Value.(string), underlying, kind)
623623
}
624624

625+
case ir.FilterVarTypeIdenticalToOp:
626+
lhsVarname := filter.Value.(string)
627+
rhsVarname := filter.Args[0].Value.(string)
628+
result.fn = makeTypesIdenticalFilter(result.src, lhsVarname, rhsVarname)
629+
625630
case ir.FilterVarTypeIsOp, ir.FilterVarTypeUnderlyingIsOp:
626631
typeString := l.unwrapStringExpr(filter.Args[0])
627632
if typeString == "" {

ruleguard/irconv/irconv.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,18 @@ func (conv *converter) convertFilterExprImpl(e ast.Expr) ir.FilterExpr {
671671
},
672672
}
673673

674+
case "Type.IdenticalTo":
675+
// TODO: reuse the code with parsing At() args?
676+
index, ok := e.Args[0].(*ast.IndexExpr)
677+
if !ok {
678+
panic(conv.errorf(e.Args[0], "expected %s[`varname`] expression", conv.group.MatcherName))
679+
}
680+
rhsVarname := conv.parseStringArg(index.Index)
681+
args := []ir.FilterExpr{
682+
{Op: ir.FilterStringOp, Value: rhsVarname},
683+
}
684+
return ir.FilterExpr{Op: ir.FilterVarTypeIdenticalToOp, Value: op.varName, Args: args}
685+
674686
case "Filter":
675687
funcName, ok := e.Args[0].(*ast.Ident)
676688
if !ok {

0 commit comments

Comments
 (0)