mirror of
https://github.com/mgechev/revive.git
synced 2025-11-25 22:12:38 +02:00
Implement initial basic version of enabling/disabling rules
This commit is contained in:
@@ -27,6 +27,11 @@ func (r *LintElseRule) Apply(file *file.File, arguments rule.Arguments) []rule.F
|
|||||||
return res.GetFailures()
|
return res.GetFailures()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetName returns the rule name.
|
||||||
|
func (r *LintElseRule) GetName() string {
|
||||||
|
return ruleName
|
||||||
|
}
|
||||||
|
|
||||||
type lintElseVisitor struct {
|
type lintElseVisitor struct {
|
||||||
visitor.RuleVisitor
|
visitor.RuleVisitor
|
||||||
}
|
}
|
||||||
|
|||||||
114
linter/linter.go
114
linter/linter.go
@@ -1,7 +1,11 @@
|
|||||||
package linter
|
package linter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/mgechev/revive/file"
|
"github.com/mgechev/revive/file"
|
||||||
"github.com/mgechev/revive/rule"
|
"github.com/mgechev/revive/rule"
|
||||||
@@ -10,7 +14,7 @@ import (
|
|||||||
// ReadFile defines an abstraction for reading files.
|
// ReadFile defines an abstraction for reading files.
|
||||||
type ReadFile func(path string) (result []byte, err error)
|
type ReadFile func(path string) (result []byte, err error)
|
||||||
|
|
||||||
// Linter is used for lintign set of files.
|
// Linter is used for linting set of files.
|
||||||
type Linter struct {
|
type Linter struct {
|
||||||
reader ReadFile
|
reader ReadFile
|
||||||
}
|
}
|
||||||
@@ -24,13 +28,17 @@ func New(reader ReadFile) Linter {
|
|||||||
func (l *Linter) Lint(filenames []string, ruleSet []rule.Rule) ([]rule.Failure, error) {
|
func (l *Linter) Lint(filenames []string, ruleSet []rule.Rule) ([]rule.Failure, error) {
|
||||||
var fileSet token.FileSet
|
var fileSet token.FileSet
|
||||||
var failures []rule.Failure
|
var failures []rule.Failure
|
||||||
|
var ruleNames = []string{}
|
||||||
|
for _, r := range ruleSet {
|
||||||
|
ruleNames = append(ruleNames, r.GetName())
|
||||||
|
}
|
||||||
for _, filename := range filenames {
|
for _, filename := range filenames {
|
||||||
content, err := l.reader(filename)
|
content, err := l.reader(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
file, err := file.New(filename, content, &fileSet)
|
file, err := file.New(filename, content, &fileSet)
|
||||||
disabledIntervals := l.disabledIntervals(file)
|
disabledIntervals := l.disabledIntervals(file, ruleNames)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -46,8 +54,106 @@ func (l *Linter) Lint(filenames []string, ruleSet []rule.Rule) ([]rule.Failure,
|
|||||||
return failures, nil
|
return failures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Linter) disabledIntervals(file *file.File) []rule.DisabledInterval {
|
type enableDisableConfig struct {
|
||||||
return nil
|
enabled bool
|
||||||
|
position int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Linter) disabledIntervals(file *file.File, allRuleNames []string) []rule.DisabledInterval {
|
||||||
|
re := regexp.MustCompile(`^\s*revive:(enable|disable)(?:-(line|next-line))?(:|\s|$)`)
|
||||||
|
|
||||||
|
enabledDisabledRulesMap := make(map[string][]enableDisableConfig)
|
||||||
|
|
||||||
|
getEnabledDisabledIntervals := func() []rule.DisabledInterval {
|
||||||
|
var result []rule.DisabledInterval
|
||||||
|
|
||||||
|
for ruleName, disabledArr := range enabledDisabledRulesMap {
|
||||||
|
for i := 0; i < len(disabledArr); i++ {
|
||||||
|
interval := rule.DisabledInterval{
|
||||||
|
RuleName: ruleName,
|
||||||
|
From: token.Position{
|
||||||
|
Filename: file.Name,
|
||||||
|
Line: disabledArr[i].position,
|
||||||
|
},
|
||||||
|
To: token.Position{
|
||||||
|
Filename: file.Name,
|
||||||
|
Line: math.MaxInt32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if i%2 == 0 {
|
||||||
|
result = append(result, interval)
|
||||||
|
} else {
|
||||||
|
result[len(result)-1].To.Line = disabledArr[i].position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
handleConfig := func(isEnabled bool, line int, name string) {
|
||||||
|
existing, ok := enabledDisabledRulesMap[name]
|
||||||
|
if !ok {
|
||||||
|
existing = []enableDisableConfig{}
|
||||||
|
enabledDisabledRulesMap[name] = existing
|
||||||
|
}
|
||||||
|
if (len(existing) > 1 && existing[len(existing)-1].enabled == isEnabled) ||
|
||||||
|
(len(existing) == 0 && isEnabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
existing = append(existing, enableDisableConfig{
|
||||||
|
enabled: isEnabled,
|
||||||
|
position: line,
|
||||||
|
})
|
||||||
|
enabledDisabledRulesMap[name] = existing
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRules := func(filename, modifier string, isEnabled bool, line int, ruleNames []string) []rule.DisabledInterval {
|
||||||
|
var result []rule.DisabledInterval
|
||||||
|
for _, name := range ruleNames {
|
||||||
|
if modifier == "line" {
|
||||||
|
handleConfig(!isEnabled, line, name)
|
||||||
|
handleConfig(isEnabled, line, name)
|
||||||
|
} else if modifier == "next-line" {
|
||||||
|
handleConfig(!isEnabled, line+1, name)
|
||||||
|
handleConfig(isEnabled, line+1, name)
|
||||||
|
} else {
|
||||||
|
handleConfig(isEnabled, line, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
handleComment := func(filename string, c *ast.CommentGroup, line int) {
|
||||||
|
text := c.Text()
|
||||||
|
parts := re.FindStringSubmatch(text)
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
str := re.FindString(text)
|
||||||
|
ruleNamesString := strings.Split(text, str)
|
||||||
|
ruleNames := []string{}
|
||||||
|
if len(ruleNamesString) == 2 {
|
||||||
|
tempNames := strings.Split(ruleNamesString[1], ",")
|
||||||
|
for _, name := range tempNames {
|
||||||
|
if len(name) > 0 {
|
||||||
|
ruleNames = append(ruleNames, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ruleNames) == 0 {
|
||||||
|
ruleNames = allRuleNames
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRules(filename, parts[2], parts[1] == "enable", line, ruleNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
comments := file.GetAST().Comments
|
||||||
|
for _, c := range comments {
|
||||||
|
handleComment(file.Name, c, file.ToPosition(c.Pos()).Line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getEnabledDisabledIntervals()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Linter) filterFailures(failures []rule.Failure, disabledIntervals []rule.DisabledInterval) []rule.Failure {
|
func (l *Linter) filterFailures(failures []rule.Failure, disabledIntervals []rule.DisabledInterval) []rule.Failure {
|
||||||
|
|||||||
3
main.go
3
main.go
@@ -12,6 +12,7 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
src := `
|
src := `
|
||||||
package p
|
package p
|
||||||
|
// revive:disable
|
||||||
|
|
||||||
func Test() {
|
func Test() {
|
||||||
if true {
|
if true {
|
||||||
@@ -28,7 +29,7 @@ func main() {
|
|||||||
var result []rule.Rule
|
var result []rule.Rule
|
||||||
result = append(result, &defaultrule.LintElseRule{})
|
result = append(result, &defaultrule.LintElseRule{})
|
||||||
|
|
||||||
failures, err := linter.Lint([]string{"foo.go", "bar.go", "baz.go"}, result)
|
failures, err := linter.Lint([]string{"foo.go" /*, "bar.go", "baz.go"*/}, result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,5 +52,6 @@ type Config struct {
|
|||||||
|
|
||||||
// Rule defines an abstract rule.
|
// Rule defines an abstract rule.
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
|
GetName() string
|
||||||
Apply(file *file.File, args Arguments) []Failure
|
Apply(file *file.File, args Arguments) []Failure
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user