Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / analysis / passes / shadow / shadow.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/go/analysis/passes/shadow/shadow.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/go/analysis/passes/shadow/shadow.go
new file mode 100644 (file)
index 0000000..b160dcf
--- /dev/null
@@ -0,0 +1,290 @@
+// Copyright 2013 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 shadow defines an Analyzer that checks for shadowed variables.
+package shadow
+
+import (
+       "go/ast"
+       "go/token"
+       "go/types"
+
+       "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/go/analysis/passes/inspect"
+       "golang.org/x/tools/go/ast/inspector"
+)
+
+// NOTE: Experimental. Not part of the vet suite.
+
+const Doc = `check for possible unintended shadowing of variables
+
+This analyzer check for shadowed variables.
+A shadowed variable is a variable declared in an inner scope
+with the same name and type as a variable in an outer scope,
+and where the outer variable is mentioned after the inner one
+is declared.
+
+(This definition can be refined; the module generates too many
+false positives and is not yet enabled by default.)
+
+For example:
+
+       func BadRead(f *os.File, buf []byte) error {
+               var err error
+               for {
+                       n, err := f.Read(buf) // shadows the function variable 'err'
+                       if err != nil {
+                               break // causes return of wrong value
+                       }
+                       foo(buf)
+               }
+               return err
+       }
+`
+
+var Analyzer = &analysis.Analyzer{
+       Name:     "shadow",
+       Doc:      Doc,
+       Requires: []*analysis.Analyzer{inspect.Analyzer},
+       Run:      run,
+}
+
+// flags
+var strict = false
+
+func init() {
+       Analyzer.Flags.BoolVar(&strict, "strict", strict, "whether to be strict about shadowing; can be noisy")
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+       inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+       spans := make(map[types.Object]span)
+       for id, obj := range pass.TypesInfo.Defs {
+               // Ignore identifiers that don't denote objects
+               // (package names, symbolic variables such as t
+               // in t := x.(type) of type switch headers).
+               if obj != nil {
+                       growSpan(spans, obj, id.Pos(), id.End())
+               }
+       }
+       for id, obj := range pass.TypesInfo.Uses {
+               growSpan(spans, obj, id.Pos(), id.End())
+       }
+       for node, obj := range pass.TypesInfo.Implicits {
+               // A type switch with a short variable declaration
+               // such as t := x.(type) doesn't declare the symbolic
+               // variable (t in the example) at the switch header;
+               // instead a new variable t (with specific type) is
+               // declared implicitly for each case. Such variables
+               // are found in the types.Info.Implicits (not Defs)
+               // map. Add them here, assuming they are declared at
+               // the type cases' colon ":".
+               if cc, ok := node.(*ast.CaseClause); ok {
+                       growSpan(spans, obj, cc.Colon, cc.Colon)
+               }
+       }
+
+       nodeFilter := []ast.Node{
+               (*ast.AssignStmt)(nil),
+               (*ast.GenDecl)(nil),
+       }
+       inspect.Preorder(nodeFilter, func(n ast.Node) {
+               switch n := n.(type) {
+               case *ast.AssignStmt:
+                       checkShadowAssignment(pass, spans, n)
+               case *ast.GenDecl:
+                       checkShadowDecl(pass, spans, n)
+               }
+       })
+       return nil, nil
+}
+
+// A span stores the minimum range of byte positions in the file in which a
+// given variable (types.Object) is mentioned. It is lexically defined: it spans
+// from the beginning of its first mention to the end of its last mention.
+// A variable is considered shadowed (if strict is off) only if the
+// shadowing variable is declared within the span of the shadowed variable.
+// In other words, if a variable is shadowed but not used after the shadowed
+// variable is declared, it is inconsequential and not worth complaining about.
+// This simple check dramatically reduces the nuisance rate for the shadowing
+// check, at least until something cleverer comes along.
+//
+// One wrinkle: A "naked return" is a silent use of a variable that the Span
+// will not capture, but the compilers catch naked returns of shadowed
+// variables so we don't need to.
+//
+// Cases this gets wrong (TODO):
+// - If a for loop's continuation statement mentions a variable redeclared in
+// the block, we should complain about it but don't.
+// - A variable declared inside a function literal can falsely be identified
+// as shadowing a variable in the outer function.
+//
+type span struct {
+       min token.Pos
+       max token.Pos
+}
+
+// contains reports whether the position is inside the span.
+func (s span) contains(pos token.Pos) bool {
+       return s.min <= pos && pos < s.max
+}
+
+// growSpan expands the span for the object to contain the source range [pos, end).
+func growSpan(spans map[types.Object]span, obj types.Object, pos, end token.Pos) {
+       if strict {
+               return // No need
+       }
+       s, ok := spans[obj]
+       if ok {
+               if s.min > pos {
+                       s.min = pos
+               }
+               if s.max < end {
+                       s.max = end
+               }
+       } else {
+               s = span{pos, end}
+       }
+       spans[obj] = s
+}
+
+// checkShadowAssignment checks for shadowing in a short variable declaration.
+func checkShadowAssignment(pass *analysis.Pass, spans map[types.Object]span, a *ast.AssignStmt) {
+       if a.Tok != token.DEFINE {
+               return
+       }
+       if idiomaticShortRedecl(pass, a) {
+               return
+       }
+       for _, expr := range a.Lhs {
+               ident, ok := expr.(*ast.Ident)
+               if !ok {
+                       pass.ReportRangef(expr, "invalid AST: short variable declaration of non-identifier")
+                       return
+               }
+               checkShadowing(pass, spans, ident)
+       }
+}
+
+// idiomaticShortRedecl reports whether this short declaration can be ignored for
+// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
+func idiomaticShortRedecl(pass *analysis.Pass, a *ast.AssignStmt) bool {
+       // Don't complain about deliberate redeclarations of the form
+       //      i := i
+       // Such constructs are idiomatic in range loops to create a new variable
+       // for each iteration. Another example is
+       //      switch n := n.(type)
+       if len(a.Rhs) != len(a.Lhs) {
+               return false
+       }
+       // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.)
+       for i, expr := range a.Lhs {
+               lhs, ok := expr.(*ast.Ident)
+               if !ok {
+                       pass.ReportRangef(expr, "invalid AST: short variable declaration of non-identifier")
+                       return true // Don't do any more processing.
+               }
+               switch rhs := a.Rhs[i].(type) {
+               case *ast.Ident:
+                       if lhs.Name != rhs.Name {
+                               return false
+                       }
+               case *ast.TypeAssertExpr:
+                       if id, ok := rhs.X.(*ast.Ident); ok {
+                               if lhs.Name != id.Name {
+                                       return false
+                               }
+                       }
+               default:
+                       return false
+               }
+       }
+       return true
+}
+
+// idiomaticRedecl reports whether this declaration spec can be ignored for
+// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
+func idiomaticRedecl(d *ast.ValueSpec) bool {
+       // Don't complain about deliberate redeclarations of the form
+       //      var i, j = i, j
+       // Don't ignore redeclarations of the form
+       //      var i = 3
+       if len(d.Names) != len(d.Values) {
+               return false
+       }
+       for i, lhs := range d.Names {
+               rhs, ok := d.Values[i].(*ast.Ident)
+               if !ok || lhs.Name != rhs.Name {
+                       return false
+               }
+       }
+       return true
+}
+
+// checkShadowDecl checks for shadowing in a general variable declaration.
+func checkShadowDecl(pass *analysis.Pass, spans map[types.Object]span, d *ast.GenDecl) {
+       if d.Tok != token.VAR {
+               return
+       }
+       for _, spec := range d.Specs {
+               valueSpec, ok := spec.(*ast.ValueSpec)
+               if !ok {
+                       pass.ReportRangef(spec, "invalid AST: var GenDecl not ValueSpec")
+                       return
+               }
+               // Don't complain about deliberate redeclarations of the form
+               //      var i = i
+               if idiomaticRedecl(valueSpec) {
+                       return
+               }
+               for _, ident := range valueSpec.Names {
+                       checkShadowing(pass, spans, ident)
+               }
+       }
+}
+
+// checkShadowing checks whether the identifier shadows an identifier in an outer scope.
+func checkShadowing(pass *analysis.Pass, spans map[types.Object]span, ident *ast.Ident) {
+       if ident.Name == "_" {
+               // Can't shadow the blank identifier.
+               return
+       }
+       obj := pass.TypesInfo.Defs[ident]
+       if obj == nil {
+               return
+       }
+       // obj.Parent.Parent is the surrounding scope. If we can find another declaration
+       // starting from there, we have a shadowed identifier.
+       _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos())
+       if shadowed == nil {
+               return
+       }
+       // Don't complain if it's shadowing a universe-declared identifier; that's fine.
+       if shadowed.Parent() == types.Universe {
+               return
+       }
+       if strict {
+               // The shadowed identifier must appear before this one to be an instance of shadowing.
+               if shadowed.Pos() > ident.Pos() {
+                       return
+               }
+       } else {
+               // Don't complain if the span of validity of the shadowed identifier doesn't include
+               // the shadowing identifier.
+               span, ok := spans[shadowed]
+               if !ok {
+                       pass.ReportRangef(ident, "internal error: no range for %q", ident.Name)
+                       return
+               }
+               if !span.contains(ident.Pos()) {
+                       return
+               }
+       }
+       // Don't complain if the types differ: that implies the programmer really wants two different things.
+       if types.Identical(obj.Type(), shadowed.Type()) {
+               line := pass.Fset.Position(shadowed.Pos()).Line
+               pass.ReportRangef(ident, "declaration of %q shadows declaration at line %d", obj.Name(), line)
+       }
+}