Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / analysis / passes / shadow / shadow.go
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package shadow defines an Analyzer that checks for shadowed variables.
6 package shadow
7
8 import (
9         "go/ast"
10         "go/token"
11         "go/types"
12
13         "golang.org/x/tools/go/analysis"
14         "golang.org/x/tools/go/analysis/passes/inspect"
15         "golang.org/x/tools/go/ast/inspector"
16 )
17
18 // NOTE: Experimental. Not part of the vet suite.
19
20 const Doc = `check for possible unintended shadowing of variables
21
22 This analyzer check for shadowed variables.
23 A shadowed variable is a variable declared in an inner scope
24 with the same name and type as a variable in an outer scope,
25 and where the outer variable is mentioned after the inner one
26 is declared.
27
28 (This definition can be refined; the module generates too many
29 false positives and is not yet enabled by default.)
30
31 For example:
32
33         func BadRead(f *os.File, buf []byte) error {
34                 var err error
35                 for {
36                         n, err := f.Read(buf) // shadows the function variable 'err'
37                         if err != nil {
38                                 break // causes return of wrong value
39                         }
40                         foo(buf)
41                 }
42                 return err
43         }
44 `
45
46 var Analyzer = &analysis.Analyzer{
47         Name:     "shadow",
48         Doc:      Doc,
49         Requires: []*analysis.Analyzer{inspect.Analyzer},
50         Run:      run,
51 }
52
53 // flags
54 var strict = false
55
56 func init() {
57         Analyzer.Flags.BoolVar(&strict, "strict", strict, "whether to be strict about shadowing; can be noisy")
58 }
59
60 func run(pass *analysis.Pass) (interface{}, error) {
61         inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
62
63         spans := make(map[types.Object]span)
64         for id, obj := range pass.TypesInfo.Defs {
65                 // Ignore identifiers that don't denote objects
66                 // (package names, symbolic variables such as t
67                 // in t := x.(type) of type switch headers).
68                 if obj != nil {
69                         growSpan(spans, obj, id.Pos(), id.End())
70                 }
71         }
72         for id, obj := range pass.TypesInfo.Uses {
73                 growSpan(spans, obj, id.Pos(), id.End())
74         }
75         for node, obj := range pass.TypesInfo.Implicits {
76                 // A type switch with a short variable declaration
77                 // such as t := x.(type) doesn't declare the symbolic
78                 // variable (t in the example) at the switch header;
79                 // instead a new variable t (with specific type) is
80                 // declared implicitly for each case. Such variables
81                 // are found in the types.Info.Implicits (not Defs)
82                 // map. Add them here, assuming they are declared at
83                 // the type cases' colon ":".
84                 if cc, ok := node.(*ast.CaseClause); ok {
85                         growSpan(spans, obj, cc.Colon, cc.Colon)
86                 }
87         }
88
89         nodeFilter := []ast.Node{
90                 (*ast.AssignStmt)(nil),
91                 (*ast.GenDecl)(nil),
92         }
93         inspect.Preorder(nodeFilter, func(n ast.Node) {
94                 switch n := n.(type) {
95                 case *ast.AssignStmt:
96                         checkShadowAssignment(pass, spans, n)
97                 case *ast.GenDecl:
98                         checkShadowDecl(pass, spans, n)
99                 }
100         })
101         return nil, nil
102 }
103
104 // A span stores the minimum range of byte positions in the file in which a
105 // given variable (types.Object) is mentioned. It is lexically defined: it spans
106 // from the beginning of its first mention to the end of its last mention.
107 // A variable is considered shadowed (if strict is off) only if the
108 // shadowing variable is declared within the span of the shadowed variable.
109 // In other words, if a variable is shadowed but not used after the shadowed
110 // variable is declared, it is inconsequential and not worth complaining about.
111 // This simple check dramatically reduces the nuisance rate for the shadowing
112 // check, at least until something cleverer comes along.
113 //
114 // One wrinkle: A "naked return" is a silent use of a variable that the Span
115 // will not capture, but the compilers catch naked returns of shadowed
116 // variables so we don't need to.
117 //
118 // Cases this gets wrong (TODO):
119 // - If a for loop's continuation statement mentions a variable redeclared in
120 // the block, we should complain about it but don't.
121 // - A variable declared inside a function literal can falsely be identified
122 // as shadowing a variable in the outer function.
123 //
124 type span struct {
125         min token.Pos
126         max token.Pos
127 }
128
129 // contains reports whether the position is inside the span.
130 func (s span) contains(pos token.Pos) bool {
131         return s.min <= pos && pos < s.max
132 }
133
134 // growSpan expands the span for the object to contain the source range [pos, end).
135 func growSpan(spans map[types.Object]span, obj types.Object, pos, end token.Pos) {
136         if strict {
137                 return // No need
138         }
139         s, ok := spans[obj]
140         if ok {
141                 if s.min > pos {
142                         s.min = pos
143                 }
144                 if s.max < end {
145                         s.max = end
146                 }
147         } else {
148                 s = span{pos, end}
149         }
150         spans[obj] = s
151 }
152
153 // checkShadowAssignment checks for shadowing in a short variable declaration.
154 func checkShadowAssignment(pass *analysis.Pass, spans map[types.Object]span, a *ast.AssignStmt) {
155         if a.Tok != token.DEFINE {
156                 return
157         }
158         if idiomaticShortRedecl(pass, a) {
159                 return
160         }
161         for _, expr := range a.Lhs {
162                 ident, ok := expr.(*ast.Ident)
163                 if !ok {
164                         pass.ReportRangef(expr, "invalid AST: short variable declaration of non-identifier")
165                         return
166                 }
167                 checkShadowing(pass, spans, ident)
168         }
169 }
170
171 // idiomaticShortRedecl reports whether this short declaration can be ignored for
172 // the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
173 func idiomaticShortRedecl(pass *analysis.Pass, a *ast.AssignStmt) bool {
174         // Don't complain about deliberate redeclarations of the form
175         //      i := i
176         // Such constructs are idiomatic in range loops to create a new variable
177         // for each iteration. Another example is
178         //      switch n := n.(type)
179         if len(a.Rhs) != len(a.Lhs) {
180                 return false
181         }
182         // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.)
183         for i, expr := range a.Lhs {
184                 lhs, ok := expr.(*ast.Ident)
185                 if !ok {
186                         pass.ReportRangef(expr, "invalid AST: short variable declaration of non-identifier")
187                         return true // Don't do any more processing.
188                 }
189                 switch rhs := a.Rhs[i].(type) {
190                 case *ast.Ident:
191                         if lhs.Name != rhs.Name {
192                                 return false
193                         }
194                 case *ast.TypeAssertExpr:
195                         if id, ok := rhs.X.(*ast.Ident); ok {
196                                 if lhs.Name != id.Name {
197                                         return false
198                                 }
199                         }
200                 default:
201                         return false
202                 }
203         }
204         return true
205 }
206
207 // idiomaticRedecl reports whether this declaration spec can be ignored for
208 // the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
209 func idiomaticRedecl(d *ast.ValueSpec) bool {
210         // Don't complain about deliberate redeclarations of the form
211         //      var i, j = i, j
212         // Don't ignore redeclarations of the form
213         //      var i = 3
214         if len(d.Names) != len(d.Values) {
215                 return false
216         }
217         for i, lhs := range d.Names {
218                 rhs, ok := d.Values[i].(*ast.Ident)
219                 if !ok || lhs.Name != rhs.Name {
220                         return false
221                 }
222         }
223         return true
224 }
225
226 // checkShadowDecl checks for shadowing in a general variable declaration.
227 func checkShadowDecl(pass *analysis.Pass, spans map[types.Object]span, d *ast.GenDecl) {
228         if d.Tok != token.VAR {
229                 return
230         }
231         for _, spec := range d.Specs {
232                 valueSpec, ok := spec.(*ast.ValueSpec)
233                 if !ok {
234                         pass.ReportRangef(spec, "invalid AST: var GenDecl not ValueSpec")
235                         return
236                 }
237                 // Don't complain about deliberate redeclarations of the form
238                 //      var i = i
239                 if idiomaticRedecl(valueSpec) {
240                         return
241                 }
242                 for _, ident := range valueSpec.Names {
243                         checkShadowing(pass, spans, ident)
244                 }
245         }
246 }
247
248 // checkShadowing checks whether the identifier shadows an identifier in an outer scope.
249 func checkShadowing(pass *analysis.Pass, spans map[types.Object]span, ident *ast.Ident) {
250         if ident.Name == "_" {
251                 // Can't shadow the blank identifier.
252                 return
253         }
254         obj := pass.TypesInfo.Defs[ident]
255         if obj == nil {
256                 return
257         }
258         // obj.Parent.Parent is the surrounding scope. If we can find another declaration
259         // starting from there, we have a shadowed identifier.
260         _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos())
261         if shadowed == nil {
262                 return
263         }
264         // Don't complain if it's shadowing a universe-declared identifier; that's fine.
265         if shadowed.Parent() == types.Universe {
266                 return
267         }
268         if strict {
269                 // The shadowed identifier must appear before this one to be an instance of shadowing.
270                 if shadowed.Pos() > ident.Pos() {
271                         return
272                 }
273         } else {
274                 // Don't complain if the span of validity of the shadowed identifier doesn't include
275                 // the shadowing identifier.
276                 span, ok := spans[shadowed]
277                 if !ok {
278                         pass.ReportRangef(ident, "internal error: no range for %q", ident.Name)
279                         return
280                 }
281                 if !span.contains(ident.Pos()) {
282                         return
283                 }
284         }
285         // Don't complain if the types differ: that implies the programmer really wants two different things.
286         if types.Identical(obj.Type(), shadowed.Type()) {
287                 line := pass.Fset.Position(shadowed.Pos()).Line
288                 pass.ReportRangef(ident, "declaration of %q shadows declaration at line %d", obj.Name(), line)
289         }
290 }