.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / go / analysis / passes / composite / composite.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/go/analysis/passes/composite/composite.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/go/analysis/passes/composite/composite.go
new file mode 100644 (file)
index 0000000..4c3ac66
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package composite defines an Analyzer that checks for unkeyed
+// composite literals.
+package composite
+
+import (
+       "go/ast"
+       "go/types"
+       "strings"
+
+       "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/go/analysis/passes/inspect"
+       "golang.org/x/tools/go/ast/inspector"
+)
+
+const Doc = `check for unkeyed composite literals
+
+This analyzer reports a diagnostic for composite literals of struct
+types imported from another package that do not use the field-keyed
+syntax. Such literals are fragile because the addition of a new field
+(even if unexported) to the struct will cause compilation to fail.
+
+As an example,
+
+       err = &net.DNSConfigError{err}
+
+should be replaced by:
+
+       err = &net.DNSConfigError{Err: err}
+`
+
+var Analyzer = &analysis.Analyzer{
+       Name:             "composites",
+       Doc:              Doc,
+       Requires:         []*analysis.Analyzer{inspect.Analyzer},
+       RunDespiteErrors: true,
+       Run:              run,
+}
+
+var whitelist = true
+
+func init() {
+       Analyzer.Flags.BoolVar(&whitelist, "whitelist", whitelist, "use composite white list; for testing only")
+}
+
+// runUnkeyedLiteral checks if a composite literal is a struct literal with
+// unkeyed fields.
+func run(pass *analysis.Pass) (interface{}, error) {
+       inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+       nodeFilter := []ast.Node{
+               (*ast.CompositeLit)(nil),
+       }
+       inspect.Preorder(nodeFilter, func(n ast.Node) {
+               cl := n.(*ast.CompositeLit)
+
+               typ := pass.TypesInfo.Types[cl].Type
+               if typ == nil {
+                       // cannot determine composite literals' type, skip it
+                       return
+               }
+               typeName := typ.String()
+               if whitelist && unkeyedLiteral[typeName] {
+                       // skip whitelisted types
+                       return
+               }
+               under := typ.Underlying()
+               for {
+                       ptr, ok := under.(*types.Pointer)
+                       if !ok {
+                               break
+                       }
+                       under = ptr.Elem().Underlying()
+               }
+               if _, ok := under.(*types.Struct); !ok {
+                       // skip non-struct composite literals
+                       return
+               }
+               if isLocalType(pass, typ) {
+                       // allow unkeyed locally defined composite literal
+                       return
+               }
+
+               // check if the CompositeLit contains an unkeyed field
+               allKeyValue := true
+               for _, e := range cl.Elts {
+                       if _, ok := e.(*ast.KeyValueExpr); !ok {
+                               allKeyValue = false
+                               break
+                       }
+               }
+               if allKeyValue {
+                       // all the composite literal fields are keyed
+                       return
+               }
+
+               pass.ReportRangef(cl, "%s composite literal uses unkeyed fields", typeName)
+       })
+       return nil, nil
+}
+
+func isLocalType(pass *analysis.Pass, typ types.Type) bool {
+       switch x := typ.(type) {
+       case *types.Struct:
+               // struct literals are local types
+               return true
+       case *types.Pointer:
+               return isLocalType(pass, x.Elem())
+       case *types.Named:
+               // names in package foo are local to foo_test too
+               return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
+       }
+       return false
+}