Skip to content

Commit

Permalink
feat: make NewAnalyzer return an error instead of panic
Browse files Browse the repository at this point in the history
Plus a bit of code cleanup and slight optimisations.
  • Loading branch information
xobotyi committed Apr 10, 2022
1 parent 55df32e commit eb118e9
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 30 deletions.
7 changes: 6 additions & 1 deletion cmd/exhaustruct/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@ import (
func main() {
flag.Bool("unsafeptr", false, "")

singlechecker.Main(analyzer.MustNewAnalyzer([]string{}, []string{}))
a, err := analyzer.NewAnalyzer([]string{}, []string{})
if err != nil {
panic(err)
}

singlechecker.Main(a)
}
69 changes: 42 additions & 27 deletions pkg/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ type analyzer struct {
exclude PatternsList
}

// MustNewAnalyzer returns a go/analysis-compatible analyzer.
// NewAnalyzer returns a go/analysis-compatible analyzer.
// -i arguments adds include patterns
// -e arguments adds exclude patterns
func MustNewAnalyzer(include []string, exclude []string) *analysis.Analyzer {
a := analyzer{
include: mustNewPatternsList(include),
exclude: mustNewPatternsList(exclude),
func NewAnalyzer(include []string, exclude []string) (*analysis.Analyzer, error) {
a := analyzer{}

var err error

a.include, err = newPatternsList(include)
if err != nil {
return nil, err
}

a.exclude, err = newPatternsList(exclude)
if err != nil {
return nil, err
}

return &analysis.Analyzer{
Expand All @@ -38,7 +47,7 @@ func MustNewAnalyzer(include []string, exclude []string) *analysis.Analyzer {
Run: a.run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
Flags: a.newFlagSet(),
}
}, nil
}

func (a *analyzer) newFlagSet() flag.FlagSet {
Expand Down Expand Up @@ -194,23 +203,23 @@ func literalKeys(lit *ast.CompositeLit) (keys []string, unnamed bool) {

func structFields(strct *types.Struct, withPrivate bool) (keys []string) {
for i := 0; i < strct.NumFields(); i++ {
fieldName := strct.Field(i).Name()
f := strct.Field(i)

if !withPrivate && !strct.Field(i).Exported() {
if !f.Exported() && !withPrivate {
continue
}

keys = append(keys, fieldName)
keys = append(keys, f.Name())
}

return keys
}

// difference returns elements that are in `a` and not in `b`.
func difference(a, b []string) (diff []string) {
mb := make(map[string]struct{}, len(b))
mb := make(map[string]bool, len(b))
for _, x := range b {
mb[x] = struct{}{}
mb[x] = true
}

for _, x := range a {
Expand All @@ -228,7 +237,6 @@ func exprName(expr ast.Expr) string {
}

s, ok := expr.(*ast.SelectorExpr)

if !ok {
return ""
}
Expand All @@ -249,37 +257,31 @@ func (l PatternsList) MatchesAny(str string) bool {
return false
}

// mustNewPatternsList parses slice of strings to a slice of compiled regular
// newPatternsList parses slice of strings to a slice of compiled regular
// expressions.
func mustNewPatternsList(in []string) (list PatternsList) {
for _, reStr := range in {
if reStr == "" {
panic(ErrEmptyPattern)
}
func newPatternsList(in []string) (PatternsList, error) {
list := PatternsList{}

re, err := regexp.Compile(reStr)
for _, str := range in {
re, err := strToRegexp(str)
if err != nil {
panic(fmt.Errorf("unable to compile %s as regular expression: %w", reStr, err))
return nil, err
}

list = append(list, re)
}

return list
return list, nil
}

type reListVar struct {
values *PatternsList
}

func (v *reListVar) Set(value string) error {
if value == "" {
return ErrEmptyPattern
}

re, err := regexp.Compile(value)
re, err := strToRegexp(value)
if err != nil {
return fmt.Errorf("unable to compile %s as regular expression: %w", value, err)
return err
}

*v.values = append(*v.values, re)
Expand All @@ -290,3 +292,16 @@ func (v *reListVar) Set(value string) error {
func (v *reListVar) String() string {
return ""
}

func strToRegexp(str string) (*regexp.Regexp, error) {
if str == "" {
return nil, ErrEmptyPattern
}

re, err := regexp.Compile(str)
if err != nil {
return nil, fmt.Errorf("unable to compile %s as regular expression: %w", str, err)
}

return re, nil
}
10 changes: 8 additions & 2 deletions pkg/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ func TestAll(t *testing.T) {

testdata := filepath.Join(filepath.Dir(filepath.Dir(wd)), "testdata")

a := analyzer.MustNewAnalyzer(
a, err := analyzer.NewAnalyzer(
[]string{".*\\.Test", ".*\\.Test2", ".*\\.Embedded", ".*\\.External"},
[]string{".*Excluded$"},
)
if err != nil {
t.Error(err)
}

analysistest.Run(t, testdata, a, "s")
}
Expand All @@ -36,10 +39,13 @@ func BenchmarkAll(b *testing.B) {

testdata := filepath.Join(filepath.Dir(filepath.Dir(wd)), "testdata")

a := analyzer.MustNewAnalyzer(
a, err := analyzer.NewAnalyzer(
[]string{".*\\.Test", ".*\\.Test2", ".*\\.Embedded", ".*\\.External"},
[]string{".*Excluded$"},
)
if err != nil {
b.Error(err)
}

for i := 0; i < b.N; i++ {
analysistest.Run(b, testdata, a, "s")
Expand Down

0 comments on commit eb118e9

Please sign in to comment.