From 1dede233c074e8d352b5ad5ca5b7f733b27288f3 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Tue, 25 Oct 2022 20:10:43 +0200 Subject: [PATCH 1/4] support import aliases It was possible to use fmt.Print by importing "fmt" under a different name. Now a pattern can get matched against the full package path instead of the import name. This is also useful to ban items from packages that may get imported under various different names. --- README.md | 24 +++-- forbidigo/forbidigo.go | 57 ++++++++++-- forbidigo/forbidigo_test.go | 93 +++++++++++++++++-- forbidigo/patterns.go | 14 ++- forbidigo/patterns_test.go | 13 ++- main.go | 9 +- pkg/analyzer/analyzer.go | 3 +- pkg/analyzer/analyzer_test.go | 9 ++ pkg/analyzer/testdata/forbidden.go | 16 +++- .../testdata/src/example.com/some/pkg/pkg.go | 4 + 10 files changed, 211 insertions(+), 31 deletions(-) create mode 100644 pkg/analyzer/testdata/src/example.com/some/pkg/pkg.go diff --git a/README.md b/README.md index b4bbf58..c238c40 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,27 @@ If no patterns are specified, the default pattern of `^(fmt\.Print.*|print|print functions (and whole files), that are identifies as Godoc examples (https://blog.golang.org/examples) are excluded from checking. +By default, patterns get matched against the actual expression as it appears in +the source code. The effect is that ``^fmt\.Print.*$` will not match when that +package gets imported with `import fmt2 "fmt"` and then the function gets +called with `fmt2.Print`. + +This makes it hard to match packages that may get imported under a variety of +different names, for example because there is no established convention or the +name is so generic that import aliases have to be used. To solve this, a +package that contains a subgroup literally called `pkg` (`(?P...)`) will be +matched against text where the import name got replaced with the full package +name (e.g. `example.com/some/pkg`) if such a substitution is possible for the +current expression. Otherwise such a pattern is ignored. + A larger set of interesting patterns might include: -* `^fmt\.Print.*$` -- forbid use of Print statements because they are likely just for debugging -* `^fmt\.Errorf$` -- forbid Errorf in favor of using github.com/pkg/errors -* `^ginkgo\.F[A-Z].*$` -- forbid ginkgo focused commands (used for debug issues) -* `^spew\.Dump$` -- forbid dumping detailed data to stdout -* `^fmt\.Errorf(# please use github\.com/pkg/errors)?$` -- forbid Errorf, with a custom message +* `^(?Pfmt)\.Print.*$` -- forbid use of Print statements because they are likely just for debugging +* `^(?Pfmt)\.Errorf$` -- forbid Errorf in favor of using github.com/pkg/errors +* `^(?Pginkgo)\.F[A-Z].*$` -- forbid ginkgo focused commands (used for debug issues) +* `^(?Pspew)\.Dump$` -- forbid dumping detailed data to stdout +* `^(?Pfmt)\.Errorf(# please use github\.com/pkg/errors)?$` -- forbid Errorf, with a custom message -Note that the linter has no knowledge of what packages were actually imported, so aliased imports will match these patterns. ### Flags - **-set_exit_status** (default false) - Set exit status to 1 if any issues are found. diff --git a/forbidigo/forbidigo.go b/forbidigo/forbidigo.go index 9b7d46b..2c04fef 100644 --- a/forbidigo/forbidigo.go +++ b/forbidigo/forbidigo.go @@ -7,6 +7,7 @@ import ( "go/ast" "go/printer" "go/token" + "go/types" "log" "regexp" "strings" @@ -97,12 +98,13 @@ type visitor struct { linter *Linter comments []*ast.CommentGroup - fset *token.FileSet - issues []Issue + fset *token.FileSet + typesInfo *types.Info + issues []Issue } -func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { - var issues []Issue +func (l *Linter) Run(fset *token.FileSet, typesInfo *types.Info, nodes ...ast.Node) ([]Issue, error) { + var issues []Issue for _, node := range nodes { var comments []*ast.CommentGroup isTestFile := false @@ -146,6 +148,7 @@ func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { isTestFile: isTestFile, linter: l, fset: fset, + typesInfo: typesInfo, comments: comments, } ast.Walk(&visitor, node) @@ -155,6 +158,7 @@ func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { } func (v *visitor) Visit(node ast.Node) ast.Visitor { + var selectorExpr *ast.SelectorExpr switch node := node.(type) { case *ast.FuncDecl: // don't descend into godoc examples if we are ignoring them @@ -164,14 +168,54 @@ func (v *visitor) Visit(node ast.Node) ast.Visitor { } return v case *ast.SelectorExpr: + selectorExpr = node case *ast.Ident: default: return v } + + // The text as it appears in the source is always used because issues + // use that. The other texts to match against are extracted when needed + // by a pattern. + srcText := v.textFor(node) + pkgText := "" for _, p := range v.linter.patterns { - if p.pattern.MatchString(v.textFor(node)) && !v.permit(node) { + if p.matchPackage && pkgText == "" { + if selectorExpr == nil { + // Not a selector at all. + continue + } + selector := selectorExpr.X + ident, ok := selector.(*ast.Ident) + if !ok { + // Not an identifier. + continue + } + object, ok := v.typesInfo.Uses[ident] + if !ok { + // No information about the identifier. Should + // not happen, but perhaps there were compile + // errors? + continue + } + pkgName, ok := object.(*types.PkgName) + if !ok { + // No package name, cannot match. + continue + } + pkgText = pkgName.Imported().Path() + "." + selectorExpr.Sel.Name + } + + matchText := "" + switch { + case p.matchPackage: + matchText = pkgText + default: + matchText = srcText + } + if p.pattern.MatchString(matchText) && !v.permit(node) { v.issues = append(v.issues, UsedIssue{ - identifier: v.textFor(node), + identifier: srcText, // Always report the expression as it appears in the source code. pattern: p.pattern.String(), pos: node.Pos(), position: v.fset.Position(node.Pos()), @@ -182,6 +226,7 @@ func (v *visitor) Visit(node ast.Node) ast.Visitor { return nil } +// textFor returns the function as it appears in the source code (= .). func (v *visitor) textFor(node ast.Node) string { buf := new(bytes.Buffer) if err := printer.Fprint(buf, v.fset, node); err != nil { diff --git a/forbidigo/forbidigo_test.go b/forbidigo/forbidigo_test.go index d8b0f8d..c82c964 100644 --- a/forbidigo/forbidigo_test.go +++ b/forbidigo/forbidigo_test.go @@ -1,11 +1,16 @@ package forbidigo import ( - "go/parser" - "go/token" + "go/ast" + "log" + "os" + "path" + "regexp" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/tools/go/packages" ) func TestForbiddenIdentifiers(t *testing.T) { @@ -19,6 +24,18 @@ func foo() { }`, "use of `fmt.Printf` forbidden by pattern `fmt\\.Printf` at testing.go:5:2") }) + t.Run("it finds forbidden, renamed identifiers", func(t *testing.T) { + linter, _ := NewLinter([]string{`fmt\.Printf`}) + expectIssues(t, linter, ` +package bar + +import renamed "fmt" + +func foo() { + renamed.Printf("here i am") +}` /* only detected inside golanci-lint */) + }) + t.Run("displays custom messages", func(t *testing.T) { linter, _ := NewLinter([]string{`^fmt\.Printf(# a custom message)?$`}) expectIssues(t, linter, ` @@ -134,24 +151,86 @@ func ExampleFoo() { }`) assert.NotEmpty(t, issues) }) + + t.Run("import renames not detected by simple pattern", func(t *testing.T) { + linter, _ := NewLinter([]string{`fmt\.Printf`}, OptionExcludeGodocExamples(false)) + issues := parseFile(t, linter, "file.go", ` +package bar + +import fmt2 "fmt" + +func ExampleFoo() { + fmt2.Printf("here i am") +}`) + assert.Empty(t, issues) + }) + + t.Run("import renames detected by package pattern", func(t *testing.T) { + linter, _ := NewLinter([]string{`(?Pfmt)\.Printf`}, OptionExcludeGodocExamples(false)) + expectIssues(t, linter, ` +package bar + +import fmt2 "fmt" + +func ExampleFoo() { + fmt2.Printf("here i am") +}`, "use of `fmt2.Printf` forbidden by pattern `(?Pfmt)\\.Printf` at testing.go:7:2") + }) + } +// sourcePath matches "at /tmp/TestForbiddenIdentifiersdisplays_custom_messages4260088387/001/testing.go". +var sourcePath = regexp.MustCompile(`at .*/([[:alnum:]]+.go)`) + func expectIssues(t *testing.T, linter *Linter, contents string, issues ...string) { actualIssues := parseFile(t, linter, "testing.go", contents) actualIssueStrs := make([]string, 0, len(actualIssues)) for _, i := range actualIssues { - actualIssueStrs = append(actualIssueStrs, i.String()) + str := i.String() + str = sourcePath.ReplaceAllString(str, "at $1") + actualIssueStrs = append(actualIssueStrs, str) } assert.ElementsMatch(t, issues, actualIssueStrs) } func parseFile(t *testing.T, linter *Linter, fileName, contents string) []Issue { - fset := token.NewFileSet() - expr, err := parser.ParseFile(fset, fileName, contents, parser.ParseComments) + // We can use packages.Load if we put a single file into a separate + // directory and parse it with Go modules of. We have to be in that + // directory to use "." as pattern, parsing it via the absolute path + // from the forbidigo project doesn't work ("cannot import absolute + // path"). + tmpDir := t.TempDir() + if err := os.WriteFile(path.Join(tmpDir, fileName), []byte(contents), 0644); err != nil { + t.Fatalf("could not write source file: %v", err) + } + env := os.Environ() + env = append(env, "GO111MODULE=off") + cfg := packages.Config{ + Mode: packages.NeedSyntax | packages.NeedName | packages.NeedFiles | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedDeps, + Env: env, + Tests: true, + } + pwd, err := os.Getwd() + require.NoError(t, err) + defer os.Chdir(pwd) + err = os.Chdir(tmpDir) + require.NoError(t, err) + pkgs, err := packages.Load(&cfg, ".") if err != nil { - t.Fatalf("unable to parse file contents: %s", err) + t.Fatalf("could not load packages: %v", err) + } + var issues []Issue + for _, p := range pkgs { + nodes := make([]ast.Node, 0, len(p.Syntax)) + for _, n := range p.Syntax { + nodes = append(nodes, n) + } + newIssues, err := linter.Run(p.Fset, p.TypesInfo, nodes...) + if err != nil { + log.Fatalf("failed: %s", err) + } + issues = append(issues, newIssues...) } - issues, err := linter.Run(fset, expr) if err != nil { t.Fatalf("unable to parse file: %s", err) } diff --git a/forbidigo/patterns.go b/forbidigo/patterns.go index 9dc70ec..49c19dc 100644 --- a/forbidigo/patterns.go +++ b/forbidigo/patterns.go @@ -8,8 +8,9 @@ import ( ) type pattern struct { - pattern *regexp.Regexp - msg string + pattern *regexp.Regexp + msg string + matchPackage bool } func parse(ptrn string) (*pattern, error) { @@ -22,7 +23,14 @@ func parse(ptrn string) (*pattern, error) { return nil, fmt.Errorf("unable to parse pattern `%s`: %s", ptrn, err) } msg := extractComment(re) - return &pattern{pattern: ptrnRe, msg: msg}, nil + matchPackage := false + for _, groupName := range ptrnRe.SubexpNames() { + switch groupName { + case "pkg": + matchPackage = true + } + } + return &pattern{pattern: ptrnRe, msg: msg, matchPackage: matchPackage}, nil } // Traverse the leaf submatches in the regex tree and extract a comment, if any diff --git a/forbidigo/patterns_test.go b/forbidigo/patterns_test.go index ce4e617..1b606df 100644 --- a/forbidigo/patterns_test.go +++ b/forbidigo/patterns_test.go @@ -9,9 +9,10 @@ import ( func TestParseValidPatterns(t *testing.T) { for _, tc := range []struct { - name string - ptrn string - expectedComment string + name string + ptrn string + expectedComment string + expectedMatchPackage bool }{ { name: "simple expression, no comment", @@ -41,12 +42,18 @@ func TestParseValidPatterns(t *testing.T) { ptrn: `^fmt\.Println(# Please don't use this!)?$`, expectedComment: "Please don't use this!", }, + { + name: "match package with non-empty group", + ptrn: `^(?Pfmt).Println$`, + expectedMatchPackage: true, + }, } { t.Run(tc.name, func(t *testing.T) { ptrn, err := parse(tc.ptrn) require.Nil(t, err) assert.Equal(t, tc.ptrn, ptrn.pattern.String()) assert.Equal(t, tc.expectedComment, ptrn.msg) + assert.Equal(t, tc.expectedMatchPackage, ptrn.matchPackage, "match pattern") }) } } diff --git a/main.go b/main.go index 568940b..ec7a964 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,7 @@ func main() { } cfg := packages.Config{ - Mode: packages.NeedSyntax | packages.NeedName | packages.NeedFiles | packages.NeedTypes, + Mode: packages.NeedSyntax | packages.NeedName | packages.NeedFiles | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedDeps, Tests: *includeTests, } pkgs, err := packages.Load(&cfg, flag.Args()[firstPkg:]...) @@ -48,20 +48,21 @@ func main() { if err != nil { log.Fatalf("Could not create linter: %s", err) } - var issues []forbidigo.Issue for _, p := range pkgs { nodes := make([]ast.Node, 0, len(p.Syntax)) for _, n := range p.Syntax { nodes = append(nodes, n) } - newIssues, err := linter.Run(p.Fset, nodes...) + newIssues, err := linter.Run(p.Fset, p.TypesInfo, nodes...) if err != nil { log.Fatalf("failed: %s", err) } issues = append(issues, newIssues...) } - + if err != nil { + log.Fatalf("failed: %s", err) + } for _, issue := range issues { log.Println(issue) } diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index a14ba18..04f7864 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -41,6 +41,7 @@ func NewAnalyzer() *analysis.Analyzer { usePermitDirective: true, includeExamples: true, } + flags.Var(&listVar{values: &a.patterns}, "p", "pattern") flags.BoolVar(&a.includeExamples, "examples", false, "check godoc examples") flags.BoolVar(&a.usePermitDirective, "permit", true, `when set, lines with "//permit" directives will be ignored`) @@ -67,7 +68,7 @@ func (a *analyzer) runAnalysis(pass *analysis.Pass) (interface{}, error) { for _, f := range pass.Files { nodes = append(nodes, f) } - issues, err := linter.Run(pass.Fset, nodes...) + issues, err := linter.Run(pass.Fset, pass.TypesInfo, nodes...) if err != nil { return nil, err } diff --git a/pkg/analyzer/analyzer_test.go b/pkg/analyzer/analyzer_test.go index 6d521cc..fc5ba13 100644 --- a/pkg/analyzer/analyzer_test.go +++ b/pkg/analyzer/analyzer_test.go @@ -3,12 +3,21 @@ package analyzer_test import ( "testing" + "github.com/ashanbrown/forbidigo/forbidigo" "github.com/ashanbrown/forbidigo/pkg/analyzer" "golang.org/x/tools/go/analysis/analysistest" ) func TestAnalyzer(t *testing.T) { testdata := analysistest.TestData() + patterns := append(forbidigo.DefaultPatterns(), + `^(?Pexample.com/some/pkg)\.Forbidden$`, + ) a := analyzer.NewAnalyzer() + for _, pattern := range patterns { + if err := a.Flags.Set("p", pattern); err != nil { + t.Fatalf("unexpected error when setting pattern: %v", err) + } + } analysistest.Run(t, testdata, a, "") } diff --git a/pkg/analyzer/testdata/forbidden.go b/pkg/analyzer/testdata/forbidden.go index 7966ae7..3990301 100644 --- a/pkg/analyzer/testdata/forbidden.go +++ b/pkg/analyzer/testdata/forbidden.go @@ -1,10 +1,24 @@ package testdata -import "fmt" +import ( + "fmt" + alias "fmt" + + "example.com/some/pkg" +) func Foo() { fmt.Println("here I am") // want "forbidden by pattern" fmt.Printf("this is ok") //permit:fmt.Printf // this is ok print("not ok") // want "forbidden by pattern" println("also not ok") // want "forbidden by pattern" + alias.Println("hello") // not matched by default pattern fmt.Println + pkg.Forbidden() // want "pkg.Forbidden.*forbidden by pattern .*example.com/some/pkg.*Forbidden" +} + +func Bar() string { + fmt := struct { + Println string + }{} + return fmt.Println // want "forbidden by pattern" } diff --git a/pkg/analyzer/testdata/src/example.com/some/pkg/pkg.go b/pkg/analyzer/testdata/src/example.com/some/pkg/pkg.go new file mode 100644 index 0000000..46872b3 --- /dev/null +++ b/pkg/analyzer/testdata/src/example.com/some/pkg/pkg.go @@ -0,0 +1,4 @@ +package pkg + +func Forbidden() { +} From 386d6bacb0c765741088d3dd8a340e3d1734e176 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Tue, 15 Nov 2022 18:11:51 +0100 Subject: [PATCH 2/4] default pattern: match against fmt package instead of name Previously, import renaming led to false negatives: import fmt2 "fmt" fmt2.Println("hello world") There were also false positives for source code that didn't use the fmt package and just looked like it did: fmt := struct { Println string }{} return fmt.Println Now the default pattern uses the new import renaming support and only matches when the actual "fmt" standard package provides the forbidden symbol. --- README.md | 2 +- forbidigo/forbidigo.go | 2 +- pkg/analyzer/testdata/forbidden.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c238c40..06ed062 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ forbidigo [flags...] patterns... -- packages... -If no patterns are specified, the default pattern of `^(fmt\.Print.*|print|println)$` is used to eliminate debug statements. By default, +If no patterns are specified, the default pattern of `^((?Pfmt)\.Print.*|print|println)$` is used to eliminate debug statements. By default, functions (and whole files), that are identifies as Godoc examples (https://blog.golang.org/examples) are excluded from checking. diff --git a/forbidigo/forbidigo.go b/forbidigo/forbidigo.go index 2c04fef..17c4826 100644 --- a/forbidigo/forbidigo.go +++ b/forbidigo/forbidigo.go @@ -58,7 +58,7 @@ type Linter struct { } func DefaultPatterns() []string { - return []string{`^(fmt\.Print(|f|ln)|print|println)$`} + return []string{`^((?Pfmt)\.Print(|f|ln)|print|println)$`} } //go:generate go-options config diff --git a/pkg/analyzer/testdata/forbidden.go b/pkg/analyzer/testdata/forbidden.go index 3990301..e8cdcd5 100644 --- a/pkg/analyzer/testdata/forbidden.go +++ b/pkg/analyzer/testdata/forbidden.go @@ -10,9 +10,9 @@ import ( func Foo() { fmt.Println("here I am") // want "forbidden by pattern" fmt.Printf("this is ok") //permit:fmt.Printf // this is ok - print("not ok") // want "forbidden by pattern" - println("also not ok") // want "forbidden by pattern" - alias.Println("hello") // not matched by default pattern fmt.Println + print("not ok") // no package, not matched + println("also not ok") // no package, not matched + alias.Println("hello") // want "forbidden by pattern" pkg.Forbidden() // want "pkg.Forbidden.*forbidden by pattern .*example.com/some/pkg.*Forbidden" } @@ -20,5 +20,5 @@ func Bar() string { fmt := struct { Println string }{} - return fmt.Println // want "forbidden by pattern" + return fmt.Println // not the fmt package, not matched } From c9e35a01ef493a1a751ac8d4e5e171804ba068ec Mon Sep 17 00:00:00 2001 From: "Andrew S. Brown" Date: Sat, 26 Nov 2022 07:36:27 -0800 Subject: [PATCH 3/4] Prevent the need for a version bump and fix a few test cases --- README.md | 2 +- examples/expected_results.txt | 6 +++--- forbidigo/forbidigo.go | 12 ++++++++++-- forbidigo/forbidigo_test.go | 2 +- go.mod | 2 +- go.sum | 27 +++++++++++++++++++++++++++ main.go | 9 ++++----- pkg/analyzer/analyzer.go | 2 +- 8 files changed, 48 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 06ed062..257ea09 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ forbidigo [flags...] patterns... -- packages... -If no patterns are specified, the default pattern of `^((?Pfmt)\.Print.*|print|println)$` is used to eliminate debug statements. By default, +If no patterns are specified, the default patterns of `^(Pfmt)\.Print(|f|ln)$` and `^(print|println)$` are used to eliminate debug statements. By default, functions (and whole files), that are identifies as Godoc examples (https://blog.golang.org/examples) are excluded from checking. diff --git a/examples/expected_results.txt b/examples/expected_results.txt index 7bedf18..fd213e8 100644 --- a/examples/expected_results.txt +++ b/examples/expected_results.txt @@ -1,3 +1,3 @@ -use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` at CURDIR/examples/example.go:6:2 -use of `print` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` at CURDIR/examples/example.go:8:2 -use of `println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` at CURDIR/examples/example.go:9:2 +use of `fmt.Println` forbidden by pattern `^(?Pfmt)\.Print(|f|ln)$` at CURDIR/examples/example.go:6:2 +use of `print` forbidden by pattern `^(print|println)$` at CURDIR/examples/example.go:8:2 +use of `println` forbidden by pattern `^(print|println)$` at CURDIR/examples/example.go:9:2 diff --git a/forbidigo/forbidigo.go b/forbidigo/forbidigo.go index 17c4826..57dd99c 100644 --- a/forbidigo/forbidigo.go +++ b/forbidigo/forbidigo.go @@ -58,7 +58,7 @@ type Linter struct { } func DefaultPatterns() []string { - return []string{`^((?Pfmt)\.Print(|f|ln)|print|println)$`} + return []string{`^(?Pfmt)\.Print(|f|ln)$`, `^(print|println)$`} } //go:generate go-options config @@ -103,7 +103,12 @@ type visitor struct { issues []Issue } -func (l *Linter) Run(fset *token.FileSet, typesInfo *types.Info, nodes ...ast.Node) ([]Issue, error) { +// Deprecated: Use RunWithTypes +func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { + return l.RunWithTypes(fset, nil, nodes...) +} + +func (l *Linter) RunWithTypes(fset *token.FileSet, typesInfo *types.Info, nodes ...ast.Node) ([]Issue, error) { var issues []Issue for _, node := range nodes { var comments []*ast.CommentGroup @@ -181,6 +186,9 @@ func (v *visitor) Visit(node ast.Node) ast.Visitor { pkgText := "" for _, p := range v.linter.patterns { if p.matchPackage && pkgText == "" { + if v.typesInfo == nil { + continue + } if selectorExpr == nil { // Not a selector at all. continue diff --git a/forbidigo/forbidigo_test.go b/forbidigo/forbidigo_test.go index c82c964..f37b563 100644 --- a/forbidigo/forbidigo_test.go +++ b/forbidigo/forbidigo_test.go @@ -225,7 +225,7 @@ func parseFile(t *testing.T, linter *Linter, fileName, contents string) []Issue for _, n := range p.Syntax { nodes = append(nodes, n) } - newIssues, err := linter.Run(p.Fset, p.TypesInfo, nodes...) + newIssues, err := linter.RunWithTypes(p.Fset, p.TypesInfo, nodes...) if err != nil { log.Fatalf("failed: %s", err) } diff --git a/go.mod b/go.mod index 45bc675..35418cb 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,5 @@ go 1.12 require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.4.0 - golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc + golang.org/x/tools v0.3.0 ) diff --git a/go.sum b/go.sum index 545861c..b2b5936 100644 --- a/go.sum +++ b/go.sum @@ -8,18 +8,45 @@ github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc h1:+GB9/q0gCzmtaIl6WdoJFMS3lPwrR6rpcMyY6jfQHAw= golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/main.go b/main.go index ec7a964..d458c9f 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,7 @@ func main() { } cfg := packages.Config{ - Mode: packages.NeedSyntax | packages.NeedName | packages.NeedFiles | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedDeps, + Mode: packages.NeedSyntax | packages.NeedName | packages.NeedFiles | packages.NeedTypes | packages.NeedTypesInfo, Tests: *includeTests, } pkgs, err := packages.Load(&cfg, flag.Args()[firstPkg:]...) @@ -48,21 +48,20 @@ func main() { if err != nil { log.Fatalf("Could not create linter: %s", err) } + var issues []forbidigo.Issue for _, p := range pkgs { nodes := make([]ast.Node, 0, len(p.Syntax)) for _, n := range p.Syntax { nodes = append(nodes, n) } - newIssues, err := linter.Run(p.Fset, p.TypesInfo, nodes...) + newIssues, err := linter.RunWithTypes(p.Fset, p.TypesInfo, nodes...) if err != nil { log.Fatalf("failed: %s", err) } issues = append(issues, newIssues...) } - if err != nil { - log.Fatalf("failed: %s", err) - } + for _, issue := range issues { log.Println(issue) } diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 04f7864..9c3d21b 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -68,7 +68,7 @@ func (a *analyzer) runAnalysis(pass *analysis.Pass) (interface{}, error) { for _, f := range pass.Files { nodes = append(nodes, f) } - issues, err := linter.Run(pass.Fset, pass.TypesInfo, nodes...) + issues, err := linter.RunWithTypes(pass.Fset, pass.TypesInfo, nodes...) if err != nil { return nil, err } From 72d8dd551112d448820bdab55bd0f5b2fabfebe0 Mon Sep 17 00:00:00 2001 From: "Andrew S. Brown" Date: Sat, 26 Nov 2022 07:50:35 -0800 Subject: [PATCH 4/4] Better comment --- forbidigo/forbidigo.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/forbidigo/forbidigo.go b/forbidigo/forbidigo.go index 57dd99c..eb3aa2f 100644 --- a/forbidigo/forbidigo.go +++ b/forbidigo/forbidigo.go @@ -103,7 +103,8 @@ type visitor struct { issues []Issue } -// Deprecated: Use RunWithTypes +// Deprecated: Run was the original entrypoint before RunWithTypes was introduced to support matching +// full package names. func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { return l.RunWithTypes(fset, nil, nodes...) }