mirror of
https://github.com/Crocmagnon/fatcontext.git
synced 2024-11-22 07:58:05 +01:00
feat: Improve detection of nested contexts in function literals
This commit is contained in:
parent
0f9412c2ac
commit
b46089e786
2 changed files with 37 additions and 4 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/printer"
|
"go/printer"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||||
|
@ -174,7 +175,7 @@ func findNestedContext(pass *analysis.Pass, block *ast.BlockStmt, stmts []ast.St
|
||||||
// allow assignment to non-pointer children of values defined within the loop
|
// allow assignment to non-pointer children of values defined within the loop
|
||||||
if lhs := getRootIdent(pass, assignStmt.Lhs[0]); lhs != nil {
|
if lhs := getRootIdent(pass, assignStmt.Lhs[0]); lhs != nil {
|
||||||
if obj := pass.TypesInfo.ObjectOf(lhs); obj != nil {
|
if obj := pass.TypesInfo.ObjectOf(lhs); obj != nil {
|
||||||
if obj.Pos() >= block.Pos() && obj.Pos() < block.End() {
|
if checkObjectScopeWithinBlock(obj.Parent(), block) {
|
||||||
continue // definition is within the loop
|
continue // definition is within the loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +187,18 @@ func findNestedContext(pass *analysis.Pass, block *ast.BlockStmt, stmts []ast.St
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkObjectScopeWithinBlock(scope *types.Scope, block *ast.BlockStmt) bool {
|
||||||
|
if scope == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope.Pos() >= block.Pos() && scope.End() <= block.End() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func getRootIdent(pass *analysis.Pass, node ast.Node) *ast.Ident {
|
func getRootIdent(pass *analysis.Pass, node ast.Node) *ast.Ident {
|
||||||
for {
|
for {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
|
|
26
testdata/src/example.go
vendored
26
testdata/src/example.go
vendored
|
@ -188,9 +188,29 @@ func inVariousNestedBlocks(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this middleware could run on every request, bloating the request parameter level context and causing a memory leak
|
// this middleware could run on every request, bloating the request parameter level context and causing a memory leak
|
||||||
func memoryLeakCausingMiddleware(ctx context.Context) func(ctx context.Context) error {
|
func badMiddleware(ctx context.Context) func() error {
|
||||||
return func(ctx context.Context) error {
|
return func() error {
|
||||||
ctx = wrapContext(ctx) // want "nested context in function literal"
|
ctx = wrapContext(ctx) // want "nested context in function literal"
|
||||||
return doSomething()
|
return doSomethingWithCtx(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this middleware is fine, as it doesn't modify the context of parent function
|
||||||
|
func okMiddleware(ctx context.Context) func() error {
|
||||||
|
return func() error {
|
||||||
|
ctx := wrapContext(ctx)
|
||||||
|
return doSomethingWithCtx(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this middleware is fine, as it only modifies the context passed to it
|
||||||
|
func okMiddleware2(ctx context.Context) func(ctx context.Context) error {
|
||||||
|
return func(ctx context.Context) error {
|
||||||
|
ctx = wrapContext(ctx)
|
||||||
|
return doSomethingWithCtx(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doSomethingWithCtx(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue