2024-03-27 19:24:38 +01:00
|
|
|
package src
|
|
|
|
|
|
|
|
import "context"
|
|
|
|
|
|
|
|
func example() {
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
ctx := context.WithValue(ctx, "key", i)
|
|
|
|
ctx = context.WithValue(ctx, "other", "val")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
2024-03-27 23:50:12 +01:00
|
|
|
ctx = context.WithValue(ctx, "key", i) // want "nested context in loop"
|
2024-03-27 19:24:38 +01:00
|
|
|
ctx = context.WithValue(ctx, "other", "val")
|
|
|
|
}
|
|
|
|
|
|
|
|
for item := range []string{"one", "two", "three"} {
|
2024-03-27 23:50:12 +01:00
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
2024-03-27 19:24:38 +01:00
|
|
|
ctx := context.WithValue(ctx, "key", item)
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
2024-03-27 23:50:12 +01:00
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
2024-03-27 19:24:38 +01:00
|
|
|
break
|
|
|
|
}
|
2024-07-12 12:04:01 +02:00
|
|
|
|
|
|
|
// not fooled by shadowing in nested blocks
|
|
|
|
for {
|
|
|
|
err := doSomething()
|
|
|
|
if err != nil {
|
|
|
|
ctx := wrapContext(ctx)
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch err {
|
|
|
|
case nil:
|
|
|
|
ctx := wrapContext(ctx)
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
default:
|
|
|
|
ctx := wrapContext(ctx)
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ctx := wrapContext(ctx)
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
ctx := wrapContext(ctx)
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
2024-03-27 19:24:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func wrapContext(ctx context.Context) context.Context {
|
|
|
|
return context.WithoutCancel(ctx)
|
|
|
|
}
|
2024-05-29 16:47:58 +02:00
|
|
|
|
2024-07-12 12:04:01 +02:00
|
|
|
func doSomething() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-05-29 16:47:58 +02:00
|
|
|
// 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")
|
|
|
|
}
|
|
|
|
|
2024-05-29 17:07:03 +02:00
|
|
|
r := []struct{ Ctx context.Context }{{ctx}}
|
2024-05-29 16:47:58 +02:00
|
|
|
for i := 0; i < 10; i++ {
|
2024-05-29 17:07:03 +02:00
|
|
|
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")
|
2024-05-29 16:47:58 +02:00
|
|
|
}
|
|
|
|
}
|
2024-07-12 12:04:01 +02:00
|
|
|
|
|
|
|
func inVariousNestedBlocks(ctx context.Context) {
|
|
|
|
for {
|
|
|
|
err := doSomething()
|
|
|
|
if err != nil {
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
err := doSomething()
|
|
|
|
if err != nil {
|
|
|
|
if true {
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
err := doSomething()
|
|
|
|
switch err {
|
|
|
|
case nil:
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
err := doSomething()
|
|
|
|
switch err {
|
|
|
|
default:
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
ctx := wrapContext(ctx)
|
|
|
|
|
|
|
|
err := doSomething()
|
|
|
|
if err != nil {
|
|
|
|
ctx = wrapContext(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
{
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
ctx = wrapContext(ctx) // want "nested context in loop"
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|