github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/redefines-builtin-id.go (about)

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