woodpecker/vendor/github.com/moricho/tparallel/tparallel.go

73 lines
1.9 KiB
Go
Raw Normal View History

package tparallel
import (
"go/types"
"github.com/gostaticanalysis/analysisutil"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"github.com/moricho/tparallel/pkg/ssafunc"
)
const doc = "tparallel detects inappropriate usage of t.Parallel() method in your Go test codes."
// Analyzer analyzes Go test codes whether they use t.Parallel() appropriately
// by using SSA (Single Static Assignment)
var Analyzer = &analysis.Analyzer{
Name: "tparallel",
Doc: doc,
Run: run,
Requires: []*analysis.Analyzer{
buildssa.Analyzer,
},
}
func run(pass *analysis.Pass) (interface{}, error) {
ssaanalyzer := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
obj := analysisutil.ObjectOf(pass, "testing", "T")
if obj == nil {
// skip checking
return nil, nil
}
testTyp, testPkg := obj.Type(), obj.Pkg()
p, _, _ := types.LookupFieldOrMethod(testTyp, true, testPkg, "Parallel")
parallel, _ := p.(*types.Func)
c, _, _ := types.LookupFieldOrMethod(testTyp, true, testPkg, "Cleanup")
cleanup, _ := c.(*types.Func)
testMap := getTestMap(ssaanalyzer, testTyp) // ex. {Test1: [TestSub1, TestSub2], Test2: [TestSub1, TestSub2, TestSub3], ...}
for top, subs := range testMap {
if len(subs) == 0 {
continue
}
isParallelTop := ssafunc.IsCalled(top, parallel)
isPararellSub := false
for _, sub := range subs {
isPararellSub = ssafunc.IsCalled(sub, parallel)
if isPararellSub {
break
}
}
if ssafunc.IsDeferCalled(top) {
useCleanup := ssafunc.IsCalled(top, cleanup)
if isPararellSub && !useCleanup {
pass.Reportf(top.Pos(), "%s should use t.Cleanup instead of defer", top.Name())
}
}
if isParallelTop == isPararellSub {
continue
} else if isPararellSub {
pass.Reportf(top.Pos(), "%s should call t.Parallel on the top level as well as its subtests", top.Name())
} else if isParallelTop {
pass.Reportf(top.Pos(), "%s's subtests should call t.Parallel", top.Name())
}
}
return nil, nil
}