mirror of
				https://github.com/mgechev/revive.git
				synced 2025-10-30 23:37:49 +02:00 
			
		
		
		
	redefines-builtin-id (new rule) (#60)
This commit is contained in:
		| @@ -267,6 +267,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a | ||||
| | `modifies-value-receiver` |  n/a   | Warns on assignments to value-passed method receivers        |    no    |  yes  | | ||||
| | `constant-logical-expr`   |  n/a   | Warns on constant logical expressions                        |    no    |  no   | | ||||
| | `bool-literal-in-expr`|  n/a   | Suggests removing Boolean literals from logic expressions        |    no    |  no   | | ||||
| | `redefines-builtin-id`|  n/a   | Warns on redefinitions of builtin identifiers                    |    no    |  no   | | ||||
|  | ||||
| ## Available Formatters | ||||
|  | ||||
|   | ||||
| @@ -63,6 +63,7 @@ var allRules = append([]lint.Rule{ | ||||
| 	&rule.ModifiesValRecRule{}, | ||||
| 	&rule.ConstantLogicalExprRule{}, | ||||
| 	&rule.BoolLiteralRule{}, | ||||
| 	&rule.RedefinesBuiltinIDRule{}, | ||||
| }, defaultRules...) | ||||
|  | ||||
| var allFormatters = []lint.Formatter{ | ||||
|   | ||||
							
								
								
									
										21
									
								
								fixtures/redefines-builtin-id.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								fixtures/redefines-builtin-id.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| package fixtures | ||||
|  | ||||
| func (this data) vmethod() { | ||||
| 	nil := true // MATCH /assignment creates a shadow of built-in identifier nil/ | ||||
| 	iota = 1    // MATCH /assignment modifies built-in identifier iota/ | ||||
| } | ||||
|  | ||||
| func append(i, j int) { // MATCH /redefinition of the built-in function append/ | ||||
|  | ||||
| } | ||||
|  | ||||
| type Type int16 // MATCH /redefinition of the built-in type Type/ | ||||
|  | ||||
| func delete(set []int64, i int) (y []int64) { // MATCH /redefinition of the built-in function delete/ | ||||
| 	for j, v := range set { | ||||
| 		if j != i { | ||||
| 			y = append(y, v) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										145
									
								
								rule/redefines-builtin-id.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								rule/redefines-builtin-id.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| 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, arguments 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, | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										12
									
								
								test/redefines-builtin-id_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/redefines-builtin-id_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| package test | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/mgechev/revive/rule" | ||||
| ) | ||||
|  | ||||
| // Tests RedefinesBuiltinID rule. | ||||
| func TestRedefinesBuiltinID(t *testing.T) { | ||||
| 	testRule(t, "redefines-builtin-id", &rule.RedefinesBuiltinIDRule{}) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user