diff --git a/fixtures/max-public-structs.go b/fixtures/max-public-structs.go new file mode 100644 index 0000000..abdd3b7 --- /dev/null +++ b/fixtures/max-public-structs.go @@ -0,0 +1,11 @@ +// Package pkg ... +package pkg // MATCH /you have exceeded the maximum number of public struct declarations/ + +type Foo struct { +} + +type Bar struct { +} + +type Baz struct { +} diff --git a/rule/max-public-structs.go b/rule/max-public-structs.go new file mode 100644 index 0000000..638ac28 --- /dev/null +++ b/rule/max-public-structs.go @@ -0,0 +1,69 @@ +package rule + +import ( + "fmt" + "go/ast" + + "strings" + + "github.com/mgechev/revive/lint" +) + +// MaxPublicStructsRule lints given else constructs. +type MaxPublicStructsRule struct{} + +// Apply applies the rule to given file. +func (r *MaxPublicStructsRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { + var failures []lint.Failure + + fileAst := file.AST + walker := &lintMaxPublicStructs{ + fileAst: fileAst, + onFailure: func(failure lint.Failure) { + failures = append(failures, failure) + }, + } + + ast.Walk(walker, fileAst) + + max, ok := arguments[0].(int64) // Alt. non panicking version + if !ok { + panic(`invalid value passed as argument number to the "max-public-structs" rule`) + } + + fmt.Println("Name:", max, walker.current) + if walker.current > max { + walker.onFailure(lint.Failure{ + Failure: "you have exceeded the maximum number of public struct declarations", + Confidence: 1, + Node: fileAst, + Category: "style", + }) + } + + return failures +} + +// Name returns the rule name. +func (r *MaxPublicStructsRule) Name() string { + return "max-public-structs" +} + +type lintMaxPublicStructs struct { + current int64 + fileAst *ast.File + onFailure func(lint.Failure) +} + +func (w *lintMaxPublicStructs) Visit(n ast.Node) ast.Visitor { + switch v := n.(type) { + case *ast.TypeSpec: + name := v.Name.Name + first := string(name[0]) + if strings.ToUpper(first) == first { + w.current++ + } + break + } + return w +} diff --git a/testutil/lint_test.go b/testutil/lint_test.go index 6cce033..3a31ea1 100644 --- a/testutil/lint_test.go +++ b/testutil/lint_test.go @@ -56,7 +56,7 @@ var rules = []lint.Rule{ &rule.ContextArgumentsRule{}, } -func TestVarDeclaration(t *testing.T) { +func TestCyclomatic(t *testing.T) { testRule(t, "cyclomatic", &rule.CyclomaticRule{}, &lint.RuleConfig{ Arguments: []interface{}{int64(1)}, }) @@ -65,6 +65,12 @@ func TestVarDeclaration(t *testing.T) { }) } +func TestMaxPublicStructs(t *testing.T) { + testRule(t, "max-public-structs", &rule.MaxPublicStructsRule{}, &lint.RuleConfig{ + Arguments: []interface{}{int64(1)}, + }) +} + func testRule(t *testing.T, filename string, rule lint.Rule, config ...*lint.RuleConfig) { baseDir := "../fixtures/" filename = filename + ".go" @@ -94,8 +100,9 @@ func TestAll(t *testing.T) { baseDir := "../fixtures/" ignoreFiles := map[string]bool{ - "cyclomatic.go": true, - "cyclomatic-2.go": true, + "cyclomatic.go": true, + "cyclomatic-2.go": true, + "max-public-structs.go": true, } rx, err := regexp.Compile(*lintMatch)