@@ -20,6 +20,8 @@ use std::collections::HashMap;
2020use  starlark:: codemap:: Pos ; 
2121use  starlark:: codemap:: Span ; 
2222use  starlark:: syntax:: AstModule ; 
23+ use  starlark_syntax:: syntax:: ast:: Argument ; 
24+ use  starlark_syntax:: syntax:: ast:: ArgumentP ; 
2325use  starlark_syntax:: syntax:: ast:: AssignIdentP ; 
2426use  starlark_syntax:: syntax:: ast:: AssignP ; 
2527use  starlark_syntax:: syntax:: ast:: AstAssignIdent ; 
@@ -33,6 +35,7 @@ use starlark_syntax::syntax::ast::AstTypeExpr;
3335use  starlark_syntax:: syntax:: ast:: Clause ; 
3436use  starlark_syntax:: syntax:: ast:: DefP ; 
3537use  starlark_syntax:: syntax:: ast:: Expr ; 
38+ use  starlark_syntax:: syntax:: ast:: ExprP ; 
3639use  starlark_syntax:: syntax:: ast:: ForClause ; 
3740use  starlark_syntax:: syntax:: ast:: ForP ; 
3841use  starlark_syntax:: syntax:: ast:: IdentP ; 
@@ -43,21 +46,35 @@ use starlark_syntax::syntax::module::AstModuleFields;
4346#[ derive( Debug ,  Clone ,  Eq ,  PartialEq ) ]  
4447pub ( crate )  enum  Assigner  { 
4548    /// Obtained from `load`. `name` is the symbol in that file, not necessarily the local name 
46- Load  { 
47-         path :  AstString , 
48-         name :  AstString , 
49-     } , 
50-     Argument ,  // From a function argument 
51-     Assign ,    // From an assignment 
49+ Load  {  path :  AstString ,  name :  AstString  } , 
50+     /// From a function call argument 
51+ Argument , 
52+     /// From an assignment 
53+ Assign , 
5254} 
5355
5456#[ derive( Debug ) ]  
5557pub ( crate )  enum  Bind  { 
56-     Set ( Assigner ,  AstAssignIdent ) ,  // Variable assigned to directly 
57-     Get ( AstIdent ) ,                  // Variable that is referenced 
58-     GetDotted ( GetDotted ) ,           // Variable is referenced, but is part of a dotted access 
59-     Flow ,          // Flow control occurs here (if, for etc) - can arrive or leave at this point 
60-     Scope ( Scope ) ,  // Entering a new scope (lambda/def/comprehension) 
58+     /// Variable assigned to directly 
59+ Set ( Assigner ,  AstAssignIdent ) , 
60+     /// Variable that is referenced 
61+ Get ( AstIdent ) , 
62+     /// Variable is referenced, but is part of a dotted access 
63+ GetDotted ( GetDotted ) , 
64+     /// An indirect reference, i.e. a named argument in a function call 
65+ IndirectReference ( IndirectReference ) , 
66+     /// Flow control occurs here (if, for etc) - can arrive or leave at this point 
67+ Flow , 
68+     /// Entering a new scope (lambda/def/comprehension) 
69+ Scope ( Scope ) , 
70+ } 
71+ 
72+ #[ derive( Debug ) ]  
73+ pub ( crate )  struct  IndirectReference  { 
74+     pub ( crate )  argument_name :  AstString , 
75+     // TODO: This could also be a dotted access, another function call, etc. These kinds of 
76+     // references are not captured at the moment. 
77+     pub ( crate )  function :  AstIdent , 
6178} 
6279
6380/// A 'get' bind that was part of a dotted member access pattern. 
@@ -123,7 +140,7 @@ impl Scope {
123140                Bind :: Scope ( scope)  => scope. free . iter ( ) . for_each ( |( k,  v) | { 
124141                    free. entry ( k. clone ( ) ) . or_insert ( * v) ; 
125142                } ) , 
126-                 Bind :: Flow  => { } 
143+                 Bind :: IndirectReference ( _ )  |  Bind :: Flow  => { } 
127144            } 
128145        } 
129146        for  x in  bound. keys ( )  { 
@@ -183,10 +200,19 @@ fn dot_access<'a>(lhs: &'a AstExpr, attribute: &'a AstString, res: &mut Vec<Bind
183200                attributes. push ( attribute) ; 
184201                f ( lhs,  attributes,  res) ; 
185202            } 
186-             Expr :: Call ( name,  parameters)  => { 
187-                 f ( name,  attributes,  res) ; 
188-                 // make sure that if someone does a(b).c, 'b' is bound and considered used. 
203+             Expr :: Call ( func_name,  parameters)  => { 
204+                 f ( func_name,  attributes,  res) ; 
189205                for  parameter in  parameters { 
206+                     if  let  ExprP :: Identifier ( func_name)  = & func_name. node  { 
207+                         if  let  ArgumentP :: Named ( arg_name,  _)  = & parameter. node  { 
208+                             res. push ( Bind :: IndirectReference ( IndirectReference  { 
209+                                 argument_name :  arg_name. clone ( ) , 
210+                                 function :  func_name. clone ( ) , 
211+                             } ) ) 
212+                         } 
213+                     } 
214+ 
215+                     // make sure that if someone does a(b).c, 'b' is bound and considered used. 
190216                    expr ( parameter. expr ( ) ,  res) ; 
191217                } 
192218            } 
@@ -221,6 +247,24 @@ fn expr(x: &AstExpr, res: &mut Vec<Bind>) {
221247            expr ( & x. 0 ,  res) ; 
222248            expr ( & x. 1 ,  res) 
223249        } ) , 
250+         Expr :: Call ( func,  args)  => { 
251+             expr ( func,  res) ; 
252+             for  x in  args { 
253+                 if  let  ExprP :: Identifier ( function_ident)  = & func. node  { 
254+                     match  & * * x { 
255+                         Argument :: Named ( name,  value)  => { 
256+                             res. push ( Bind :: IndirectReference ( IndirectReference  { 
257+                                 argument_name :  name. clone ( ) , 
258+                                 function :  function_ident. clone ( ) , 
259+                             } ) ) ; 
260+                             expr ( value,  res) ; 
261+                         } 
262+                         _ => expr ( x. expr ( ) ,  res) , 
263+                     } 
264+                 } 
265+                 expr ( x. expr ( ) ,  res) 
266+             } 
267+         } 
224268
225269        // Uninteresting - just recurse 
226270        _ => x. visit_expr ( |x| expr ( x,  res) ) , 
0 commit comments