@@ -58,10 +58,11 @@ type freeRef struct {
58
58
59
59
// An object abstracts a free types.Object referenced by the callee. Gob-serializable.
60
60
type object struct {
61
- Name string // Object.Name()
62
- Kind string // one of {var,func,const,type,pkgname,nil,builtin}
63
- PkgPath string // pkgpath of object (or of imported package if kind="pkgname")
64
- ValidPos bool // Object.Pos().IsValid()
61
+ Name string // Object.Name()
62
+ Kind string // one of {var,func,const,type,pkgname,nil,builtin}
63
+ PkgPath string // pkgpath of object (or of imported package if kind="pkgname")
64
+ ValidPos bool // Object.Pos().IsValid()
65
+ Shadow map [string ]bool // names shadowed at one of the object's refs
65
66
}
66
67
67
68
// AnalyzeCallee analyzes a function that is a candidate for inlining
@@ -119,7 +120,14 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
119
120
)
120
121
var f func (n ast.Node ) bool
121
122
visit := func (n ast.Node ) { ast .Inspect (n , f ) }
123
+ var stack []ast.Node
124
+ stack = append (stack , decl .Type ) // for scope of function itself
122
125
f = func (n ast.Node ) bool {
126
+ if n != nil {
127
+ stack = append (stack , n ) // push
128
+ } else {
129
+ stack = stack [:len (stack )- 1 ] // pop
130
+ }
123
131
switch n := n .(type ) {
124
132
case * ast.SelectorExpr :
125
133
// Check selections of free fields/methods.
@@ -198,6 +206,8 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
198
206
freeObjIndex [obj ] = objidx
199
207
}
200
208
209
+ freeObjs [objidx ].Shadow = addShadows (freeObjs [objidx ].Shadow , info , obj .Name (), stack )
210
+
201
211
freeRefs = append (freeRefs , freeRef {
202
212
Offset : int (n .Pos () - decl .Pos ()),
203
213
Object : objidx ,
@@ -417,6 +427,9 @@ func analyzeParams(logf func(string, ...any), fset *token.FileSet, info *types.I
417
427
418
428
// Record locations of all references to parameters.
419
429
// And record the set of intervening definitions for each parameter.
430
+ //
431
+ // TODO(adonovan): combine this traversal with the one that computes
432
+ // FreeRefs. The tricky part is that calleefx needs this one first.
420
433
var stack []ast.Node
421
434
stack = append (stack , decl .Type ) // for scope of function itself
422
435
ast .Inspect (decl .Body , func (n ast.Node ) bool {
@@ -429,26 +442,11 @@ func analyzeParams(logf func(string, ...any), fset *token.FileSet, info *types.I
429
442
if id , ok := n .(* ast.Ident ); ok {
430
443
if v , ok := info .Uses [id ].(* types.Var ); ok {
431
444
if pinfo , ok := paramInfos [v ]; ok {
432
- // Record location of ref to parameter/result.
445
+ // Record location of ref to parameter/result
446
+ // and any intervening (shadowing) names.
433
447
offset := int (n .Pos () - decl .Pos ())
434
448
pinfo .Refs = append (pinfo .Refs , offset )
435
-
436
- // Find set of names shadowed within body
437
- // (excluding the parameter itself).
438
- // If these names are free in the arg expression,
439
- // we can't substitute the parameter.
440
- for _ , n := range stack {
441
- if scope , ok := info .Scopes [n ]; ok {
442
- for _ , name := range scope .Names () {
443
- if name != pinfo .Name {
444
- if pinfo .Shadow == nil {
445
- pinfo .Shadow = make (map [string ]bool )
446
- }
447
- pinfo .Shadow [name ] = true
448
- }
449
- }
450
- }
451
- }
449
+ pinfo .Shadow = addShadows (pinfo .Shadow , info , pinfo .Name , stack )
452
450
}
453
451
}
454
452
}
@@ -465,6 +463,29 @@ func analyzeParams(logf func(string, ...any), fset *token.FileSet, info *types.I
465
463
466
464
// -- callee helpers --
467
465
466
+ // addShadows returns the shadows set augmented by the set of names
467
+ // locally shadowed at the location of the reference in the callee
468
+ // (identified by the stack). The name of the reference itself is
469
+ // excluded.
470
+ //
471
+ // These shadowed names may not be used in a replacement expression
472
+ // for the reference.
473
+ func addShadows (shadows map [string ]bool , info * types.Info , exclude string , stack []ast.Node ) map [string ]bool {
474
+ for _ , n := range stack {
475
+ if scope , ok := info .Scopes [n ]; ok {
476
+ for _ , name := range scope .Names () {
477
+ if name != exclude {
478
+ if shadows == nil {
479
+ shadows = make (map [string ]bool )
480
+ }
481
+ shadows [name ] = true
482
+ }
483
+ }
484
+ }
485
+ }
486
+ return shadows
487
+ }
488
+
468
489
// deref removes a pointer type constructor from the core type of t.
469
490
func deref (t types.Type ) types.Type {
470
491
if ptr , ok := typeparams .CoreType (t ).(* types.Pointer ); ok {
0 commit comments