github.com/Johnny2210/revive@v1.0.8-0.20210625134200-febf37ccd0f5/rule/redefines-builtin-id.go (about)

     1  package rule
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/mgechev/revive/lint"
     6  	"go/ast"
     7  	"go/token"
     8  )
     9  
    10  // RedefinesBuiltinIDRule warns when a builtin identifier is shadowed.
    11  type RedefinesBuiltinIDRule struct{}
    12  
    13  // Apply applies the rule to given file.
    14  func (r *RedefinesBuiltinIDRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    15  	var failures []lint.Failure
    16  
    17  	var builtInConstAndVars = map[string]bool{
    18  		"true":  true,
    19  		"false": true,
    20  		"iota":  true,
    21  		"nil":   true,
    22  	}
    23  
    24  	var builtFunctions = map[string]bool{
    25  		"append":  true,
    26  		"cap":     true,
    27  		"close":   true,
    28  		"complex": true,
    29  		"copy":    true,
    30  		"delete":  true,
    31  		"imag":    true,
    32  		"len":     true,
    33  		"make":    true,
    34  		"new":     true,
    35  		"panic":   true,
    36  		"print":   true,
    37  		"println": true,
    38  		"real":    true,
    39  		"recover": true,
    40  	}
    41  
    42  	var builtInTypes = map[string]bool{
    43  		"ComplexType": true,
    44  		"FloatType":   true,
    45  		"IntegerType": true,
    46  		"Type":        true,
    47  		"Type1":       true,
    48  		"bool":        true,
    49  		"byte":        true,
    50  		"complex128":  true,
    51  		"complex64":   true,
    52  		"error":       true,
    53  		"float32":     true,
    54  		"float64":     true,
    55  		"int":         true,
    56  		"int16":       true,
    57  		"int32":       true,
    58  		"int64":       true,
    59  		"int8":        true,
    60  		"rune":        true,
    61  		"string":      true,
    62  		"uint":        true,
    63  		"uint16":      true,
    64  		"uint32":      true,
    65  		"uint64":      true,
    66  		"uint8":       true,
    67  		"uintptr":     true,
    68  	}
    69  
    70  	onFailure := func(failure lint.Failure) {
    71  		failures = append(failures, failure)
    72  	}
    73  
    74  	astFile := file.AST
    75  	w := &lintRedefinesBuiltinID{builtInConstAndVars, builtFunctions, builtInTypes, onFailure}
    76  	ast.Walk(w, astFile)
    77  
    78  	return failures
    79  }
    80  
    81  // Name returns the rule name.
    82  func (r *RedefinesBuiltinIDRule) Name() string {
    83  	return "redefines-builtin-id"
    84  }
    85  
    86  type lintRedefinesBuiltinID struct {
    87  	constsAndVars map[string]bool
    88  	funcs         map[string]bool
    89  	types         map[string]bool
    90  	onFailure     func(lint.Failure)
    91  }
    92  
    93  func (w *lintRedefinesBuiltinID) Visit(node ast.Node) ast.Visitor {
    94  	switch n := node.(type) {
    95  	case *ast.GenDecl:
    96  		if n.Tok != token.TYPE {
    97  			return nil // skip if not type declaration
    98  		}
    99  		typeSpec, ok := n.Specs[0].(*ast.TypeSpec)
   100  		if !ok {
   101  			return nil
   102  		}
   103  		id := typeSpec.Name.Name
   104  		if w.types[id] {
   105  			w.addFailure(n, fmt.Sprintf("redefinition of the built-in type %s", id))
   106  		}
   107  	case *ast.FuncDecl:
   108  		if n.Recv != nil {
   109  			return w // skip methods
   110  		}
   111  
   112  		id := n.Name.Name
   113  		if w.funcs[id] {
   114  			w.addFailure(n, fmt.Sprintf("redefinition of the built-in function %s", id))
   115  		}
   116  	case *ast.AssignStmt:
   117  		for _, e := range n.Lhs {
   118  			id, ok := e.(*ast.Ident)
   119  			if !ok {
   120  				continue
   121  			}
   122  
   123  			if w.constsAndVars[id.Name] {
   124  				var msg string
   125  				if n.Tok == token.DEFINE {
   126  					msg = fmt.Sprintf("assignment creates a shadow of built-in identifier %s", id.Name)
   127  				} else {
   128  					msg = fmt.Sprintf("assignment modifies built-in identifier %s", id.Name)
   129  				}
   130  				w.addFailure(n, msg)
   131  			}
   132  		}
   133  	}
   134  
   135  	return w
   136  }
   137  
   138  func (w lintRedefinesBuiltinID) addFailure(node ast.Node, msg string) {
   139  	w.onFailure(lint.Failure{
   140  		Confidence: 1,
   141  		Node:       node,
   142  		Category:   "logic",
   143  		Failure:    msg,
   144  	})
   145  }