Skip to content

Commit

Permalink
use analysis.Pass (#42)
Browse files Browse the repository at this point in the history
Signed-off-by: sivchari <[email protected]>
  • Loading branch information
sivchari authored Oct 25, 2024
1 parent 5cae67a commit 7b68c50
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 42 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
run: |
go mod download
- name: Test
run: go test
run: go test ./...

lint:
name: Lint
Expand All @@ -42,4 +42,4 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.59.0
version: v1.61.0
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/sivchari/tenv

go 1.21.0
go 1.22.3

require (
github.com/gostaticanalysis/testutil v0.4.0
Expand Down
57 changes: 18 additions & 39 deletions tenv.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tenv

import (
"fmt"
"go/ast"
"strings"

Expand Down Expand Up @@ -51,15 +52,15 @@ func run(pass *analysis.Pass) (interface{}, error) {
}

func checkFuncDecl(pass *analysis.Pass, f *ast.FuncDecl, fileName string) {
argName, ok := targetRunner(f.Type.Params.List, fileName)
argName, ok := targetRunner(pass, f.Type.Params.List, fileName)
if !ok {
return
}
checkStmts(pass, f.Body.List, f.Name.Name, argName)
}

func checkFuncLit(pass *analysis.Pass, f *ast.FuncLit, fileName string) {
argName, ok := targetRunner(f.Type.Params.List, fileName)
argName, ok := targetRunner(pass, f.Type.Params.List, fileName)
if !ok {
return
}
Expand Down Expand Up @@ -97,11 +98,8 @@ func checkExprStmt(pass *analysis.Pass, stmt *ast.ExprStmt, funcName, argName st
if !ok {
return false
}
x, ok := fun.X.(*ast.Ident)
if !ok {
return false
}
targetName := x.Name + "." + fun.Sel.Name
obj := pass.TypesInfo.ObjectOf(fun.Sel)
targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name())
if targetName == "os.Setenv" {
if argName == "" {
argName = "testing"
Expand All @@ -121,11 +119,8 @@ func checkArgs(pass *analysis.Pass, args []ast.Expr, funcName, argName string) {
if !ok {
continue
}
x, ok := fun.X.(*ast.Ident)
if !ok {
continue
}
targetName := x.Name + "." + fun.Sel.Name
obj := pass.TypesInfo.ObjectOf(fun.Sel)
targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name())
if targetName == "os.Setenv" {
if argName == "" {
argName = "testing"
Expand All @@ -148,11 +143,8 @@ func checkIfStmt(pass *analysis.Pass, stmt *ast.IfStmt, funcName, argName string
if !ok {
return false
}
x, ok := fun.X.(*ast.Ident)
if !ok {
return false
}
targetName := x.Name + "." + fun.Sel.Name
obj := pass.TypesInfo.ObjectOf(fun.Sel)
targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name())
if targetName == "os.Setenv" {
if argName == "" {
argName = "testing"
Expand All @@ -171,11 +163,8 @@ func checkAssignStmt(pass *analysis.Pass, stmt *ast.AssignStmt, funcName, argNam
if !ok {
return false
}
x, ok := fun.X.(*ast.Ident)
if !ok {
return false
}
targetName := x.Name + "." + fun.Sel.Name
obj := pass.TypesInfo.ObjectOf(fun.Sel)
targetName := fmt.Sprintf("%s.%s", obj.Pkg().Name(), obj.Name())
if targetName == "os.Setenv" {
if argName == "" {
argName = "testing"
Expand All @@ -189,19 +178,19 @@ func checkForStmt(pass *analysis.Pass, stmt *ast.ForStmt, funcName, argName stri
checkStmts(pass, stmt.Body.List, funcName, argName)
}

func targetRunner(params []*ast.Field, fileName string) (string, bool) {
func targetRunner(pass *analysis.Pass, params []*ast.Field, fileName string) (string, bool) {
for _, p := range params {
switch typ := p.Type.(type) {
case *ast.StarExpr:
if checkStarExprTarget(typ) {
if checkStarExprTarget(pass, typ) {
if len(p.Names) == 0 {
return "", false
}
argName := p.Names[0].Name
return argName, true
}
case *ast.SelectorExpr:
if checkSelectorExprTarget(typ) {
if checkSelectorExprTarget(pass, typ) {
if len(p.Names) == 0 {
return "", false
}
Expand All @@ -216,29 +205,19 @@ func targetRunner(params []*ast.Field, fileName string) (string, bool) {
return "", false
}

func checkStarExprTarget(typ *ast.StarExpr) bool {
func checkStarExprTarget(pass *analysis.Pass, typ *ast.StarExpr) bool {
selector, ok := typ.X.(*ast.SelectorExpr)
if !ok {
return false
}
x, ok := selector.X.(*ast.Ident)
if !ok {
return false
}
targetName := x.Name + "." + selector.Sel.Name
switch targetName {
switch pass.TypesInfo.TypeOf(selector).String() {
case "testing.T", "testing.B":
return true
default:
return false
}
}

func checkSelectorExprTarget(typ *ast.SelectorExpr) bool {
x, ok := typ.X.(*ast.Ident)
if !ok {
return false
}
targetName := x.Name + "." + typ.Sel.Name
return targetName == "testing.TB"
func checkSelectorExprTarget(pass *analysis.Pass, typ *ast.SelectorExpr) bool {
return pass.TypesInfo.TypeOf(typ).String() == "testing.TB"
}
104 changes: 104 additions & 0 deletions testdata/src/a/a_custom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package a

import (
"fmt"
"os"
"testing"
mytest "testing"

"github.com/stretchr/testify/require"
)

var (
e2 = os.Setenv("a", "b") // never seen
)

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"
if err != nil {
_ = err
}
os.Setenv("a", "b") // if -all = true, "func setup is not using testing.Setenv"
}

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"
_ = err
if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestF"
_ = 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"
_ = err
if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `b\\.Setenv\\(\\)` in BenchmarkF"
_ = 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"
_ = err
if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `tb\\.Setenv\\(\\)` in TB"
_ = err
}
}

func TestFunctionLiteral2(t *mytest.T) {
testsetup()
t.Run("test", func(t *mytest.T) {
os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function"
err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function"
_ = err
if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function"
_ = err
}
})
}

func TestEmpty2(t *mytest.T) {
t.Run("test", func(*testing.T) {})
}

func TestEmptyTB2(t *mytest.T) {
func(testing.TB) {}(t)
}

func TestTDD2(t *mytest.T) {
for _, tt := range []struct {
name string
}{
{"test"},
} {
t.Run(tt.name, func(t *testing.T) {
os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function"
err := os.Setenv("a", "b") // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function"
_ = err
if err := os.Setenv("a", "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in anonymous function"
_ = err
}
})
}
}

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"
_ = err
if err := os.Setenv(fmt.Sprintf("a%d", i), "b"); err != nil { // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestLoop"
_ = err
}
}
}

func TestUsingArg2(t *mytest.T) {
require.NoError(t, os.Setenv("a", "b")) // want "os\\.Setenv\\(\\) can be replaced by `t\\.Setenv\\(\\)` in TestUsingArg"
}

0 comments on commit 7b68c50

Please sign in to comment.