From 4bff5cbccc0a49e127aba272d65392fabb6071f1 Mon Sep 17 00:00:00 2001 From: "Iskander (Alex) Sharipov" Date: Sun, 28 Aug 2022 19:37:47 +0300 Subject: [PATCH] internal/xtypes: handle new Union and TypeParam types (#399) Fixes #398 --- .github/workflows/go.yml | 4 ++-- Makefile | 2 +- analyzer/analyzer_test.go | 1 + analyzer/testdata/src/generics/rules.go | 12 ++++++++++++ analyzer/testdata/src/generics/target.go | 9 +++++++++ go.mod | 1 + go.sum | 2 ++ internal/xtypes/xtypes.go | 16 +++++++++++++--- 8 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 analyzer/testdata/src/generics/rules.go create mode 100644 analyzer/testdata/src/generics/target.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 5bbb4ca6..6d931d8e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -8,9 +8,9 @@ "runs-on": "ubuntu-latest", steps: [ { - name: "Set up Go 1.16", + name: "Set up Go 1.18", uses: "actions/setup-go@v1", - "with": {"go-version": 1.16}, + "with": {"go-version": 1.18}, id: "go", }, {name: "Check out code into the Go module directory", uses: "actions/checkout@v1"}, diff --git a/Makefile b/Makefile index 6c2dd9ab..3f610b09 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ test-release: @echo "everything is OK" lint: - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH_DIR)/bin v1.43.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH_DIR)/bin v1.49.0 $(GOPATH_DIR)/bin/golangci-lint run ./... go build -o go-ruleguard ./cmd/ruleguard ./go-ruleguard -debug-imports -rules rules.go ./... diff --git a/analyzer/analyzer_test.go b/analyzer/analyzer_test.go index cfbc9907..e218a341 100644 --- a/analyzer/analyzer_test.go +++ b/analyzer/analyzer_test.go @@ -48,6 +48,7 @@ var tests = []struct { {name: "localfunc"}, {name: "goversion", flags: map[string]string{"go": "1.16"}}, {name: "imports"}, + {name: "generics"}, {name: "quickfix", quickfixes: true}, } diff --git a/analyzer/testdata/src/generics/rules.go b/analyzer/testdata/src/generics/rules.go new file mode 100644 index 00000000..8ddba378 --- /dev/null +++ b/analyzer/testdata/src/generics/rules.go @@ -0,0 +1,12 @@ +//go:build ignore +// +build ignore + +package gorules + +import "github.com/quasilyte/go-ruleguard/dsl" + +func externalErrorReassign(m dsl.Matcher) { + m.Match(`$pkg.$err = $x`). + Where(m["err"].Type.Is(`error`) && m["pkg"].Object.Is(`PkgName`)). + Report(`suspicious reassigment of error from another package`) +} diff --git a/analyzer/testdata/src/generics/target.go b/analyzer/testdata/src/generics/target.go new file mode 100644 index 00000000..8ac7d259 --- /dev/null +++ b/analyzer/testdata/src/generics/target.go @@ -0,0 +1,9 @@ +package main + +type myType[T any] struct { + value T +} + +func (m *myType[T]) set(v T) { + m.value = v +} diff --git a/go.mod b/go.mod index ad346f52..bfc006eb 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 + golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 golang.org/x/tools v0.1.12 ) diff --git a/go.sum b/go.sum index 6df5248e..a2d93fa2 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 h1:Ic/qN6TEifvObMGQy72k0n1LlJr7DjWWEi+MOsDOiSk= +golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= diff --git a/internal/xtypes/xtypes.go b/internal/xtypes/xtypes.go index 028a5f14..4c5c2a2a 100644 --- a/internal/xtypes/xtypes.go +++ b/internal/xtypes/xtypes.go @@ -2,6 +2,8 @@ package xtypes import ( "go/types" + + "golang.org/x/exp/typeparams" ) // Implements reports whether type v implements iface. @@ -63,9 +65,6 @@ func typeIdentical(x, y types.Type, p *ifacePair) bool { } switch x := x.(type) { - case nil: - return false - case *types.Basic: // Basic types are singletons except for the rune and byte // aliases, thus we cannot solely rely on the x == y check @@ -142,6 +141,11 @@ func typeIdentical(x, y types.Type, p *ifacePair) bool { typeIdentical(x.Results(), y.Results(), p) } + case *typeparams.Union: + // TODO(quasilyte): do we want to match generic union types too? + // It would require copying a lot of code from the go/types. + return false + case *types.Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from @@ -214,6 +218,12 @@ func typeIdentical(x, y types.Type, p *ifacePair) bool { } return sameID(x.Obj(), y.Obj().Pkg(), y.Obj().Name()) + case *typeparams.TypeParam: + // nothing to do (x and y being equal is caught in the very beginning of this function) + + case nil: + // avoid a crash in case of nil type + default: panic("unreachable") }