diff --git a/v2/skeleton/_template/inspect/@@.Pkg@@_test.go b/v2/skeleton/_template/inspect/@@.Pkg@@_test.go index 1a6ca5e..ca091ba 100644 --- a/v2/skeleton/_template/inspect/@@.Pkg@@_test.go +++ b/v2/skeleton/_template/inspect/@@.Pkg@@_test.go @@ -10,6 +10,11 @@ import ( // TestAnalyzer is a test for Analyzer. func TestAnalyzer(t *testing.T) { + @@if .CopyParentGoMod -@@ + modfile := testutil.ModFile(t, ".", nil) + testdata := testutil.WithModules(t, analysistest.TestData(), modfile) + @@else -@@ testdata := testutil.WithModules(t, analysistest.TestData(), nil) + @@end -@@ analysistest.Run(t, testdata, @@.Pkg@@.Analyzer, "a") } diff --git a/v2/skeleton/_template/ssa/@@.Pkg@@_test.go b/v2/skeleton/_template/ssa/@@.Pkg@@_test.go index 1a6ca5e..ca091ba 100644 --- a/v2/skeleton/_template/ssa/@@.Pkg@@_test.go +++ b/v2/skeleton/_template/ssa/@@.Pkg@@_test.go @@ -10,6 +10,11 @@ import ( // TestAnalyzer is a test for Analyzer. func TestAnalyzer(t *testing.T) { + @@if .CopyParentGoMod -@@ + modfile := testutil.ModFile(t, ".", nil) + testdata := testutil.WithModules(t, analysistest.TestData(), modfile) + @@else -@@ testdata := testutil.WithModules(t, analysistest.TestData(), nil) + @@end -@@ analysistest.Run(t, testdata, @@.Pkg@@.Analyzer, "a") } diff --git a/v2/skeleton/info.go b/v2/skeleton/info.go index bb44383..737ab1f 100644 --- a/v2/skeleton/info.go +++ b/v2/skeleton/info.go @@ -1,12 +1,13 @@ package skeleton type Info struct { - Kind Kind - Checker Checker - Pkg string - Path string - Cmd bool - Plugin bool - GoMod bool - GoVersion string + Kind Kind + Checker Checker + Pkg string + Path string + Cmd bool + Plugin bool + GoMod bool + GoVersion string + CopyParentGoMod bool } diff --git a/v2/skeleton/skeleton.go b/v2/skeleton/skeleton.go index aa513cb..7855434 100644 --- a/v2/skeleton/skeleton.go +++ b/v2/skeleton/skeleton.go @@ -120,6 +120,7 @@ func (s *Skeleton) parseFlag(args []string, info *Info) (*flag.FlagSet, error) { flags.BoolVar(&info.Plugin, "plugin", false, "create golangci-lint plugin") flags.StringVar(&info.Pkg, "pkg", "", "package name") flags.BoolVar(&info.GoMod, "gomod", true, "create a go.mod file") + flags.BoolVar(&info.CopyParentGoMod, "copy-parent-gomod", false, "copy parent go.mod file to testdata") if err := flags.Parse(args); err != nil { return nil, err diff --git a/v2/skeleton/skeleton_test.go b/v2/skeleton/skeleton_test.go index da79431..b9a746c 100644 --- a/v2/skeleton/skeleton_test.go +++ b/v2/skeleton/skeleton_test.go @@ -60,6 +60,8 @@ func TestSkeletonRun(t *testing.T) { "kind-packages": {"", "", "", "-kind packages", "example.com/example", "", skeleton.ExitSuccess, "", true}, "parent-module": {"", "", F(t, "go.mod", "module example.com/example"), "-gomod=false", "sub", "", skeleton.ExitSuccess, "", true}, "parent-module-deep": {"", "sub", F(t, "go.mod", "module example.com/example", "sub/sub.go", "package sub"), "-gomod=false", "subsub", "", skeleton.ExitSuccess, "", true}, + "kind-inspect-copy-parent-gomod-to-testdata": {"", "", "", "-kind inspect -copy-parent-gomod", "example.com/example", "", skeleton.ExitSuccess, "", true}, + "kind-ssa-copy-parent-gomod-to-testdata": {"", "", "", "-kind ssa -copy-parent-gomod", "example.com/example", "", skeleton.ExitSuccess, "", true}, } if flagUpdate { diff --git a/v2/skeleton/testdata/kind-inspect-copy-parent-gomod-to-testdata-go-test.golden b/v2/skeleton/testdata/kind-inspect-copy-parent-gomod-to-testdata-go-test.golden new file mode 100644 index 0000000..8e7d05a --- /dev/null +++ b/v2/skeleton/testdata/kind-inspect-copy-parent-gomod-to-testdata-go-test.golden @@ -0,0 +1,6 @@ +--- FAIL: TestAnalyzer (0000s) + analysistest.go:550: a/a.go:6: diagnostic "identifier is gopher" does not match pattern `pattern` + analysistest.go:614: a/a.go:6: no diagnostic was reported matching `pattern` +FAIL +exit status 1 +FAIL example.com/example 0000s diff --git a/v2/skeleton/testdata/kind-inspect-copy-parent-gomod-to-testdata.golden b/v2/skeleton/testdata/kind-inspect-copy-parent-gomod-to-testdata.golden new file mode 100644 index 0000000..59005f3 --- /dev/null +++ b/v2/skeleton/testdata/kind-inspect-copy-parent-gomod-to-testdata.golden @@ -0,0 +1,85 @@ +-- example/cmd/example/main.go -- +package main + +import ( + "example.com/example" + "golang.org/x/tools/go/analysis/unitchecker" +) + +func main() { unitchecker.Main(example.Analyzer) } +-- example/example.go -- +package example + +import ( + "go/ast" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const doc = "example is ..." + +// Analyzer is ... +var Analyzer = &analysis.Analyzer{ + Name: "example", + Doc: doc, + Run: run, + Requires: []*analysis.Analyzer{ + inspect.Analyzer, + }, +} + +func run(pass *analysis.Pass) (any, error) { + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + + nodeFilter := []ast.Node{ + (*ast.Ident)(nil), + } + + inspect.Preorder(nodeFilter, func(n ast.Node) { + switch n := n.(type) { + case *ast.Ident: + if n.Name == "gopher" { + pass.Reportf(n.Pos(), "identifier is gopher") + } + } + }) + + return nil, nil +} +-- example/example_test.go -- +package example_test + +import ( + "testing" + + "example.com/example" + "github.com/gostaticanalysis/testutil" + "golang.org/x/tools/go/analysis/analysistest" +) + +// TestAnalyzer is a test for Analyzer. +func TestAnalyzer(t *testing.T) { + modfile := testutil.ModFile(t, ".", nil) + testdata := testutil.WithModules(t, analysistest.TestData(), modfile) + analysistest.Run(t, testdata, example.Analyzer, "a") +} +-- example/go.mod -- +module example.com/example + +go 1.23.3 + +-- example/testdata/src/a/a.go -- +package a + +func f() { + // The pattern can be written in regular expression. + var gopher int // want "pattern" + print(gopher) // want "identifier is gopher" +} +-- example/testdata/src/a/go.mod -- +module a + +go 1.23.3 + diff --git a/v2/skeleton/testdata/kind-ssa-copy-parent-gomod-to-testdata-go-test.golden b/v2/skeleton/testdata/kind-ssa-copy-parent-gomod-to-testdata-go-test.golden new file mode 100644 index 0000000..dc0421e --- /dev/null +++ b/v2/skeleton/testdata/kind-ssa-copy-parent-gomod-to-testdata-go-test.golden @@ -0,0 +1,12 @@ +a.f + Block 0 + *ssa.Call print(0:int) + *ssa.Builtin builtin print + *ssa.Const 0:int + *ssa.Return return +--- FAIL: TestAnalyzer (0000s) + analysistest.go:614: a/a.go:6: no diagnostic was reported matching `pattern` + analysistest.go:614: a/a.go:7: no diagnostic was reported matching `identifier is gopher` +FAIL +exit status 1 +FAIL example.com/example 0000s diff --git a/v2/skeleton/testdata/kind-ssa-copy-parent-gomod-to-testdata.golden b/v2/skeleton/testdata/kind-ssa-copy-parent-gomod-to-testdata.golden new file mode 100644 index 0000000..724cec2 --- /dev/null +++ b/v2/skeleton/testdata/kind-ssa-copy-parent-gomod-to-testdata.golden @@ -0,0 +1,84 @@ +-- example/cmd/example/main.go -- +package main + +import ( + "example.com/example" + "golang.org/x/tools/go/analysis/unitchecker" +) + +func main() { unitchecker.Main(example.Analyzer) } +-- example/example.go -- +package example + +import ( + "fmt" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" +) + +const doc = "example is ..." + +// Analyzer is ... +var Analyzer = &analysis.Analyzer{ + Name: "example", + Doc: doc, + Run: run, + Requires: []*analysis.Analyzer{ + buildssa.Analyzer, + }, +} + +func run(pass *analysis.Pass) (any, error) { + s := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) + for _, f := range s.SrcFuncs { + fmt.Println(f) + for _, b := range f.Blocks { + fmt.Printf("\tBlock %d\n", b.Index) + for _, instr := range b.Instrs { + fmt.Printf("\t\t%[1]T\t%[1]v\n", instr) + for _, v := range instr.Operands(nil) { + if v != nil { + fmt.Printf("\t\t\t%[1]T\t%[1]v\n", *v) + } + } + } + } + } + return nil, nil +} +-- example/example_test.go -- +package example_test + +import ( + "testing" + + "example.com/example" + "github.com/gostaticanalysis/testutil" + "golang.org/x/tools/go/analysis/analysistest" +) + +// TestAnalyzer is a test for Analyzer. +func TestAnalyzer(t *testing.T) { + modfile := testutil.ModFile(t, ".", nil) + testdata := testutil.WithModules(t, analysistest.TestData(), modfile) + analysistest.Run(t, testdata, example.Analyzer, "a") +} +-- example/go.mod -- +module example.com/example + +go 1.23.3 + +-- example/testdata/src/a/a.go -- +package a + +func f() { + // The pattern can be written in regular expression. + var gopher int // want "pattern" + print(gopher) // want "identifier is gopher" +} +-- example/testdata/src/a/go.mod -- +module a + +go 1.23.3 +