var doc … var Analyzer … func run(pass *analysis.Pass) (interface{ … } // reportCaptured reports a diagnostic stating a loop variable // has been captured by a func literal if checkStmt has escaping // references to vars. vars is expected to be variables updated by a loop statement, // and checkStmt is expected to be a statements from the body of a func literal in the loop. func reportCaptured(pass *analysis.Pass, vars []types.Object, checkStmt ast.Stmt) { … } // forEachLastStmt calls onLast on each "last" statement in a list of statements. // "Last" is defined recursively so, for example, if the last statement is // a switch statement, then each switch case is also visited to examine // its last statements. func forEachLastStmt(stmts []ast.Stmt, onLast func(last ast.Stmt)) { … } // litStmts returns all statements from the function body of a function // literal. // // If fun is not a function literal, it returns nil. func litStmts(fun ast.Expr) []ast.Stmt { … } // goInvoke returns a function expression that would be called asynchronously // (but not awaited) in another goroutine as a consequence of the call. // For example, given the g.Go call below, it returns the function literal expression. // // import "sync/errgroup" // var g errgroup.Group // g.Go(func() error { ... }) // // Currently only "golang.org/x/sync/errgroup.Group()" is considered. func goInvoke(info *types.Info, call *ast.CallExpr) ast.Expr { … } // parallelSubtest returns statements that can be easily proven to execute // concurrently via the go test runner, as t.Run has been invoked with a // function literal that calls t.Parallel. // // In practice, users rely on the fact that statements before the call to // t.Parallel are synchronous. For example by declaring test := test inside the // function literal, but before the call to t.Parallel. // // Therefore, we only flag references in statements that are obviously // dominated by a call to t.Parallel. As a simple heuristic, we only consider // statements following the final labeled statement in the function body, to // avoid scenarios where a jump would cause either the call to t.Parallel or // the problematic reference to be skipped. // // import "testing" // // func TestFoo(t *testing.T) { // tests := []int{0, 1, 2} // for i, test := range tests { // t.Run("subtest", func(t *testing.T) { // println(i, test) // OK // t.Parallel() // println(i, test) // Not OK // }) // } // } func parallelSubtest(info *types.Info, call *ast.CallExpr) []ast.Stmt { … } // unlabel returns the inner statement for the possibly labeled statement stmt, // stripping any (possibly nested) *ast.LabeledStmt wrapper. // // The second result reports whether stmt was an *ast.LabeledStmt. func unlabel(stmt ast.Stmt) (ast.Stmt, bool) { … } // isMethodCall reports whether expr is a method call of // <pkgPath>.<typeName>.<method>. func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method string) bool { … }