mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			146 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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,
 | 
						|
	})
 | 
						|
}
 |