diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-22 16:07:17 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-23 10:42:36 +0000 |
| commit | 7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch) | |
| tree | e6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/kulti | |
| parent | 475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff) | |
vendor: delete
Diffstat (limited to 'vendor/github.com/kulti')
| -rw-r--r-- | vendor/github.com/kulti/thelper/LICENSE | 21 | ||||
| -rw-r--r-- | vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go | 639 | ||||
| -rw-r--r-- | vendor/github.com/kulti/thelper/pkg/analyzer/report.go | 56 |
3 files changed, 0 insertions, 716 deletions
diff --git a/vendor/github.com/kulti/thelper/LICENSE b/vendor/github.com/kulti/thelper/LICENSE deleted file mode 100644 index e070215fe..000000000 --- a/vendor/github.com/kulti/thelper/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Aleksey Bakin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go b/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go deleted file mode 100644 index a22fd6aca..000000000 --- a/vendor/github.com/kulti/thelper/pkg/analyzer/analyzer.go +++ /dev/null @@ -1,639 +0,0 @@ -package analyzer - -import ( - "flag" - "fmt" - "go/ast" - "go/token" - "go/types" - "sort" - "strings" - - "github.com/gostaticanalysis/analysisutil" - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/ast/inspector" -) - -const ( - doc = "thelper detects tests helpers which is not start with t.Helper() method." - checksDoc = `coma separated list of enabled checks - -Available checks - -` + checkTBegin + ` - check t.Helper() begins helper function -` + checkTFirst + ` - check *testing.T is first param of helper function -` + checkTName + ` - check *testing.T param has t name - -Also available similar checks for benchmark and TB helpers: ` + - checkFBegin + `, ` + checkFFirst + `, ` + checkFName + `,` + - checkBBegin + `, ` + checkBFirst + `, ` + checkBName + `,` + - checkTBBegin + `, ` + checkTBFirst + `, ` + checkTBName + ` - -` -) - -type enabledChecksValue map[string]struct{} - -func (m enabledChecksValue) Enabled(c string) bool { - _, ok := m[c] - return ok -} - -func (m enabledChecksValue) String() string { - ss := make([]string, 0, len(m)) - for s := range m { - ss = append(ss, s) - } - sort.Strings(ss) - return strings.Join(ss, ",") -} - -func (m enabledChecksValue) Set(s string) error { - ss := strings.FieldsFunc(s, func(c rune) bool { return c == ',' }) - if len(ss) == 0 { - return nil - } - - for k := range m { - delete(m, k) - } - for _, v := range ss { - switch v { - case checkTBegin, checkTFirst, checkTName, - checkFBegin, checkFFirst, checkFName, - checkBBegin, checkBFirst, checkBName, - checkTBBegin, checkTBFirst, checkTBName: - m[v] = struct{}{} - default: - return fmt.Errorf("unknown check name %q (see help for full list)", v) - } - } - return nil -} - -const ( - checkTBegin = "t_begin" - checkTFirst = "t_first" - checkTName = "t_name" - checkFBegin = "f_begin" - checkFFirst = "f_first" - checkFName = "f_name" - checkBBegin = "b_begin" - checkBFirst = "b_first" - checkBName = "b_name" - checkTBBegin = "tb_begin" - checkTBFirst = "tb_first" - checkTBName = "tb_name" -) - -type thelper struct { - enabledChecks enabledChecksValue -} - -// NewAnalyzer return a new thelper analyzer. -// thelper analyzes Go test codes how they use t.Helper() method. -func NewAnalyzer() *analysis.Analyzer { - thelper := thelper{} - thelper.enabledChecks = enabledChecksValue{ - checkTBegin: struct{}{}, - checkTFirst: struct{}{}, - checkTName: struct{}{}, - checkFBegin: struct{}{}, - checkFFirst: struct{}{}, - checkFName: struct{}{}, - checkBBegin: struct{}{}, - checkBFirst: struct{}{}, - checkBName: struct{}{}, - checkTBBegin: struct{}{}, - checkTBFirst: struct{}{}, - checkTBName: struct{}{}, - } - - a := &analysis.Analyzer{ - Name: "thelper", - Doc: doc, - Run: thelper.run, - Requires: []*analysis.Analyzer{ - inspect.Analyzer, - }, - } - - a.Flags.Init("thelper", flag.ExitOnError) - a.Flags.Var(&thelper.enabledChecks, "checks", checksDoc) - - return a -} - -func (t thelper) run(pass *analysis.Pass) (interface{}, error) { - tCheckOpts, fCheckOpts, bCheckOpts, tbCheckOpts, ok := t.buildCheckFuncOpts(pass) - if !ok { - return nil, nil - } - - inspect, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - if !ok { - return nil, nil - } - - var reports reports - nodeFilter := []ast.Node{ - (*ast.FuncDecl)(nil), - (*ast.FuncLit)(nil), - (*ast.CallExpr)(nil), - } - inspect.Preorder(nodeFilter, func(node ast.Node) { - var fd funcDecl - switch n := node.(type) { - case *ast.FuncLit: - fd.Pos = n.Pos() - fd.Type = n.Type - fd.Body = n.Body - fd.Name = ast.NewIdent("") - case *ast.FuncDecl: - fd.Pos = n.Name.NamePos - fd.Type = n.Type - fd.Body = n.Body - fd.Name = n.Name - case *ast.CallExpr: - runSubtestExprs := extractSubtestExp(pass, n, tCheckOpts.subRun, tCheckOpts.subTestFuncType) - if len(runSubtestExprs) == 0 { - runSubtestExprs = extractSubtestExp(pass, n, bCheckOpts.subRun, bCheckOpts.subTestFuncType) - } - if len(runSubtestExprs) == 0 { - runSubtestExprs = extractSubtestFuzzExp(pass, n, fCheckOpts.subRun) - } - - if len(runSubtestExprs) > 0 { - for _, expr := range runSubtestExprs { - reports.Filter(funcDefPosition(pass, expr)) - } - } else { - reports.NoFilter(funcDefPosition(pass, n.Fun)) - } - return - default: - return - } - - checkFunc(pass, &reports, fd, tCheckOpts) - checkFunc(pass, &reports, fd, fCheckOpts) - checkFunc(pass, &reports, fd, bCheckOpts) - checkFunc(pass, &reports, fd, tbCheckOpts) - }) - - reports.Flush(pass) - - return nil, nil -} - -type checkFuncOpts struct { - skipPrefix string - varName string - fnHelper types.Object - subRun types.Object - subTestFuncType types.Type - hpType types.Type - ctxType types.Type - checkBegin bool - checkFirst bool - checkName bool -} - -func (t thelper) buildCheckFuncOpts(pass *analysis.Pass) (checkFuncOpts, checkFuncOpts, checkFuncOpts, checkFuncOpts, bool) { - var ctxType types.Type - ctxObj := analysisutil.ObjectOf(pass, "context", "Context") - if ctxObj != nil { - ctxType = ctxObj.Type() - } - - tCheckOpts, ok := t.buildTestCheckFuncOpts(pass, ctxType) - if !ok { - return checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, false - } - - fCheckOpts, ok := t.buildFuzzCheckFuncOpts(pass, ctxType) - if !ok { - return checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, false - } - - bCheckOpts, ok := t.buildBenchmarkCheckFuncOpts(pass, ctxType) - if !ok { - return checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, false - } - - tbCheckOpts, ok := t.buildTBCheckFuncOpts(pass, ctxType) - if !ok { - return checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, checkFuncOpts{}, false - } - - return tCheckOpts, fCheckOpts, bCheckOpts, tbCheckOpts, true -} - -func (t thelper) buildTestCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - tObj := analysisutil.ObjectOf(pass, "testing", "T") - if tObj == nil { - return checkFuncOpts{}, false - } - - tHelper, _, _ := types.LookupFieldOrMethod(tObj.Type(), true, tObj.Pkg(), "Helper") - if tHelper == nil { - return checkFuncOpts{}, false - } - - tRun, _, _ := types.LookupFieldOrMethod(tObj.Type(), true, tObj.Pkg(), "Run") - if tRun == nil { - return checkFuncOpts{}, false - } - - tType := types.NewPointer(tObj.Type()) - tVar := types.NewVar(token.NoPos, nil, "t", tType) - return checkFuncOpts{ - skipPrefix: "Test", - varName: "t", - fnHelper: tHelper, - subRun: tRun, - hpType: tType, - subTestFuncType: types.NewSignature(nil, types.NewTuple(tVar), nil, false), - ctxType: ctxType, - checkBegin: t.enabledChecks.Enabled(checkTBegin), - checkFirst: t.enabledChecks.Enabled(checkTFirst), - checkName: t.enabledChecks.Enabled(checkTName), - }, true -} - -func (t thelper) buildFuzzCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - fObj := analysisutil.ObjectOf(pass, "testing", "F") - if fObj == nil { - return checkFuncOpts{}, true // fuzzing supports since go1.18, it's ok, that testig.F is missed. - } - - fHelper, _, _ := types.LookupFieldOrMethod(fObj.Type(), true, fObj.Pkg(), "Helper") - if fHelper == nil { - return checkFuncOpts{}, false - } - - tFuzz, _, _ := types.LookupFieldOrMethod(fObj.Type(), true, fObj.Pkg(), "Fuzz") - if tFuzz == nil { - return checkFuncOpts{}, false - } - - return checkFuncOpts{ - skipPrefix: "Fuzz", - varName: "f", - fnHelper: fHelper, - subRun: tFuzz, - hpType: types.NewPointer(fObj.Type()), - ctxType: ctxType, - checkBegin: t.enabledChecks.Enabled(checkFBegin), - checkFirst: t.enabledChecks.Enabled(checkFFirst), - checkName: t.enabledChecks.Enabled(checkFName), - }, true -} - -func (t thelper) buildBenchmarkCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - bObj := analysisutil.ObjectOf(pass, "testing", "B") - if bObj == nil { - return checkFuncOpts{}, false - } - - bHelper, _, _ := types.LookupFieldOrMethod(bObj.Type(), true, bObj.Pkg(), "Helper") - if bHelper == nil { - return checkFuncOpts{}, false - } - - bRun, _, _ := types.LookupFieldOrMethod(bObj.Type(), true, bObj.Pkg(), "Run") - if bRun == nil { - return checkFuncOpts{}, false - } - - bType := types.NewPointer(bObj.Type()) - bVar := types.NewVar(token.NoPos, nil, "b", bType) - return checkFuncOpts{ - skipPrefix: "Benchmark", - varName: "b", - fnHelper: bHelper, - subRun: bRun, - hpType: types.NewPointer(bObj.Type()), - subTestFuncType: types.NewSignature(nil, types.NewTuple(bVar), nil, false), - ctxType: ctxType, - checkBegin: t.enabledChecks.Enabled(checkBBegin), - checkFirst: t.enabledChecks.Enabled(checkBFirst), - checkName: t.enabledChecks.Enabled(checkBName), - }, true -} - -func (t thelper) buildTBCheckFuncOpts(pass *analysis.Pass, ctxType types.Type) (checkFuncOpts, bool) { - tbObj := analysisutil.ObjectOf(pass, "testing", "TB") - if tbObj == nil { - return checkFuncOpts{}, false - } - - tbHelper, _, _ := types.LookupFieldOrMethod(tbObj.Type(), true, tbObj.Pkg(), "Helper") - if tbHelper == nil { - return checkFuncOpts{}, false - } - - return checkFuncOpts{ - skipPrefix: "", - varName: "tb", - fnHelper: tbHelper, - hpType: tbObj.Type(), - ctxType: ctxType, - checkBegin: t.enabledChecks.Enabled(checkTBBegin), - checkFirst: t.enabledChecks.Enabled(checkTBFirst), - checkName: t.enabledChecks.Enabled(checkTBName), - }, true -} - -type funcDecl struct { - Pos token.Pos - Name *ast.Ident - Type *ast.FuncType - Body *ast.BlockStmt -} - -func checkFunc(pass *analysis.Pass, reports *reports, funcDecl funcDecl, opts checkFuncOpts) { - if !opts.checkFirst && !opts.checkBegin && !opts.checkName { - return - } - - if opts.skipPrefix != "" && strings.HasPrefix(funcDecl.Name.Name, opts.skipPrefix) { - return - } - - p, pos, ok := searchFuncParam(pass, funcDecl, opts.hpType) - if !ok { - return - } - - if opts.checkFirst { - if pos != 0 { - checkFirstPassed := false - if pos == 1 && opts.ctxType != nil { - _, pos, ok := searchFuncParam(pass, funcDecl, opts.ctxType) - checkFirstPassed = ok && (pos == 0) - } - - if !checkFirstPassed { - reports.Reportf(funcDecl.Pos, "parameter %s should be the first or after context.Context", opts.hpType) - } - } - } - - if len(p.Names) > 0 && p.Names[0].Name != "_" { - if opts.checkName { - if p.Names[0].Name != opts.varName { - reports.Reportf(funcDecl.Pos, "parameter %s should have name %s", opts.hpType, opts.varName) - } - } - - if opts.checkBegin { - if len(funcDecl.Body.List) == 0 || !isTHelperCall(pass, funcDecl.Body.List[0], opts.fnHelper) { - reports.Reportf(funcDecl.Pos, "test helper function should start from %s.Helper()", opts.varName) - } - } - } -} - -// searchFuncParam search a function param with desired type. -// It returns the param field, its position, and true if something is found. -func searchFuncParam(pass *analysis.Pass, f funcDecl, p types.Type) (*ast.Field, int, bool) { - for i, f := range f.Type.Params.List { - if isExprHasType(pass, f.Type, p) { - return f, i, true - } - } - return nil, 0, false -} - -// isTHelperCall returns true if provided statement 's' is t.Helper() or b.Helper() call. -func isTHelperCall(pass *analysis.Pass, s ast.Stmt, tHelper types.Object) bool { - exprStmt, ok := s.(*ast.ExprStmt) - if !ok { - return false - } - - callExpr, ok := exprStmt.X.(*ast.CallExpr) - if !ok { - return false - } - - selExpr, ok := callExpr.Fun.(*ast.SelectorExpr) - if !ok { - return false - } - - return isSelectorCall(pass, selExpr, tHelper) -} - -// extractSubtestExp analyzes that call expresion 'e' is t.Run or b.Run -// and returns subtest function. -func extractSubtestExp( - pass *analysis.Pass, e *ast.CallExpr, tbRun types.Object, testFuncType types.Type, -) []ast.Expr { - selExpr, ok := e.Fun.(*ast.SelectorExpr) - if !ok { - return nil - } - - if !isSelectorCall(pass, selExpr, tbRun) { - return nil - } - - if len(e.Args) != 2 { - return nil - } - - if funcs := unwrapTestingFunctionBuilding(pass, e.Args[1], testFuncType); funcs != nil { - return funcs - } - - return []ast.Expr{e.Args[1]} -} - -// extractSubtestFuzzExp analyzes that call expresion 'e' is f.Fuzz -// and returns subtest function. -func extractSubtestFuzzExp( - pass *analysis.Pass, e *ast.CallExpr, fuzzRun types.Object, -) []ast.Expr { - selExpr, ok := e.Fun.(*ast.SelectorExpr) - if !ok { - return nil - } - - if !isSelectorCall(pass, selExpr, fuzzRun) { - return nil - } - - if len(e.Args) != 1 { - return nil - } - - return []ast.Expr{e.Args[0]} -} - -// unwrapTestingFunctionConstruction checks that expresion is build testing functions -// and returns the result of building. -func unwrapTestingFunctionBuilding(pass *analysis.Pass, expr ast.Expr, testFuncType types.Type) []ast.Expr { - callExpr, ok := expr.(*ast.CallExpr) - if !ok { - return nil - } - - var funcDecl funcDecl - switch f := callExpr.Fun.(type) { - case *ast.FuncLit: - funcDecl.Body = f.Body - funcDecl.Type = f.Type - case *ast.Ident: - funObjDecl := findFunctionDeclaration(pass, f) - if funObjDecl == nil { - return nil - } - - funcDecl.Body = funObjDecl.Body - funcDecl.Type = funObjDecl.Type - case *ast.SelectorExpr: - fd := findSelectorDeclaration(pass, f) - if fd == nil { - return nil - } - - funcDecl.Body = fd.Body - funcDecl.Type = fd.Type - default: - return nil - } - - results := funcDecl.Type.Results.List - if len(results) != 1 || !isExprHasType(pass, results[0].Type, testFuncType) { - return nil - } - - var funcs []ast.Expr - ast.Inspect(funcDecl.Body, func(n ast.Node) bool { - if n == nil { - return false - } - - if retStmt, ok := n.(*ast.ReturnStmt); ok { - if len(retStmt.Results) == 1 { - funcs = append(funcs, retStmt.Results[0]) - } - } - return true - }) - - return funcs -} - -// funcDefPosition returns a function's position. -// It works with anonymous functions as well with function names. -func funcDefPosition(pass *analysis.Pass, e ast.Expr) token.Pos { - anonFunLit, ok := e.(*ast.FuncLit) - if ok { - return anonFunLit.Pos() - } - - funIdent, ok := e.(*ast.Ident) - if !ok { - selExpr, ok := e.(*ast.SelectorExpr) - if !ok { - return token.NoPos - } - funIdent = selExpr.Sel - } - - funDef, ok := pass.TypesInfo.Uses[funIdent] - if !ok { - return token.NoPos - } - - return funDef.Pos() -} - -// isSelectorCall checks is selExpr is a call expresion on specific callObj. -// Useful to check Run() call for t.Run or b.Run. -func isSelectorCall(pass *analysis.Pass, selExpr *ast.SelectorExpr, callObj types.Object) bool { - sel, ok := pass.TypesInfo.Selections[selExpr] - if !ok { - return false - } - - return sel.Obj() == callObj -} - -// isExprHasType returns true if expr has expected type. -func isExprHasType(pass *analysis.Pass, expr ast.Expr, expType types.Type) bool { - typeInfo, ok := pass.TypesInfo.Types[expr] - if !ok { - return false - } - - return types.Identical(typeInfo.Type, expType) -} - -// findSelectorDeclaration returns function declaration called by selector expression. -func findSelectorDeclaration(pass *analysis.Pass, expr *ast.SelectorExpr) *ast.FuncDecl { - xsel, ok := pass.TypesInfo.Selections[expr] - if !ok { - return nil - } - - for _, file := range pass.Files { - for _, decl := range file.Decls { - fd, ok := decl.(*ast.FuncDecl) - if ok && fd.Recv != nil && len(fd.Recv.List) == 1 { - recvType, ok := fd.Recv.List[0].Type.(*ast.Ident) - if !ok { - continue - } - - recvObj, ok := pass.TypesInfo.Uses[recvType] - if !ok { - continue - } - - if !(types.Identical(recvObj.Type(), xsel.Recv())) { - continue - } - - if fd.Name.Name == expr.Sel.Name { - return fd - } - } - } - } - - return nil -} - -// findFunctionDeclaration returns function declaration called by identity. -func findFunctionDeclaration(pass *analysis.Pass, ident *ast.Ident) *ast.FuncDecl { - if ident.Obj != nil { - if funObjDecl, ok := ident.Obj.Decl.(*ast.FuncDecl); ok { - return funObjDecl - } - } - - obj := pass.TypesInfo.ObjectOf(ident) - if obj == nil { - return nil - } - - for _, file := range pass.Files { - for _, decl := range file.Decls { - funcDecl, ok := decl.(*ast.FuncDecl) - if !ok { - continue - } - - if funcDecl.Name.Pos() == obj.Pos() { - return funcDecl - } - } - } - - return nil -} diff --git a/vendor/github.com/kulti/thelper/pkg/analyzer/report.go b/vendor/github.com/kulti/thelper/pkg/analyzer/report.go deleted file mode 100644 index 4a23e36d5..000000000 --- a/vendor/github.com/kulti/thelper/pkg/analyzer/report.go +++ /dev/null @@ -1,56 +0,0 @@ -package analyzer - -import ( - "go/token" - - "golang.org/x/tools/go/analysis" -) - -type reports struct { - reports []report - filter map[token.Pos]struct{} - nofilter map[token.Pos]struct{} -} - -type report struct { - pos token.Pos - format string - args []interface{} -} - -func (rr *reports) Reportf(pos token.Pos, format string, args ...interface{}) { - rr.reports = append(rr.reports, report{ - pos: pos, - format: format, - args: args, - }) -} - -func (rr *reports) Filter(pos token.Pos) { - if pos.IsValid() { - if rr.filter == nil { - rr.filter = make(map[token.Pos]struct{}) - } - rr.filter[pos] = struct{}{} - } -} - -func (rr *reports) NoFilter(pos token.Pos) { - if pos.IsValid() { - if rr.nofilter == nil { - rr.nofilter = make(map[token.Pos]struct{}) - } - rr.nofilter[pos] = struct{}{} - } -} - -func (rr reports) Flush(pass *analysis.Pass) { - for _, r := range rr.reports { - if _, ok := rr.filter[r.pos]; ok { - if _, ok := rr.nofilter[r.pos]; !ok { - continue - } - } - pass.Reportf(r.pos, r.format, r.args...) - } -} |
