.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / 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         if t == nil || v == nil {
45                 // not assertable to, but there is no missing method
46                 return nil
47         }
48         // ensure that v and t are interfaces
49         V, _ := v.Underlying().(*types.Interface)
50         T, _ := t.Underlying().(*types.Interface)
51         if V == nil || T == nil {
52                 return nil
53         }
54         if f, wrongType := types.MissingMethod(V, T, false); wrongType {
55                 return f
56         }
57         return nil
58 }
59
60 func run(pass *analysis.Pass) (interface{}, error) {
61         inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
62         nodeFilter := []ast.Node{
63                 (*ast.TypeAssertExpr)(nil),
64                 (*ast.TypeSwitchStmt)(nil),
65         }
66         inspect.Preorder(nodeFilter, func(n ast.Node) {
67                 var (
68                         assert  *ast.TypeAssertExpr // v.(T) expression
69                         targets []ast.Expr          // interfaces T in v.(T)
70                 )
71                 switch n := n.(type) {
72                 case *ast.TypeAssertExpr:
73                         // take care of v.(type) in *ast.TypeSwitchStmt
74                         if n.Type == nil {
75                                 return
76                         }
77                         assert = n
78                         targets = append(targets, n.Type)
79                 case *ast.TypeSwitchStmt:
80                         // retrieve type assertion from type switch's 'assign' field
81                         switch t := n.Assign.(type) {
82                         case *ast.ExprStmt:
83                                 assert = t.X.(*ast.TypeAssertExpr)
84                         case *ast.AssignStmt:
85                                 assert = t.Rhs[0].(*ast.TypeAssertExpr)
86                         }
87                         // gather target types from case clauses
88                         for _, c := range n.Body.List {
89                                 targets = append(targets, c.(*ast.CaseClause).List...)
90                         }
91                 }
92                 V := pass.TypesInfo.TypeOf(assert.X)
93                 for _, target := range targets {
94                         T := pass.TypesInfo.TypeOf(target)
95                         if f := assertableTo(V, T); f != nil {
96                                 pass.Reportf(
97                                         target.Pos(),
98                                         "impossible type assertion: no type can implement both %v and %v (conflicting types for %v method)",
99                                         V, T, f.Name(),
100                                 )
101                         }
102                 }
103         })
104         return nil, nil
105 }