|
- package rule
-
- import (
- "fmt"
- "github.com/mgechev/revive/lint"
- "go/ast"
- "go/token"
- )
-
- // RedefinesBuiltinIDRule warns when a builtin identifier is shadowed.
- type RedefinesBuiltinIDRule struct{}
-
- // Apply applies the rule to given file.
- func (r *RedefinesBuiltinIDRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
-
- var builtInConstAndVars = map[string]bool{
- "true": true,
- "false": true,
- "iota": true,
- "nil": true,
- }
-
- var builtFunctions = map[string]bool{
- "append": true,
- "cap": true,
- "close": true,
- "complex": true,
- "copy": true,
- "delete": true,
- "imag": true,
- "len": true,
- "make": true,
- "new": true,
- "panic": true,
- "print": true,
- "println": true,
- "real": true,
- "recover": true,
- }
-
- var builtInTypes = map[string]bool{
- "ComplexType": true,
- "FloatType": true,
- "IntegerType": true,
- "Type": true,
- "Type1": true,
- "bool": true,
- "byte": true,
- "complex128": true,
- "complex64": true,
- "error": true,
- "float32": true,
- "float64": true,
- "int": true,
- "int16": true,
- "int32": true,
- "int64": true,
- "int8": true,
- "rune": true,
- "string": true,
- "uint": true,
- "uint16": true,
- "uint32": true,
- "uint64": true,
- "uint8": true,
- "uintptr": true,
- }
-
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- astFile := file.AST
- w := &lintRedefinesBuiltinID{builtInConstAndVars, builtFunctions, builtInTypes, onFailure}
- ast.Walk(w, astFile)
-
- return failures
- }
-
- // Name returns the rule name.
- func (r *RedefinesBuiltinIDRule) Name() string {
- return "redefines-builtin-id"
- }
-
- type lintRedefinesBuiltinID struct {
- constsAndVars map[string]bool
- funcs map[string]bool
- types map[string]bool
- onFailure func(lint.Failure)
- }
-
- func (w *lintRedefinesBuiltinID) Visit(node ast.Node) ast.Visitor {
- switch n := node.(type) {
- case *ast.GenDecl:
- if n.Tok != token.TYPE {
- return nil // skip if not type declaration
- }
- typeSpec, ok := n.Specs[0].(*ast.TypeSpec)
- if !ok {
- return nil
- }
- id := typeSpec.Name.Name
- if w.types[id] {
- w.addFailure(n, fmt.Sprintf("redefinition of the built-in type %s", id))
- }
- case *ast.FuncDecl:
- if n.Recv != nil {
- return w // skip methods
- }
-
- id := n.Name.Name
- if w.funcs[id] {
- w.addFailure(n, fmt.Sprintf("redefinition of the built-in function %s", id))
- }
- case *ast.AssignStmt:
- for _, e := range n.Lhs {
- id, ok := e.(*ast.Ident)
- if !ok {
- continue
- }
-
- if w.constsAndVars[id.Name] {
- var msg string
- if n.Tok == token.DEFINE {
- msg = fmt.Sprintf("assignment creates a shadow of built-in identifier %s", id.Name)
- } else {
- msg = fmt.Sprintf("assignment modifies built-in identifier %s", id.Name)
- }
- w.addFailure(n, msg)
- }
- }
- }
-
- return w
- }
-
- func (w lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) {
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: node,
- Category: "logic",
- Failure: msg,
- })
- }
|