github.com/prysmaticlabs/prysm@v1.4.4/tools/analyzers/shadowpredecl/analyzer.go (about) 1 // Package shadowpredecl implements a static analyzer which disallows declaring constructs 2 // that shadow predeclared Go identifiers by having the same name. 3 package shadowpredecl 4 5 import ( 6 "errors" 7 "go/ast" 8 "go/token" 9 10 "golang.org/x/tools/go/analysis" 11 "golang.org/x/tools/go/analysis/passes/inspect" 12 "golang.org/x/tools/go/ast/inspector" 13 ) 14 15 // Doc explaining the tool. 16 const Doc = "Tool to detect declarations that shadow predeclared identifiers by having the same name." 17 18 const messageTemplate = "%s '%s' shadows a predeclared identifier with the same name. Choose another name." 19 20 // Aligned with https://golang.org/ref/spec#Predeclared_identifiers 21 var predeclared = []string{"bool", "byte", "complex64", "complex128", "error", "float32", "float64", "int", "int8", 22 "int16", "int32", "int64", "rune", "string", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "true", 23 "false", "iota", "nil", "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", 24 "panic", "print", "println", "real", "recover"} 25 26 // Analyzer runs static analysis. 27 var Analyzer = &analysis.Analyzer{ 28 Name: "shadowpredecl", 29 Doc: Doc, 30 Requires: []*analysis.Analyzer{inspect.Analyzer}, 31 Run: run, 32 } 33 34 func run(pass *analysis.Pass) (interface{}, error) { 35 inspection, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 36 if !ok { 37 return nil, errors.New("analyzer is not type *inspector.Inspector") 38 } 39 40 nodeFilter := []ast.Node{ 41 (*ast.FuncDecl)(nil), 42 (*ast.FuncLit)(nil), 43 (*ast.AssignStmt)(nil), 44 (*ast.TypeSpec)(nil), 45 (*ast.ValueSpec)(nil), 46 } 47 48 inspection.Preorder(nodeFilter, func(node ast.Node) { 49 switch declaration := node.(type) { 50 case *ast.FuncDecl: 51 if declaration.Recv != nil { 52 return 53 } 54 name := declaration.Name.Name 55 if shadows(name) { 56 pass.Reportf(declaration.Name.NamePos, messageTemplate, "Function", name) 57 } 58 inspectFunctionParams(pass, declaration.Type.Params.List) 59 case *ast.FuncLit: 60 inspectFunctionParams(pass, declaration.Type.Params.List) 61 case *ast.AssignStmt: 62 if declaration.Tok == token.ASSIGN { 63 return 64 } 65 for _, expr := range declaration.Lhs { 66 if identifier, ok := expr.(*ast.Ident); ok { 67 name := identifier.Name 68 if shadows(name) { 69 pass.Reportf(identifier.NamePos, messageTemplate, "Identifier", name) 70 } 71 } 72 } 73 case *ast.TypeSpec: 74 name := declaration.Name.Name 75 if shadows(name) { 76 pass.Reportf(declaration.Name.NamePos, messageTemplate, "Type", name) 77 } 78 case *ast.ValueSpec: 79 for _, identifier := range declaration.Names { 80 name := identifier.Name 81 if shadows(name) { 82 pass.Reportf(identifier.NamePos, messageTemplate, "Identifier", name) 83 } 84 } 85 } 86 }) 87 88 return nil, nil 89 } 90 91 func inspectFunctionParams(pass *analysis.Pass, paramList []*ast.Field) { 92 for _, field := range paramList { 93 for _, identifier := range field.Names { 94 name := identifier.Name 95 if shadows(name) { 96 pass.Reportf(identifier.NamePos, messageTemplate, "Identifier", name) 97 } 98 } 99 } 100 } 101 102 func shadows(name string) bool { 103 for _, identifier := range predeclared { 104 if identifier == name { 105 return true 106 } 107 } 108 return false 109 }