From 0253981f14400ced7afb9b9f294aa6e5d26fec34 Mon Sep 17 00:00:00 2001 From: sivchari Date: Fri, 25 Oct 2024 23:40:12 +0900 Subject: [PATCH] handle dot import Signed-off-by: sivchari --- tenv.go | 78 +++++++++++----------- testdata/src/a/a_custom_test.go | 32 +++++----- testdata/src/a/dot_import_test.go | 103 ++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 52 deletions(-) create mode 100644 testdata/src/a/dot_import_test.go diff --git a/tenv.go b/tenv.go index 4cbd1a0..647f368 100644 --- a/tenv.go +++ b/tenv.go @@ -3,6 +3,8 @@ package tenv import ( "fmt" "go/ast" + "go/token" + "go/types" "strings" "golang.org/x/tools/go/analysis" @@ -94,19 +96,17 @@ func checkExprStmt(pass *analysis.Pass, stmt *ast.ExprStmt, funcName, argName st return false } checkArgs(pass, callExpr.Args, funcName, argName) - fun, ok := callExpr.Fun.(*ast.SelectorExpr) - if !ok { - return false + ident, ok := callExpr.Fun.(*ast.Ident) + if ok { + obj := pass.TypesInfo.ObjectOf(ident) + return checkObj(pass, obj, stmt.Pos(), funcName, argName) } - obj := pass.TypesInfo.ObjectOf(fun.Sel) - targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name()) - if targetName == "os.Setenv" { - if argName == "" { - argName = "testing" - } - pass.Reportf(stmt.Pos(), "os.Setenv() can be replaced by `%s.Setenv()` in %s", argName, funcName) + fun, ok := callExpr.Fun.(*ast.SelectorExpr) + if ok { + obj := pass.TypesInfo.ObjectOf(fun.Sel) + return checkObj(pass, obj, stmt.Pos(), funcName, argName) } - return true + return false } func checkArgs(pass *analysis.Pass, args []ast.Expr, funcName, argName string) { @@ -115,17 +115,15 @@ func checkArgs(pass *analysis.Pass, args []ast.Expr, funcName, argName string) { if !ok { continue } - fun, ok := callExpr.Fun.(*ast.SelectorExpr) - if !ok { - continue + ident, ok := callExpr.Fun.(*ast.Ident) + if ok { + obj := pass.TypesInfo.ObjectOf(ident) + checkObj(pass, obj, arg.Pos(), funcName, argName) } - obj := pass.TypesInfo.ObjectOf(fun.Sel) - targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name()) - if targetName == "os.Setenv" { - if argName == "" { - argName = "testing" - } - pass.Reportf(arg.Pos(), "os.Setenv() can be replaced by `%s.Setenv()` in %s", argName, funcName) + fun, ok := callExpr.Fun.(*ast.SelectorExpr) + if ok { + obj := pass.TypesInfo.ObjectOf(fun.Sel) + checkObj(pass, obj, arg.Pos(), funcName, argName) } } } @@ -139,19 +137,17 @@ func checkIfStmt(pass *analysis.Pass, stmt *ast.IfStmt, funcName, argName string if !ok { return false } - fun, ok := rhs.Fun.(*ast.SelectorExpr) - if !ok { - return false + ident, ok := rhs.Fun.(*ast.Ident) + if ok { + obj := pass.TypesInfo.ObjectOf(ident) + return checkObj(pass, obj, stmt.Pos(), funcName, argName) } - obj := pass.TypesInfo.ObjectOf(fun.Sel) - targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name()) - if targetName == "os.Setenv" { - if argName == "" { - argName = "testing" - } - pass.Reportf(stmt.Pos(), "os.Setenv() can be replaced by `%s.Setenv()` in %s", argName, funcName) + fun, ok := rhs.Fun.(*ast.SelectorExpr) + if ok { + obj := pass.TypesInfo.ObjectOf(fun.Sel) + return checkObj(pass, obj, stmt.Pos(), funcName, argName) } - return true + return false } func checkAssignStmt(pass *analysis.Pass, stmt *ast.AssignStmt, funcName, argName string) bool { @@ -159,17 +155,27 @@ func checkAssignStmt(pass *analysis.Pass, stmt *ast.AssignStmt, funcName, argNam if !ok { return false } + ident, ok := rhs.Fun.(*ast.Ident) + if ok { + obj := pass.TypesInfo.ObjectOf(ident) + return checkObj(pass, obj, stmt.Pos(), funcName, argName) + } fun, ok := rhs.Fun.(*ast.SelectorExpr) - if !ok { - return false + if ok { + obj := pass.TypesInfo.ObjectOf(fun.Sel) + return checkObj(pass, obj, stmt.Pos(), funcName, argName) } - obj := pass.TypesInfo.ObjectOf(fun.Sel) + return false +} + +func checkObj(pass *analysis.Pass, obj types.Object, pos token.Pos, funcName, argName string) bool { targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name()) if targetName == "os.Setenv" { if argName == "" { argName = "testing" } - pass.Reportf(stmt.Pos(), "os.Setenv() can be replaced by `%s.Setenv()` in %s", argName, funcName) + fmt.Println(argName, funcName) + pass.Reportf(pos, "os.Setenv() can be replaced by `%s.Setenv()` in %s", argName, funcName) } return true } diff --git a/testdata/src/a/a_custom_test.go b/testdata/src/a/a_custom_test.go index 8c27955..33572d5 100644 --- a/testdata/src/a/a_custom_test.go +++ b/testdata/src/a/a_custom_test.go @@ -14,8 +14,8 @@ var ( ) func testsetup2() { - os.Setenv("a", "b") // if -all = true, want "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in testsetup" - err := os.Setenv("a", "b") // if -all = true, want "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in testsetup" + os.Setenv("a", "b") // if -all = true, want "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in testsetup2" + err := os.Setenv("a", "b") // if -all = true, want "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in testsetup2" if err != nil { _ = err } @@ -23,30 +23,30 @@ func testsetup2() { } func TestF2(t *mytest.T) { - testsetup() - os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF" - err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF" + testsetup2() + os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF2" + err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF2" _ = err - if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF" + if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF2" _ = err } } func BenchmarkF2(b *mytest.B) { TB(b) - os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF" - err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF" + os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF2" + err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF2" _ = err - if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF" + if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF2" _ = err } } func TB2(tb mytest.TB) { - os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB" - err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB" + os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB2" + err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB2" _ = err - if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB" + if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB2" _ = err } } @@ -90,15 +90,15 @@ func TestTDD2(t *mytest.T) { func TestLoop2(t *mytest.T) { for i := 0; i < 3; i++ { - os.Setenv(fmt.Sprintf("a%d", i), "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop" - err := os.Setenv(fmt.Sprintf("a%d", i), "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop" + os.Setenv(fmt.Sprintf("a%d", i), "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop2" + err := os.Setenv(fmt.Sprintf("a%d", i), "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop2" _ = err - if err := os.Setenv(fmt.Sprintf("a%d", i), "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop" + if err := os.Setenv(fmt.Sprintf("a%d", i), "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop2" _ = err } } } func TestUsingArg2(t *mytest.T) { - require.NoError(t, os.Setenv("a", "b")) // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestUsingArg" + require.NoError(t, os.Setenv("a", "b")) // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestUsingArg2" } diff --git a/testdata/src/a/dot_import_test.go b/testdata/src/a/dot_import_test.go new file mode 100644 index 0000000..c8a5ad2 --- /dev/null +++ b/testdata/src/a/dot_import_test.go @@ -0,0 +1,103 @@ +package a + +import ( + "fmt" + . "os" + "testing" + + "github.com/stretchr/testify/require" +) + +var ( + e3 = Setenv("a", "b") // never seen +) + +func testsetup3() { + Setenv("a", "b") // if -all = true, want "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in testsetup3" + err := Setenv("a", "b") // if -all = true, want "os\\.Setenv\\(\\) can be replaced by `testing\\.Setenv\\(\\)` in testsetup3" + if err != nil { + _ = err + } + Setenv("a", "b") // if -all = true, "func setup is not using testing.Setenv" +} + +func TestF3(t *testing.T) { + testsetup3() + Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF3" + err := Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF3" + _ = err + if err := Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF3" + _ = err + } +} + +func BenchmarkF3(b *testing.B) { + TB(b) + Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF3" + err := Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF3" + _ = err + if err := Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF3" + _ = err + } +} + +func TB3(tb testing.TB) { + Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB3" + err := Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB3" + _ = err + if err := Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB3" + _ = err + } +} + +func TestFunctionLiteral3(t *testing.T) { + testsetup3() + t.Run("test", func(t *testing.T) { + Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function" + err := Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function" + _ = err + if err := Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function" + _ = err + } + }) +} + +func TestEmpty3(t *testing.T) { + t.Run("test", func(*testing.T) {}) +} + +func TestEmptyTB3(t *testing.T) { + func(testing.TB) {}(t) +} + +func TestTDD3(t *testing.T) { + for _, tt := range []struct { + name string + }{ + {"test"}, + } { + t.Run(tt.name, func(t *testing.T) { + Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function" + err := Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function" + _ = err + if err := Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function" + _ = err + } + }) + } +} + +func TestLoop3(t *testing.T) { + for i := 0; i < 3; i++ { + Setenv(fmt.Sprintf("a%d", i), "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop3" + err := Setenv(fmt.Sprintf("a%d", i), "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop3" + _ = err + if err := Setenv(fmt.Sprintf("a%d", i), "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop3" + _ = err + } + } +} + +func TestUsingArg3(t *testing.T) { + require.NoError(t, Setenv("a", "b")) // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestUsingArg3" +}