@@ -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