...
1
2
3
4
5 package ifaceassert
6
7 import (
8 _ "embed"
9 "go/ast"
10 "go/types"
11
12 "golang.org/x/tools/go/analysis"
13 "golang.org/x/tools/go/analysis/passes/inspect"
14 "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
15 "golang.org/x/tools/go/ast/inspector"
16 )
17
18
19 var doc string
20
21 var Analyzer = &analysis.Analyzer{
22 Name: "ifaceassert",
23 Doc: analysisutil.MustExtractDoc(doc, "ifaceassert"),
24 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
25 Requires: []*analysis.Analyzer{inspect.Analyzer},
26 Run: run,
27 }
28
29
30
31 func assertableTo(v, t types.Type) *types.Func {
32 if t == nil || v == nil {
33
34 return nil
35 }
36
37 V, _ := v.Underlying().(*types.Interface)
38 T, _ := t.Underlying().(*types.Interface)
39 if V == nil || T == nil {
40 return nil
41 }
42
43
44
45 if isParameterized(V) || isParameterized(T) {
46 return nil
47 }
48 if f, wrongType := types.MissingMethod(V, T, false); wrongType {
49 return f
50 }
51 return nil
52 }
53
54 func run(pass *analysis.Pass) (interface{}, error) {
55 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
56 nodeFilter := []ast.Node{
57 (*ast.TypeAssertExpr)(nil),
58 (*ast.TypeSwitchStmt)(nil),
59 }
60 inspect.Preorder(nodeFilter, func(n ast.Node) {
61 var (
62 assert *ast.TypeAssertExpr
63 targets []ast.Expr
64 )
65 switch n := n.(type) {
66 case *ast.TypeAssertExpr:
67
68 if n.Type == nil {
69 return
70 }
71 assert = n
72 targets = append(targets, n.Type)
73 case *ast.TypeSwitchStmt:
74
75 switch t := n.Assign.(type) {
76 case *ast.ExprStmt:
77 assert = t.X.(*ast.TypeAssertExpr)
78 case *ast.AssignStmt:
79 assert = t.Rhs[0].(*ast.TypeAssertExpr)
80 }
81
82 for _, c := range n.Body.List {
83 targets = append(targets, c.(*ast.CaseClause).List...)
84 }
85 }
86 V := pass.TypesInfo.TypeOf(assert.X)
87 for _, target := range targets {
88 T := pass.TypesInfo.TypeOf(target)
89 if f := assertableTo(V, T); f != nil {
90 pass.Reportf(
91 target.Pos(),
92 "impossible type assertion: no type can implement both %v and %v (conflicting types for %v method)",
93 V, T, f.Name(),
94 )
95 }
96 }
97 })
98 return nil, nil
99 }
100
View as plain text