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 / ifaceassert / ifaceassert.go
1 // Copyright 2020 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 ifaceassert defines an Analyzer that flags
6 // impossible interface-interface type assertions.
7 package ifaceassert
8
9 import (
10         "go/ast"
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 const Doc = `detect impossible interface-to-interface type assertions
19
20 This checker flags type assertions v.(T) and corresponding type-switch cases
21 in which the static type V of v is an interface that cannot possibly implement
22 the target interface T. This occurs when V and T contain methods with the same
23 name but different signatures. Example:
24
25         var v interface {
26                 Read()
27         }
28         _ = v.(io.Reader)
29
30 The Read method in v has a different signature than the Read method in
31 io.Reader, so this assertion cannot succeed.
32 `
33
34 var Analyzer = &analysis.Analyzer{
35         Name:     "ifaceassert",
36         Doc:      Doc,
37         Requires: []*analysis.Analyzer{inspect.Analyzer},
38         Run:      run,
39 }
40
41 // assertableTo checks whether interface v can be asserted into t. It returns
42 // nil on success, or the first conflicting method on failure.
43 func assertableTo(v, t types.Type) *types.Func {
44         // ensure that v and t are interfaces
45         V, _ := v.Underlying().(*types.Interface)
46         T, _ := t.Underlying().(*types.Interface)
47         if V == nil || T == nil {
48                 return nil
49         }
50         if f, wrongType := types.MissingMethod(V, T, false); wrongType {
51                 return f
52         }
53         return nil
54 }
55
56 func run(pass *analysis.Pass) (interface{}, error) {
57         inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
58         nodeFilter := []ast.Node{
59                 (*ast.TypeAssertExpr)(nil),
60                 (*ast.TypeSwitchStmt)(nil),
61         }
62         inspect.Preorder(nodeFilter, func(n ast.Node) {
63                 var (
64                         assert  *ast.TypeAssertExpr // v.(T) expression
65                         targets []ast.Expr          // interfaces T in v.(T)
66                 )
67                 switch n := n.(type) {
68                 case *ast.TypeAssertExpr:
69                         // take care of v.(type) in *ast.TypeSwitchStmt
70                         if n.Type == nil {
71                                 return
72                         }
73                         assert = n
74                         targets = append(targets, n.Type)
75                 case *ast.TypeSwitchStmt:
76                         // retrieve type assertion from type switch's 'assign' field
77                         switch t := n.Assign.(type) {
78                         case *ast.ExprStmt:
79                                 assert = t.X.(*ast.TypeAssertExpr)
80                         case *ast.AssignStmt:
81                                 assert = t.Rhs[0].(*ast.TypeAssertExpr)
82                         }
83                         // gather target types from case clauses
84                         for _, c := range n.Body.List {
85                                 targets = append(targets, c.(*ast.CaseClause).List...)
86                         }
87                 }
88                 V := pass.TypesInfo.TypeOf(assert.X)
89                 for _, target := range targets {
90                         T := pass.TypesInfo.TypeOf(target)
91                         if f := assertableTo(V, T); f != nil {
92                                 pass.Reportf(
93                                         target.Pos(),
94                                         "impossible type assertion: no type can implement both %v and %v (conflicting types for %v method)",
95                                         V, T, f.Name(),
96                                 )
97                         }
98                 }
99         })
100         return nil, nil
101 }