golang.org/x/tools@v0.21.0/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go (about) 1 // Copyright 2021 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 reflectvaluecompare 6 7 import ( 8 _ "embed" 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/analysis/passes/internal/analysisutil" 16 "golang.org/x/tools/go/ast/inspector" 17 "golang.org/x/tools/go/types/typeutil" 18 ) 19 20 //go:embed doc.go 21 var doc string 22 23 var Analyzer = &analysis.Analyzer{ 24 Name: "reflectvaluecompare", 25 Doc: analysisutil.MustExtractDoc(doc, "reflectvaluecompare"), 26 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/reflectvaluecompare", 27 Requires: []*analysis.Analyzer{inspect.Analyzer}, 28 Run: run, 29 } 30 31 func run(pass *analysis.Pass) (interface{}, error) { 32 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 33 34 nodeFilter := []ast.Node{ 35 (*ast.BinaryExpr)(nil), 36 (*ast.CallExpr)(nil), 37 } 38 inspect.Preorder(nodeFilter, func(n ast.Node) { 39 switch n := n.(type) { 40 case *ast.BinaryExpr: 41 if n.Op != token.EQL && n.Op != token.NEQ { 42 return 43 } 44 if isReflectValue(pass, n.X) || isReflectValue(pass, n.Y) { 45 if n.Op == token.EQL { 46 pass.ReportRangef(n, "avoid using == with reflect.Value") 47 } else { 48 pass.ReportRangef(n, "avoid using != with reflect.Value") 49 } 50 } 51 case *ast.CallExpr: 52 fn, _ := typeutil.Callee(pass.TypesInfo, n).(*types.Func) 53 if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && (isReflectValue(pass, n.Args[0]) || isReflectValue(pass, n.Args[1])) { 54 pass.ReportRangef(n, "avoid using reflect.DeepEqual with reflect.Value") 55 } 56 } 57 }) 58 return nil, nil 59 } 60 61 // isReflectValue reports whether the type of e is reflect.Value. 62 func isReflectValue(pass *analysis.Pass, e ast.Expr) bool { 63 tv, ok := pass.TypesInfo.Types[e] 64 if !ok { // no type info, something else is wrong 65 return false 66 } 67 // See if the type is reflect.Value 68 if !analysisutil.IsNamedType(tv.Type, "reflect", "Value") { 69 return false 70 } 71 if _, ok := e.(*ast.CompositeLit); ok { 72 // This is reflect.Value{}. Don't treat that as an error. 73 // Users should probably use x.IsValid() rather than x == reflect.Value{}, but the latter isn't wrong. 74 return false 75 } 76 return true 77 }