aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/nishanths
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-02-22 20:37:25 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-02-22 21:02:12 +0100
commitfcc6d71be2c3ce7d9305c04fc2e87af554571bac (patch)
treeb01dbb3d1e2988e28ea158d2d543d603ec0b9569 /vendor/github.com/nishanths
parent8f23c528ad5a943b9ffec5dcaf332fd0f614006e (diff)
go.mod: update golangci-lint to v1.37
Diffstat (limited to 'vendor/github.com/nishanths')
-rw-r--r--vendor/github.com/nishanths/exhaustive/.gitignore2
-rw-r--r--vendor/github.com/nishanths/exhaustive/.travis.yml12
-rw-r--r--vendor/github.com/nishanths/exhaustive/README.md16
-rw-r--r--vendor/github.com/nishanths/exhaustive/enum.go65
-rw-r--r--vendor/github.com/nishanths/exhaustive/exhaustive.go64
-rw-r--r--vendor/github.com/nishanths/exhaustive/generated.go34
-rw-r--r--vendor/github.com/nishanths/exhaustive/go.mod2
-rw-r--r--vendor/github.com/nishanths/exhaustive/go.sum17
-rw-r--r--vendor/github.com/nishanths/exhaustive/map.go158
-rw-r--r--vendor/github.com/nishanths/exhaustive/switch.go96
-rw-r--r--vendor/github.com/nishanths/predeclared/LICENSE29
-rw-r--r--vendor/github.com/nishanths/predeclared/passes/predeclared/go18.go9
-rw-r--r--vendor/github.com/nishanths/predeclared/passes/predeclared/pre_go18.go53
-rw-r--r--vendor/github.com/nishanths/predeclared/passes/predeclared/predeclared.go202
14 files changed, 542 insertions, 217 deletions
diff --git a/vendor/github.com/nishanths/exhaustive/.gitignore b/vendor/github.com/nishanths/exhaustive/.gitignore
index a724b56a9..24bde5301 100644
--- a/vendor/github.com/nishanths/exhaustive/.gitignore
+++ b/vendor/github.com/nishanths/exhaustive/.gitignore
@@ -1,4 +1,6 @@
.DS_Store
+*.swp
+tags
# binary
cmd/exhaustive/exhaustive
diff --git a/vendor/github.com/nishanths/exhaustive/.travis.yml b/vendor/github.com/nishanths/exhaustive/.travis.yml
new file mode 100644
index 000000000..bd342f558
--- /dev/null
+++ b/vendor/github.com/nishanths/exhaustive/.travis.yml
@@ -0,0 +1,12 @@
+language: go
+
+go:
+ - 1.x
+ - master
+
+# Only clone the most recent commit.
+git:
+ depth: 1
+
+notifications:
+ email: false
diff --git a/vendor/github.com/nishanths/exhaustive/README.md b/vendor/github.com/nishanths/exhaustive/README.md
index ecc76c7c5..90afc87fe 100644
--- a/vendor/github.com/nishanths/exhaustive/README.md
+++ b/vendor/github.com/nishanths/exhaustive/README.md
@@ -2,6 +2,8 @@
[![Godoc](https://godoc.org/github.com/nishanths/exhaustive?status.svg)](https://godoc.org/github.com/nishanths/exhaustive)
+[![Build Status](https://travis-ci.org/nishanths/exhaustive.svg?branch=master)](https://travis-ci.org/nishanths/exhaustive)
+
The `exhaustive` package and command line program can be used to detect
enum switch statements that are not exhaustive.
@@ -29,6 +31,8 @@ The command line usage is:
Usage: exhaustive [-flags] [packages...]
Flags:
+ -check-generated
+ check switch statements in generated files also
-default-signifies-exhaustive
indicates that switch statements are to be considered exhaustive if a 'default' case
is present, even if all enum members aren't listed in the switch (default false)
@@ -36,8 +40,8 @@ Flags:
apply all suggested fixes (default false)
Examples:
- exhaustive code.org/proj/...
- exhaustive -fix example.org/foo/pkg example.org/foo/bar
+ exhaustive github.com/foo/bar/...
+ exhaustive github.com/a/b github.com/x/y
```
## Example
@@ -65,11 +69,11 @@ import "token"
func processToken(t token.Token) {
switch t {
case token.Add:
- // ...
+ ...
case token.Subtract:
- // ...
+ ...
case token.Multiply:
- // ...
+ ...
}
}
```
@@ -80,6 +84,8 @@ Running the `exhaustive` command will print:
calc.go:6:2: missing cases in switch of type token.Token: Quotient, Remainder
```
+Enums can also be defined using explicit constant values instead of `iota`.
+
## License
BSD 2-Clause
diff --git a/vendor/github.com/nishanths/exhaustive/enum.go b/vendor/github.com/nishanths/exhaustive/enum.go
index 98b5656b6..ed0df642b 100644
--- a/vendor/github.com/nishanths/exhaustive/enum.go
+++ b/vendor/github.com/nishanths/exhaustive/enum.go
@@ -8,7 +8,42 @@ import (
"golang.org/x/tools/go/analysis"
)
-type enums map[string][]string // enum type name -> enum member names
+type enums map[string]*enumMembers // enum type name -> enum members
+
+type enumMembers struct {
+ // Names in the order encountered in the AST.
+ OrderedNames []string
+
+ // Maps name -> (constant.Value).ExactString().
+ // If a name is missing in the map, it means that it does not have a
+ // corresponding constant.Value defined in the AST.
+ NameToValue map[string]string
+
+ // Maps (constant.Value).ExactString() -> names.
+ // Names that don't have a constant.Value defined in the AST (e.g., some
+ // iota constants) will not have a corresponding entry in this map.
+ ValueToNames map[string][]string
+}
+
+func (em *enumMembers) add(name string, constVal *string) {
+ em.OrderedNames = append(em.OrderedNames, name)
+
+ if constVal != nil {
+ if em.NameToValue == nil {
+ em.NameToValue = make(map[string]string)
+ }
+ em.NameToValue[name] = *constVal
+
+ if em.ValueToNames == nil {
+ em.ValueToNames = make(map[string][]string)
+ }
+ em.ValueToNames[*constVal] = append(em.ValueToNames[*constVal], name)
+ }
+}
+
+func (em *enumMembers) numMembers() int {
+ return len(em.OrderedNames)
+}
func findEnums(pass *analysis.Pass) enums {
pkgEnums := make(enums)
@@ -39,13 +74,14 @@ func findEnums(pass *analysis.Pass) enums {
if !ok {
continue
}
+
switch i := basic.Info(); {
case i&types.IsInteger != 0:
- pkgEnums[named.Obj().Name()] = nil
+ pkgEnums[named.Obj().Name()] = &enumMembers{}
case i&types.IsFloat != 0:
- pkgEnums[named.Obj().Name()] = nil
+ pkgEnums[named.Obj().Name()] = &enumMembers{}
case i&types.IsString != 0:
- pkgEnums[named.Obj().Name()] = nil
+ pkgEnums[named.Obj().Name()] = &enumMembers{}
}
}
}
@@ -64,22 +100,33 @@ func findEnums(pass *analysis.Pass) enums {
for _, s := range gen.Specs {
// Must be ValueSpec since we've filtered on token.CONST, token.VAR.
v := s.(*ast.ValueSpec)
- for _, name := range v.Names {
+ for i, name := range v.Names {
obj := pass.TypesInfo.Defs[name]
if obj == nil {
continue
}
+
named, ok := obj.Type().(*types.Named)
if !ok {
continue
}
- members, ok := pkgEnums[named.Obj().Name()]
+ // Get the constant.Value representation, if any.
+ var constVal *string
+ if len(v.Values) > i {
+ value := v.Values[i]
+ if con, ok := pass.TypesInfo.Types[value]; ok && con.Value != nil {
+ str := con.Value.ExactString() // temp var to be able to take address
+ constVal = &str
+ }
+ }
+
+ em, ok := pkgEnums[named.Obj().Name()]
if !ok {
continue
}
- members = append(members, obj.Name())
- pkgEnums[named.Obj().Name()] = members
+ em.add(obj.Name(), constVal)
+ pkgEnums[named.Obj().Name()] = em
}
}
}
@@ -90,7 +137,7 @@ func findEnums(pass *analysis.Pass) enums {
// the existence of members. (The type may just be a named type,
// for instance.)
for k, v := range pkgEnums {
- if len(v) == 0 {
+ if v.numMembers() == 0 {
delete(pkgEnums, k)
}
}
diff --git a/vendor/github.com/nishanths/exhaustive/exhaustive.go b/vendor/github.com/nishanths/exhaustive/exhaustive.go
index ef869f268..73815a626 100644
--- a/vendor/github.com/nishanths/exhaustive/exhaustive.go
+++ b/vendor/github.com/nishanths/exhaustive/exhaustive.go
@@ -1,26 +1,27 @@
-// Package exhaustive provides an analyzer that helps ensure enum switch statements
-// are exhaustive. The analyzer also provides fixes to make the offending switch
-// statements exhaustive (see "Fixes" section).
+// Package exhaustive provides an analyzer that checks exhaustiveness of enum
+// switch statements. The analyzer also provides fixes to make the offending
+// switch statements exhaustive (see "Fixes" section).
//
// See "cmd/exhaustive" subpackage for the related command line program.
//
// Definition of enum
//
-// The language spec does not provide an explicit definition for enums.
+// The Go language spec does not provide an explicit definition for enums.
// For the purpose of this program, an enum type is a package-level named type
// whose underlying type is an integer (includes byte and rune), a float, or
// a string type. An enum type must have associated with it one or more
// package-level variables of the named type in the package. These variables
// constitute the enum's members.
//
-// In the code snippet below, Biome is an enum type with 3 members.
+// In the code snippet below, Biome is an enum type with 3 members. (You may
+// also use iota instead of explicitly specifying values.)
//
// type Biome int
//
// const (
-// Tundra Biome = iota
-// Savanna
-// Desert
+// Tundra Biome = 1
+// Savanna Biome = 2
+// Desert Biome = 3
// )
//
// Switch statement exhaustiveness
@@ -36,11 +37,15 @@
// Flags
//
// The analyzer accepts a boolean flag: -default-signifies-exhaustive.
-// The flag, if set, indicates to the analyzer that switch statements
+// The flag, if enabled, indicates to the analyzer that switch statements
// are to be considered exhaustive as long as a 'default' case is present, even
// if all enum members aren't listed in the switch statements cases.
//
-// The other relevant flag is the -fix flag.
+// The -check-generated boolean flag, disabled by default, indicates whether
+// to check switch statements in generated Go source files.
+//
+// The other relevant flag is the -fix flag; its behavior is described
+// in the next section.
//
// Fixes
//
@@ -48,7 +53,7 @@
// and does not have a 'default' case. The suggested fix always adds a single
// case clause for the missing enum members.
//
-// case missingA, missingB, missingC:
+// case MissingA, MissingB, MissingC:
// panic(fmt.Sprintf("unhandled value: %v", v))
//
// where v is the expression in the switch statement's tag (in other words, the
@@ -63,7 +68,7 @@
//
// Imports will be adjusted automatically to account for the "fmt" dependency.
//
-// Skip analysis of specific switch statements
+// Skipping analysis
//
// If the following directive comment:
//
@@ -71,6 +76,10 @@
//
// is associated with a switch statement, the analyzer skips
// checking of the switch statement and no diagnostics are reported.
+//
+// Additionally, no diagnostics are reported for switch statements in
+// generated files (see https://golang.org/s/generatedcode for definition of
+// generated file), unless the -check-generated flag is enabled.
package exhaustive
import (
@@ -84,20 +93,21 @@ import (
"golang.org/x/tools/go/ast/inspector"
)
+// Flag names used by the analyzer. They are exported for use by analyzer
+// driver programs.
const (
- // DefaultSignifiesExhaustiveFlag is a flag name used by the analyzer. It
- // is exported for use by analyzer driver programs.
DefaultSignifiesExhaustiveFlag = "default-signifies-exhaustive"
+ CheckGeneratedFlag = "check-generated"
)
var (
- fCheckMaps bool
fDefaultSignifiesExhaustive bool
+ fCheckGeneratedFiles bool
)
func init() {
- Analyzer.Flags.BoolVar(&fCheckMaps, "maps", false, "check key exhaustiveness for map literals of enum key type, in addition to checking switch statements")
Analyzer.Flags.BoolVar(&fDefaultSignifiesExhaustive, DefaultSignifiesExhaustiveFlag, false, "indicates that switch statements are to be considered exhaustive if a 'default' case is present, even if all enum members aren't listed in the switch")
+ Analyzer.Flags.BoolVar(&fCheckGeneratedFiles, CheckGeneratedFlag, false, "check switch statements in generated files also")
}
var Analyzer = &analysis.Analyzer{
@@ -109,8 +119,7 @@ var Analyzer = &analysis.Analyzer{
}
// IgnoreDirectivePrefix is used to exclude checking of specific switch statements.
-// See https://godoc.org/github.com/nishanths/exhaustive#hdr-Skip_analysis_of_specific_switch_statements
-// for details.
+// See package comment for details.
const IgnoreDirectivePrefix = "//exhaustive:ignore"
func containsIgnoreDirective(comments []*ast.Comment) bool {
@@ -123,7 +132,7 @@ func containsIgnoreDirective(comments []*ast.Comment) bool {
}
type enumsFact struct {
- Entries enums
+ Enums enums
}
var _ analysis.Fact = (*enumsFact)(nil)
@@ -133,20 +142,21 @@ func (e *enumsFact) AFact() {}
func (e *enumsFact) String() string {
// sort for stability (required for testing)
var sortedKeys []string
- for k := range e.Entries {
+ for k := range e.Enums {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
var buf strings.Builder
for i, k := range sortedKeys {
- v := e.Entries[k]
+ v := e.Enums[k]
buf.WriteString(k)
buf.WriteString(":")
- for j, vv := range v {
+
+ for j, vv := range v.OrderedNames {
buf.WriteString(vv)
// add comma separator between each enum member in an enum type
- if j != len(v)-1 {
+ if j != len(v.OrderedNames)-1 {
buf.WriteString(",")
}
}
@@ -161,16 +171,14 @@ func (e *enumsFact) String() string {
func run(pass *analysis.Pass) (interface{}, error) {
e := findEnums(pass)
if len(e) != 0 {
- pass.ExportPackageFact(&enumsFact{Entries: e})
+ pass.ExportPackageFact(&enumsFact{Enums: e})
}
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
comments := make(map[*ast.File]ast.CommentMap) // CommentMap per package file, lazily populated by reference
+ generated := make(map[*ast.File]bool)
- checkSwitchStatements(pass, inspect, comments)
- if fCheckMaps {
- checkMapLiterals(pass, inspect, comments)
- }
+ checkSwitchStatements(pass, inspect, comments, generated)
return nil, nil
}
diff --git a/vendor/github.com/nishanths/exhaustive/generated.go b/vendor/github.com/nishanths/exhaustive/generated.go
new file mode 100644
index 000000000..19b4fb12b
--- /dev/null
+++ b/vendor/github.com/nishanths/exhaustive/generated.go
@@ -0,0 +1,34 @@
+package exhaustive
+
+import (
+ "go/ast"
+ "strings"
+)
+
+// Adapated from https://gotools.org/dmitri.shuralyov.com/go/generated
+
+func isGeneratedFile(file *ast.File) bool {
+ for _, c := range file.Comments {
+ for _, cc := range c.List {
+ s := cc.Text // "\n" already removed (see doc comment)
+ if len(s) >= 1 && s[len(s)-1] == '\r' {
+ s = s[:len(s)-1] // Trim "\r".
+ }
+ if containsGeneratedComment(s) {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+func containsGeneratedComment(s string) bool {
+ return strings.HasPrefix(s, genCommentPrefix) &&
+ strings.HasSuffix(s, genCommentSuffix)
+}
+
+const (
+ genCommentPrefix = "// Code generated "
+ genCommentSuffix = " DO NOT EDIT."
+)
diff --git a/vendor/github.com/nishanths/exhaustive/go.mod b/vendor/github.com/nishanths/exhaustive/go.mod
index b15048eab..9a75e5152 100644
--- a/vendor/github.com/nishanths/exhaustive/go.mod
+++ b/vendor/github.com/nishanths/exhaustive/go.mod
@@ -2,4 +2,4 @@ module github.com/nishanths/exhaustive
go 1.14
-require golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a
+require golang.org/x/tools v0.0.0-20201011145850-ed2f50202694
diff --git a/vendor/github.com/nishanths/exhaustive/go.sum b/vendor/github.com/nishanths/exhaustive/go.sum
index 01ba99965..4f00a79cc 100644
--- a/vendor/github.com/nishanths/exhaustive/go.sum
+++ b/vendor/github.com/nishanths/exhaustive/go.sum
@@ -1,21 +1,38 @@
+github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a h1:gILuVKC+ZPD6g/tj6zBOdnOH1ZHI0zZ86+KLMogc6/s=
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200519142718-10921354bc51 h1:GtYAC9y+dpwWCXBwbcZgxcFfiqW4SI93yvQqpF+9+P8=
+golang.org/x/tools v0.0.0-20201011145850-ed2f50202694 h1:BANdcOVw3KTuUiyfDp7wrzCpkCe8UP3lowugJngxBTg=
+golang.org/x/tools v0.0.0-20201011145850-ed2f50202694/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/vendor/github.com/nishanths/exhaustive/map.go b/vendor/github.com/nishanths/exhaustive/map.go
deleted file mode 100644
index 6d875e32a..000000000
--- a/vendor/github.com/nishanths/exhaustive/map.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package exhaustive
-
-import (
- "fmt"
- "go/ast"
- "go/token"
- "go/types"
- "sort"
- "strings"
-
- "golang.org/x/tools/go/analysis"
- "golang.org/x/tools/go/ast/astutil"
- "golang.org/x/tools/go/ast/inspector"
-)
-
-func checkMapLiterals(pass *analysis.Pass, inspect *inspector.Inspector, comments map[*ast.File]ast.CommentMap) {
- for _, f := range pass.Files {
- for _, d := range f.Decls {
- gen, ok := d.(*ast.GenDecl)
- if !ok {
- continue
- }
- if gen.Tok != token.VAR {
- continue // map literals have to be declared as "var"
- }
- for _, s := range gen.Specs {
- valueSpec := s.(*ast.ValueSpec)
- for idx, name := range valueSpec.Names {
- obj := pass.TypesInfo.Defs[name]
- if obj == nil {
- continue
- }
-
- mapType, ok := obj.Type().(*types.Map)
- if !ok {
- continue
- }
-
- keyType, ok := mapType.Key().(*types.Named)
- if !ok {
- continue
- }
- keyPkg := keyType.Obj().Pkg()
- if keyPkg == nil {
- // Doc comment: nil for labels and objects in the Universe scope.
- // This happens for the `error` type, for example.
- // Continuing would mean that ImportPackageFact panics.
- continue
- }
-
- var enums enumsFact
- if !pass.ImportPackageFact(keyPkg, &enums) {
- // Can't do anything further.
- continue
- }
-
- enumMembers, ok := enums.Entries[keyType.Obj().Name()]
- if !ok {
- // Key type is not a known enum.
- continue
- }
-
- // Check comments for the ignore directive.
-
- var allComments ast.CommentMap
- if cm, ok := comments[f]; ok {
- allComments = cm
- } else {
- allComments = ast.NewCommentMap(pass.Fset, f, f.Comments)
- comments[f] = allComments
- }
-
- genDeclComments := allComments.Filter(gen)
- genDeclIgnore := false
- for _, group := range genDeclComments.Comments() {
- if containsIgnoreDirective(group.List) && gen.Lparen == token.NoPos && len(gen.Specs) == 1 {
- genDeclIgnore = true
- break
- }
- }
- if genDeclIgnore {
- continue
- }
-
- if (valueSpec.Doc != nil && containsIgnoreDirective(valueSpec.Doc.List)) ||
- (valueSpec.Comment != nil && containsIgnoreDirective(valueSpec.Comment.List)) {
- continue
- }
-
- samePkg := keyPkg == pass.Pkg
- checkUnexported := samePkg
-
- hitlist := hitlistFromEnumMembers(enumMembers, checkUnexported)
- if len(hitlist) == 0 {
- // can happen if external package and enum consists only of
- // unexported members
- continue
- }
-
- if !(len(valueSpec.Values) > idx) {
- continue // no value for name
- }
- comp, ok := valueSpec.Values[idx].(*ast.CompositeLit)
- if !ok {
- continue
- }
- for _, el := range comp.Elts {
- kvExpr, ok := el.(*ast.KeyValueExpr)
- if !ok {
- continue
- }
- e := astutil.Unparen(kvExpr.Key)
- if samePkg {
- ident, ok := e.(*ast.Ident)
- if !ok {
- continue
- }
- delete(hitlist, ident.Name)
- } else {
- selExpr, ok := e.(*ast.SelectorExpr)
- if !ok {
- continue
- }
-
- // ensure X is package identifier
- ident, ok := selExpr.X.(*ast.Ident)
- if !ok {
- continue
- }
- if !isPackageNameIdentifier(pass, ident) {
- continue
- }
-
- delete(hitlist, selExpr.Sel.Name)
- }
- }
-
- if len(hitlist) > 0 {
- reportMapLiteral(pass, name, samePkg, keyType, hitlist)
- }
- }
- }
- }
- }
-}
-
-func reportMapLiteral(pass *analysis.Pass, mapVarIdent *ast.Ident, samePkg bool, enumType *types.Named, missingMembers map[string]struct{}) {
- missing := make([]string, 0, len(missingMembers))
- for m := range missingMembers {
- missing = append(missing, m)
- }
- sort.Strings(missing)
-
- pass.Report(analysis.Diagnostic{
- Pos: mapVarIdent.Pos(),
- Message: fmt.Sprintf("missing keys in map %s of key type %s: %s", mapVarIdent.Name, enumTypeName(enumType, samePkg), strings.Join(missing, ", ")),
- })
-}
diff --git a/vendor/github.com/nishanths/exhaustive/switch.go b/vendor/github.com/nishanths/exhaustive/switch.go
index 5889c2934..2cec7f9cb 100644
--- a/vendor/github.com/nishanths/exhaustive/switch.go
+++ b/vendor/github.com/nishanths/exhaustive/switch.go
@@ -20,11 +20,33 @@ func isDefaultCase(c *ast.CaseClause) bool {
return c.List == nil // see doc comment on field
}
-func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, comments map[*ast.File]ast.CommentMap) {
+func checkSwitchStatements(
+ pass *analysis.Pass,
+ inspect *inspector.Inspector,
+ comments map[*ast.File]ast.CommentMap,
+ generated map[*ast.File]bool,
+) {
inspect.WithStack([]ast.Node{&ast.SwitchStmt{}}, func(n ast.Node, push bool, stack []ast.Node) bool {
if !push {
return true
}
+
+ file := stack[0].(*ast.File)
+
+ // Determine if file is a generated file, based on https://golang.org/s/generatedcode.
+ // If generated, don't check this file.
+ var isGenerated bool
+ if gen, ok := generated[file]; ok {
+ isGenerated = gen
+ } else {
+ isGenerated = isGeneratedFile(file)
+ generated[file] = isGenerated
+ }
+ if isGenerated && !fCheckGeneratedFiles {
+ // don't check
+ return true
+ }
+
sw := n.(*ast.SwitchStmt)
if sw.Tag == nil {
return true
@@ -52,14 +74,13 @@ func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, co
return true
}
- enumMembers, isEnum := enums.Entries[tagType.Obj().Name()]
+ em, isEnum := enums.Enums[tagType.Obj().Name()]
if !isEnum {
// Tag's type is not a known enum.
return true
}
// Get comment map.
- file := stack[0].(*ast.File)
var allComments ast.CommentMap
if cm, ok := comments[file]; ok {
allComments = cm
@@ -78,7 +99,7 @@ func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, co
samePkg := tagPkg == pass.Pkg
checkUnexported := samePkg
- hitlist := hitlistFromEnumMembers(enumMembers, checkUnexported)
+ hitlist := hitlistFromEnumMembers(em, checkUnexported)
if len(hitlist) == 0 {
// can happen if external package and enum consists only of
// unexported members
@@ -99,7 +120,7 @@ func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, co
if !ok {
continue
}
- delete(hitlist, ident.Name)
+ updateHitlist(hitlist, em, ident.Name)
} else {
selExpr, ok := e.(*ast.SelectorExpr)
if !ok {
@@ -115,7 +136,7 @@ func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, co
continue
}
- delete(hitlist, selExpr.Sel.Name)
+ updateHitlist(hitlist, em, selExpr.Sel.Name)
}
}
}
@@ -124,12 +145,27 @@ func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, co
shouldReport := len(hitlist) > 0 && !defaultSuffices
if shouldReport {
- reportSwitch(pass, sw, samePkg, tagType, hitlist, defaultCaseExists, file)
+ reportSwitch(pass, sw, samePkg, tagType, em, hitlist, defaultCaseExists, file)
}
return true
})
}
+func updateHitlist(hitlist map[string]struct{}, em *enumMembers, foundName string) {
+ constVal, ok := em.NameToValue[foundName]
+ if !ok {
+ // only delete the name alone from hitlist
+ delete(hitlist, foundName)
+ return
+ }
+
+ // delete all of the same-valued names from hitlist
+ namesToDelete := em.ValueToNames[constVal]
+ for _, n := range namesToDelete {
+ delete(hitlist, n)
+ }
+}
+
func isPackageNameIdentifier(pass *analysis.Pass, ident *ast.Ident) bool {
obj := pass.TypesInfo.ObjectOf(ident)
if obj == nil {
@@ -139,26 +175,54 @@ func isPackageNameIdentifier(pass *analysis.Pass, ident *ast.Ident) bool {
return ok
}
-func hitlistFromEnumMembers(enumMembers []string, checkUnexported bool) map[string]struct{} {
+func hitlistFromEnumMembers(em *enumMembers, checkUnexported bool) map[string]struct{} {
hitlist := make(map[string]struct{})
- for _, m := range enumMembers {
+ for _, m := range em.OrderedNames {
if m == "_" {
// blank identifier is often used to skip entries in iota lists
continue
}
- if ast.IsExported(m) || checkUnexported {
- hitlist[m] = struct{}{}
+ if !ast.IsExported(m) && !checkUnexported {
+ continue
}
+ hitlist[m] = struct{}{}
}
return hitlist
}
-func reportSwitch(pass *analysis.Pass, sw *ast.SwitchStmt, samePkg bool, enumType *types.Named, missingMembers map[string]struct{}, defaultCaseExists bool, f *ast.File) {
- missing := make([]string, 0, len(missingMembers))
+func determineMissingOutput(missingMembers map[string]struct{}, em *enumMembers) []string {
+ constValMembers := make(map[string][]string) // value -> names
+ var otherMembers []string // non-constant value names
+
for m := range missingMembers {
- missing = append(missing, m)
+ if constVal, ok := em.NameToValue[m]; ok {
+ constValMembers[constVal] = append(constValMembers[constVal], m)
+ } else {
+ otherMembers = append(otherMembers, m)
+ }
}
- sort.Strings(missing)
+
+ missingOutput := make([]string, 0, len(constValMembers)+len(otherMembers))
+ for _, names := range constValMembers {
+ sort.Strings(names)
+ missingOutput = append(missingOutput, strings.Join(names, "|"))
+ }
+ missingOutput = append(missingOutput, otherMembers...)
+ sort.Strings(missingOutput)
+ return missingOutput
+}
+
+func reportSwitch(
+ pass *analysis.Pass,
+ sw *ast.SwitchStmt,
+ samePkg bool,
+ enumType *types.Named,
+ em *enumMembers,
+ missingMembers map[string]struct{},
+ defaultCaseExists bool,
+ f *ast.File,
+) {
+ missingOutput := determineMissingOutput(missingMembers, em)
var fixes []analysis.SuggestedFix
if !defaultCaseExists {
@@ -170,7 +234,7 @@ func reportSwitch(pass *analysis.Pass, sw *ast.SwitchStmt, samePkg bool, enumTyp
pass.Report(analysis.Diagnostic{
Pos: sw.Pos(),
End: sw.End(),
- Message: fmt.Sprintf("missing cases in switch of type %s: %s", enumTypeName(enumType, samePkg), strings.Join(missing, ", ")),
+ Message: fmt.Sprintf("missing cases in switch of type %s: %s", enumTypeName(enumType, samePkg), strings.Join(missingOutput, ", ")),
SuggestedFixes: fixes,
})
}
diff --git a/vendor/github.com/nishanths/predeclared/LICENSE b/vendor/github.com/nishanths/predeclared/LICENSE
new file mode 100644
index 000000000..946212315
--- /dev/null
+++ b/vendor/github.com/nishanths/predeclared/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2017, Nishanth Shanmugham
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/nishanths/predeclared/passes/predeclared/go18.go b/vendor/github.com/nishanths/predeclared/passes/predeclared/go18.go
new file mode 100644
index 000000000..4083efc74
--- /dev/null
+++ b/vendor/github.com/nishanths/predeclared/passes/predeclared/go18.go
@@ -0,0 +1,9 @@
+// +build go1.8
+
+package predeclared
+
+import "go/doc"
+
+func isPredeclaredIdent(name string) bool {
+ return doc.IsPredeclared(name)
+}
diff --git a/vendor/github.com/nishanths/predeclared/passes/predeclared/pre_go18.go b/vendor/github.com/nishanths/predeclared/passes/predeclared/pre_go18.go
new file mode 100644
index 000000000..5780e0b56
--- /dev/null
+++ b/vendor/github.com/nishanths/predeclared/passes/predeclared/pre_go18.go
@@ -0,0 +1,53 @@
+// +build !go1.8
+
+package predeclared
+
+func isPredeclaredIdent(name string) bool {
+ return predeclaredIdents[name]
+}
+
+// Keep in sync with https://golang.org/ref/spec#Predeclared_identifiers
+var predeclaredIdents = map[string]bool{
+ "bool": true,
+ "byte": true,
+ "complex64": true,
+ "complex128": true,
+ "error": true,
+ "float32": true,
+ "float64": true,
+ "int": true,
+ "int8": true,
+ "int16": true,
+ "int32": true,
+ "int64": true,
+ "rune": true,
+ "string": true,
+ "uint": true,
+ "uint8": true,
+ "uint16": true,
+ "uint32": true,
+ "uint64": true,
+ "uintptr": true,
+
+ "true": true,
+ "false": true,
+ "iota": true,
+
+ "nil": true,
+
+ "append": true,
+ "cap": true,
+ "close": true,
+ "complex": true,
+ "copy": true,
+ "delete": true,
+ "imag": true,
+ "len": true,
+ "make": true,
+ "new": true,
+ "panic": true,
+ "print": true,
+ "println": true,
+ "real": true,
+ "recover": true,
+}
diff --git a/vendor/github.com/nishanths/predeclared/passes/predeclared/predeclared.go b/vendor/github.com/nishanths/predeclared/passes/predeclared/predeclared.go
new file mode 100644
index 000000000..67c0e0a00
--- /dev/null
+++ b/vendor/github.com/nishanths/predeclared/passes/predeclared/predeclared.go
@@ -0,0 +1,202 @@
+// Package predeclared provides a static analysis (used by the predeclared command)
+// that can detect declarations in Go code that shadow one of Go's predeclared identifiers.
+package predeclared
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// Flag names used by the analyzer. They are exported for use by analyzer
+// driver programs.
+const (
+ IgnoreFlag = "ignore"
+ QualifiedFlag = "q"
+)
+
+var (
+ fIgnore string
+ fQualified bool
+)
+
+func init() {
+ Analyzer.Flags.StringVar(&fIgnore, IgnoreFlag, "", "comma-separated list of predeclared identifiers to not report on")
+ Analyzer.Flags.BoolVar(&fQualified, QualifiedFlag, false, "include method names and field names (i.e., qualified names) in checks")
+}
+
+var Analyzer = &analysis.Analyzer{
+ Name: "predeclared",
+ Doc: "find code that shadows one of Go's predeclared identifiers",
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ cfg := newConfig(fIgnore, fQualified)
+ for _, file := range pass.Files {
+ processFile(pass.Report, cfg, pass.Fset, file)
+ }
+ return nil, nil
+}
+
+type config struct {
+ qualified bool
+ ignoredIdents map[string]struct{}
+}
+
+func newConfig(ignore string, qualified bool) *config {
+ cfg := &config{
+ qualified: qualified,
+ ignoredIdents: map[string]struct{}{},
+ }
+ for _, s := range strings.Split(ignore, ",") {
+ ident := strings.TrimSpace(s)
+ if ident == "" {
+ continue
+ }
+ cfg.ignoredIdents[ident] = struct{}{}
+ }
+ return cfg
+}
+
+type issue struct {
+ ident *ast.Ident
+ kind string
+ fset *token.FileSet
+}
+
+func (i issue) String() string {
+ pos := i.fset.Position(i.ident.Pos())
+ return fmt.Sprintf("%s: %s %s has same name as predeclared identifier", pos, i.kind, i.ident.Name)
+}
+
+func processFile(report func(analysis.Diagnostic), cfg *config, fset *token.FileSet, file *ast.File) []issue { // nolint: gocyclo
+ var issues []issue
+
+ maybeReport := func(x *ast.Ident, kind string) {
+ if _, isIgnored := cfg.ignoredIdents[x.Name]; !isIgnored && isPredeclaredIdent(x.Name) {
+ report(analysis.Diagnostic{
+ Pos: x.Pos(),
+ End: x.End(),
+ Message: fmt.Sprintf("%s %s has same name as predeclared identifier", kind, x.Name),
+ })
+ issues = append(issues, issue{x, kind, fset})
+ }
+ }
+
+ seenValueSpecs := make(map[*ast.ValueSpec]bool)
+
+ // TODO: consider deduping package name issues for files in the
+ // same directory.
+ maybeReport(file.Name, "package name")
+
+ for _, spec := range file.Imports {
+ if spec.Name == nil {
+ continue
+ }
+ maybeReport(spec.Name, "import name")
+ }
+
+ // Handle declarations and fields.
+ // https://golang.org/ref/spec#Declarations_and_scope
+ ast.Inspect(file, func(n ast.Node) bool {
+ switch x := n.(type) {
+ case *ast.GenDecl:
+ var kind string
+ switch x.Tok {
+ case token.CONST:
+ kind = "const"
+ case token.VAR:
+ kind = "variable"
+ default:
+ return true
+ }
+ for _, spec := range x.Specs {
+ if vspec, ok := spec.(*ast.ValueSpec); ok && !seenValueSpecs[vspec] {
+ seenValueSpecs[vspec] = true
+ for _, name := range vspec.Names {
+ maybeReport(name, kind)
+ }
+ }
+ }
+ return true
+ case *ast.TypeSpec:
+ maybeReport(x.Name, "type")
+ return true
+ case *ast.StructType:
+ if cfg.qualified && x.Fields != nil {
+ for _, field := range x.Fields.List {
+ for _, name := range field.Names {
+ maybeReport(name, "field")
+ }
+ }
+ }
+ return true
+ case *ast.InterfaceType:
+ if cfg.qualified && x.Methods != nil {
+ for _, meth := range x.Methods.List {
+ for _, name := range meth.Names {
+ maybeReport(name, "method")
+ }
+ }
+ }
+ return true
+ case *ast.FuncDecl:
+ if x.Recv == nil {
+ // it's a function
+ maybeReport(x.Name, "function")
+ } else {
+ // it's a method
+ if cfg.qualified {
+ maybeReport(x.Name, "method")
+ }
+ }
+ // add receivers idents
+ if x.Recv != nil {
+ for _, field := range x.Recv.List {
+ for _, name := range field.Names {
+ maybeReport(name, "receiver")
+ }
+ }
+ }
+ // Params and Results will be checked in the *ast.FuncType case.
+ return true
+ case *ast.FuncType:
+ // add params idents
+ for _, field := range x.Params.List {
+ for _, name := range field.Names {
+ maybeReport(name, "param")
+ }
+ }
+ // add returns idents
+ if x.Results != nil {
+ for _, field := range x.Results.List {
+ for _, name := range field.Names {
+ maybeReport(name, "named return")
+ }
+ }
+ }
+ return true
+ case *ast.LabeledStmt:
+ maybeReport(x.Label, "label")
+ return true
+ case *ast.AssignStmt:
+ // We only care about short variable declarations, which use token.DEFINE.
+ if x.Tok == token.DEFINE {
+ for _, expr := range x.Lhs {
+ if ident, ok := expr.(*ast.Ident); ok {
+ maybeReport(ident, "variable")
+ }
+ }
+ }
+ return true
+ default:
+ return true
+ }
+ })
+
+ return issues
+}