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  }