package rule import ( "fmt" "go/ast" "strings" "sync" "github.com/mgechev/revive/lint" ) // BannedCharsRule checks if a file contains banned characters. type BannedCharsRule struct { bannedCharList []string sync.Mutex } const bannedCharsRuleName = "banned-characters" func (r *BannedCharsRule) configure(arguments lint.Arguments) { r.Lock() if r.bannedCharList == nil { checkNumberOfArguments(1, arguments, bannedCharsRuleName) r.bannedCharList = r.getBannedCharsList(arguments) } r.Unlock() } // Apply applied the rule to the given file. func (r *BannedCharsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { r.configure(arguments) var failures []lint.Failure onFailure := func(failure lint.Failure) { failures = append(failures, failure) } w := lintBannedCharsRule{ bannedChars: r.bannedCharList, onFailure: onFailure, } ast.Walk(w, file.AST) return failures } // Name returns the rule name func (*BannedCharsRule) Name() string { return bannedCharsRuleName } // getBannedCharsList converts arguments into the banned characters list func (r *BannedCharsRule) getBannedCharsList(args lint.Arguments) []string { var bannedChars []string for _, char := range args { charStr, ok := char.(string) if !ok { panic(fmt.Sprintf("Invalid argument for the %s rule: expecting a string, got %T", r.Name(), char)) } bannedChars = append(bannedChars, charStr) } return bannedChars } type lintBannedCharsRule struct { bannedChars []string onFailure func(lint.Failure) } // Visit checks for each node if an identifier contains banned characters func (w lintBannedCharsRule) Visit(node ast.Node) ast.Visitor { n, ok := node.(*ast.Ident) if !ok { return w } for _, c := range w.bannedChars { ok := strings.Contains(n.Name, c) if ok { w.onFailure(lint.Failure{ Confidence: 1, Failure: fmt.Sprintf("banned character found: %s", c), RuleName: bannedCharsRuleName, Node: n, }) } } return w }