mirror of
https://github.com/Crocmagnon/fatcontext.git
synced 2024-11-21 23:48:10 +01:00
Merge pull request #9 from MichaelUrman/contained
Some checks failed
Go / build (1.21, macos-latest) (push) Has been cancelled
Go / build (1.21, ubuntu-latest) (push) Has been cancelled
Go / build (1.21, windows-latest) (push) Has been cancelled
Go / build (1.22, macos-latest) (push) Has been cancelled
Go / build (1.22, ubuntu-latest) (push) Has been cancelled
Go / build (1.22, windows-latest) (push) Has been cancelled
golangci-lint / lint (1.21) (push) Has been cancelled
golangci-lint / lint (1.22) (push) Has been cancelled
Some checks failed
Go / build (1.21, macos-latest) (push) Has been cancelled
Go / build (1.21, ubuntu-latest) (push) Has been cancelled
Go / build (1.21, windows-latest) (push) Has been cancelled
Go / build (1.22, macos-latest) (push) Has been cancelled
Go / build (1.22, ubuntu-latest) (push) Has been cancelled
Go / build (1.22, windows-latest) (push) Has been cancelled
golangci-lint / lint (1.21) (push) Has been cancelled
golangci-lint / lint (1.22) (push) Has been cancelled
Test and fix cases with nested contexts
This commit is contained in:
commit
e8053df661
2 changed files with 69 additions and 0 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/printer"
|
"go/printer"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
|
||||||
"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"
|
||||||
"golang.org/x/tools/go/ast/inspector"
|
"golang.org/x/tools/go/ast/inspector"
|
||||||
|
@ -54,6 +55,15 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow assignment to non-pointer children of values defined within the loop
|
||||||
|
if lhs := getRootIdent(pass, assignStmt.Lhs[0]); lhs != nil {
|
||||||
|
if obj := pass.TypesInfo.ObjectOf(lhs); obj != nil {
|
||||||
|
if obj.Pos() >= body.Pos() && obj.Pos() < body.End() {
|
||||||
|
continue // definition is within the loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suggestedStmt := ast.AssignStmt{
|
suggestedStmt := ast.AssignStmt{
|
||||||
Lhs: assignStmt.Lhs,
|
Lhs: assignStmt.Lhs,
|
||||||
TokPos: assignStmt.TokPos,
|
TokPos: assignStmt.TokPos,
|
||||||
|
@ -103,6 +113,24 @@ func getBody(node ast.Node) (*ast.BlockStmt, error) {
|
||||||
return nil, errUnknown
|
return nil, errUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRootIdent(pass *analysis.Pass, node ast.Node) *ast.Ident {
|
||||||
|
for {
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *ast.Ident:
|
||||||
|
return n
|
||||||
|
case *ast.IndexExpr:
|
||||||
|
node = n.X
|
||||||
|
case *ast.SelectorExpr:
|
||||||
|
if sel, ok := pass.TypesInfo.Selections[n]; ok && sel.Indirect() {
|
||||||
|
return nil // indirected (pointer) roots don't imply a (safe) copy
|
||||||
|
}
|
||||||
|
node = n.X
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// render returns the pretty-print of the given node
|
// render returns the pretty-print of the given node
|
||||||
func render(fset *token.FileSet, x interface{}) (string, error) {
|
func render(fset *token.FileSet, x interface{}) (string, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
41
testdata/src/example.go
vendored
41
testdata/src/example.go
vendored
|
@ -30,3 +30,44 @@ func example() {
|
||||||
func wrapContext(ctx context.Context) context.Context {
|
func wrapContext(ctx context.Context) context.Context {
|
||||||
return context.WithoutCancel(ctx)
|
return context.WithoutCancel(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// storing contexts in a struct isn't recommended, but local copies of a non-pointer struct should act like local copies of a context.
|
||||||
|
func inStructs(ctx context.Context) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
c := struct{ Ctx context.Context }{ctx}
|
||||||
|
c.Ctx = context.WithValue(c.Ctx, "key", i)
|
||||||
|
c.Ctx = context.WithValue(c.Ctx, "other", "val")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
c := []struct{ Ctx context.Context }{{ctx}}
|
||||||
|
c[0].Ctx = context.WithValue(c[0].Ctx, "key", i)
|
||||||
|
c[0].Ctx = context.WithValue(c[0].Ctx, "other", "val")
|
||||||
|
}
|
||||||
|
|
||||||
|
c := struct{ Ctx context.Context }{ctx}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
c := c
|
||||||
|
c.Ctx = context.WithValue(c.Ctx, "key", i)
|
||||||
|
c.Ctx = context.WithValue(c.Ctx, "other", "val")
|
||||||
|
}
|
||||||
|
|
||||||
|
pc := &struct{ Ctx context.Context }{ctx}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
c := pc
|
||||||
|
c.Ctx = context.WithValue(c.Ctx, "key", i) // want "nested context in loop"
|
||||||
|
c.Ctx = context.WithValue(c.Ctx, "other", "val")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := []struct{ Ctx context.Context }{{ctx}}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
r[0].Ctx = context.WithValue(r[0].Ctx, "key", i) // want "nested context in loop"
|
||||||
|
r[0].Ctx = context.WithValue(r[0].Ctx, "other", "val")
|
||||||
|
}
|
||||||
|
|
||||||
|
rp := []*struct{ Ctx context.Context }{{ctx}}
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
rp[0].Ctx = context.WithValue(rp[0].Ctx, "key", i) // want "nested context in loop"
|
||||||
|
rp[0].Ctx = context.WithValue(rp[0].Ctx, "other", "val")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue