Skip to content

Commit

Permalink
feat: use regular expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Jul 16, 2022
1 parent 22ea7ac commit 6b5f528
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 65 deletions.
59 changes: 30 additions & 29 deletions asasalint.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,62 @@ import (
"go/ast"
"go/token"
"go/types"
"regexp"
"strings"

"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)

const BuiltinExclude = "Print,Printf,Println," +
"Fprint,Fprintf,Fprintln," +
"Sprint,Sprintf,Sprintln," +
"Fatal,Fatalf,Fatalln," +
"Panic,Panicf,Panicln," +
"Error,Errorf,Errorln," +
"Warn,Warnf,Warnln," +
"Warning,Warningf,Warningln," +
"Info,Infof,Infoln," +
"Debug,Debugf,Debugln"
const BuiltinExclusions = `^(Print|Fprint|Sprint|Fatal|Panic|Error|Warn|Warning|Info|Debug)(|f|ln)$`

type LinterSetting struct {
Exclude []string
NoBuiltinExclude bool
IgnoreInTest bool
Exclude []string
NoBuiltinExclusions bool
IgnoreTest bool
}

func NewAnalyzer(setting LinterSetting) *analysis.Analyzer {
a := newAnalyzer(setting)
func NewAnalyzer(setting LinterSetting) (*analysis.Analyzer, error) {
a, err := newAnalyzer(setting)
if err != nil {
return nil, err
}

return &analysis.Analyzer{
Name: "asasalint",
Doc: "check for pass []any as any in variadic func(...any)",
Run: a.run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
}
}, nil
}

type analyzer struct {
excludes map[string]bool
excludes []*regexp.Regexp
setting LinterSetting
}

func newAnalyzer(setting LinterSetting) *analyzer {
func newAnalyzer(setting LinterSetting) (*analyzer, error) {
a := &analyzer{
excludes: make(map[string]bool),
setting: setting,
setting: setting,
}

if !a.setting.NoBuiltinExclude {
for _, exclude := range strings.Split(BuiltinExclude, `,`) {
a.excludes[exclude] = true
}
if !a.setting.NoBuiltinExclusions {
a.excludes = append(a.excludes, regexp.MustCompile(BuiltinExclusions))
}

for _, exclude := range a.setting.Exclude {
if exclude != "" {
a.excludes[exclude] = true
exp, err := regexp.Compile(exclude)
if err != nil {
return nil, err
}

a.excludes = append(a.excludes, exp)
}
}

return a
return a, nil
}

func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) {
Expand All @@ -75,7 +73,7 @@ func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) {

func (a *analyzer) AsCheckVisitor(pass *analysis.Pass) func(ast.Node) {
return func(n ast.Node) {
if a.setting.IgnoreInTest {
if a.setting.IgnoreTest {
pos := pass.Fset.Position(n.Pos())
if strings.HasSuffix(pos.Filename, "_test.go") {
return
Expand All @@ -94,8 +92,11 @@ func (a *analyzer) AsCheckVisitor(pass *analysis.Pass) func(ast.Node) {
}

fnName := getFuncName(caller)
if a.excludes[fnName] {
return

for _, exclude := range a.excludes {
if exclude.MatchString(fnName) {
return
}
}

fnType := pass.TypesInfo.TypeOf(caller.Fun)
Expand Down
56 changes: 35 additions & 21 deletions asasalint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,43 @@ func (a *A) hello2(a int, b int) {
})
}

func TestNewAnalyzer(t *testing.T) {
_ = NewAnalyzer(LinterSetting{})
_ = NewAnalyzer(LinterSetting{
Exclude: []string{"hello"},
NoBuiltinExclude: true,
IgnoreInTest: true,
})
}

func TestAnalyzer(t *testing.T) {
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), NewAnalyzer(LinterSetting{}), "basic")
}

func TestAnalyzer_custom_NoBuiltinExclude(t *testing.T) {
setting := LinterSetting{
NoBuiltinExclude: true,
testCases := []struct {
desc string
settings LinterSetting
}{
{
desc: "basic",
settings: LinterSetting{},
},
{
desc: "nobuiltin",
settings: LinterSetting{
NoBuiltinExclusions: true,
},
},
{
desc: "ignoretest",
settings: LinterSetting{
IgnoreTest: true,
},
},
{
desc: "custom",
settings: LinterSetting{
Exclude: []string{"get.+"},
},
},
}
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), NewAnalyzer(setting), "nobuiltin")
}

func TestAnalyzer_custom_IgnoreInTest(t *testing.T) {
setting := LinterSetting{
IgnoreInTest: true,
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
a, err := NewAnalyzer(test.settings)
if err != nil {
t.Fatal(err)
}

analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), a, test.desc)
})
}
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), NewAnalyzer(setting), "ignoretest")
}
34 changes: 19 additions & 15 deletions cmd/asasalint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"flag"
"log"
"strings"

"github.com/alingse/asasalint"
Expand All @@ -10,23 +11,26 @@ import (

func main() {
var extraExclude string
var noBuiltinExclude bool
var ignoreInTest bool
flag.StringVar(&extraExclude,
"e",
"",
"extra exclude func names, like: FuncA,append,Append",
)
flag.BoolVar(&noBuiltinExclude, "no-builtin-exclude", false,
"disbale the builtin exclude func names: "+asasalint.BuiltinExclude)
flag.BoolVar(&ignoreInTest, "ignore-in-test", false,
"ingore case in *_test.go")
var noBuiltinExclusions bool
var ignoreTest bool
flag.StringVar(&extraExclude, "e", "",
"Extra exclusions func names. It can be regular expressions. ex: FuncA,(A|a)ppend")
flag.BoolVar(&noBuiltinExclusions, "no-builtin-exclude", false,
"Disable the builtin exclusions func names: "+asasalint.BuiltinExclusions)
flag.BoolVar(&ignoreTest, "ignore-test", false,
"Ignore test files (*_test.go)")
flag.Parse()

setting := asasalint.LinterSetting{
Exclude: strings.Split(extraExclude, ","),
NoBuiltinExclude: noBuiltinExclude,
IgnoreInTest: ignoreInTest,
Exclude: strings.Split(extraExclude, ","),
NoBuiltinExclusions: noBuiltinExclusions,
IgnoreTest: ignoreTest,
}
singlechecker.Main(asasalint.NewAnalyzer(setting))

analyzer, err := asasalint.NewAnalyzer(setting)
if err != nil {
log.Fatal(err)
}

singlechecker.Main(analyzer)
}
71 changes: 71 additions & 0 deletions testdata/src/custom/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

type Logger interface {
Debug(args ...interface{})
Debugf(format string, args ...interface{})
Debugln(args ...interface{})

Info(args ...interface{})
Infof(format string, args ...interface{})
Infoln(args ...interface{})

Print(args ...interface{})
Printf(format string, args ...interface{})
Println(args ...interface{})

Warn(args ...interface{})
Warnf(format string, args ...interface{})
Warnln(args ...interface{})

Warning(args ...interface{})
Warningf(format string, args ...interface{})
Warningln(args ...interface{})

Error(args ...interface{})
Errorf(format string, args ...interface{})
Errorln(args ...interface{})

Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Fatalln(args ...interface{})

Panic(args ...interface{})
Panicf(format string, args ...interface{})
Panicln(args ...interface{})
}

func fromLogger(l Logger) {
var a = []any{1, 2, 3}

l.Debug(a)
l.Debugf("%v", a)
l.Debugln(a)

l.Info(a)
l.Infof("%v", a)
l.Infoln(a)

l.Print(a)
l.Printf("%v", a)
l.Println(a)

l.Warn(a)
l.Warnf("%v", a)
l.Warnln(a)

l.Warning(a)
l.Warningf("%v", a)
l.Warningln(a)

l.Error(a)
l.Errorf("%v", a)
l.Errorln(a)

l.Fatal(a)
l.Fatalf("%v", a)
l.Fatalln(a)

l.Panic(a)
l.Panicf("%v", a)
l.Panicln(a)
}
41 changes: 41 additions & 0 deletions testdata/src/custom/logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import "testing"

func TestLogger(t *testing.T) {
var l Logger

var a = []any{1, 2, 3}

l.Debug(a)
l.Debugf("%v", a)
l.Debugln(a)

l.Info(a)
l.Infof("%v", a)
l.Infoln(a)

l.Print(a)
l.Printf("%v", a)
l.Println(a)

l.Warn(a)
l.Warnf("%v", a)
l.Warnln(a)

l.Warning(a)
l.Warningf("%v", a)
l.Warningln(a)

l.Error(a)
l.Errorf("%v", a)
l.Errorln(a)

l.Fatal(a)
l.Fatalf("%v", a)
l.Fatalln(a)

l.Panic(a)
l.Panicf("%v", a)
l.Panicln(a)
}
22 changes: 22 additions & 0 deletions testdata/src/custom/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

func main() {
var a = []any{1, 2, 3}

getArgsLength(a)
getArgsLength(a...)
getArgsLength(1, 2, 3)
getArgsLength([]any{1, 2, 3})
getArgsLength(append([]any{1, 2, 3}, 4, 5, 6))

getOneOrMore(a)
getOneOrMore(1, a)
}

func getArgsLength(args ...any) int {
return len(args)
}

func getOneOrMore(arg any, others ...any) int {
return len(append([]any{arg}, others...))
}
16 changes: 16 additions & 0 deletions testdata/src/custom/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import "testing"

func TestSimple(t *testing.T) {
var a = []any{1, 2, 3}

getArgsLength(a)
getArgsLength(a...)
getArgsLength(1, 2, 3)
getArgsLength([]any{1, 2, 3})
getArgsLength(append([]any{1, 2, 3}, 4, 5, 6))

getOneOrMore(a)
getOneOrMore(1, a)
}
Loading

0 comments on commit 6b5f528

Please sign in to comment.