@@ -20,6 +20,8 @@ use std::collections::HashMap;
20
20
use starlark:: codemap:: Pos ;
21
21
use starlark:: codemap:: Span ;
22
22
use starlark:: syntax:: AstModule ;
23
+ use starlark_syntax:: syntax:: ast:: Argument ;
24
+ use starlark_syntax:: syntax:: ast:: ArgumentP ;
23
25
use starlark_syntax:: syntax:: ast:: AssignIdentP ;
24
26
use starlark_syntax:: syntax:: ast:: AssignP ;
25
27
use starlark_syntax:: syntax:: ast:: AstAssignIdent ;
@@ -33,6 +35,7 @@ use starlark_syntax::syntax::ast::AstTypeExpr;
33
35
use starlark_syntax:: syntax:: ast:: Clause ;
34
36
use starlark_syntax:: syntax:: ast:: DefP ;
35
37
use starlark_syntax:: syntax:: ast:: Expr ;
38
+ use starlark_syntax:: syntax:: ast:: ExprP ;
36
39
use starlark_syntax:: syntax:: ast:: ForClause ;
37
40
use starlark_syntax:: syntax:: ast:: ForP ;
38
41
use starlark_syntax:: syntax:: ast:: IdentP ;
@@ -43,21 +46,35 @@ use starlark_syntax::syntax::module::AstModuleFields;
43
46
#[ derive( Debug , Clone , Eq , PartialEq ) ]
44
47
pub ( crate ) enum Assigner {
45
48
/// 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 ,
52
54
}
53
55
54
56
#[ derive( Debug ) ]
55
57
pub ( 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 ,
61
78
}
62
79
63
80
/// A 'get' bind that was part of a dotted member access pattern.
@@ -123,7 +140,7 @@ impl Scope {
123
140
Bind :: Scope ( scope) => scope. free . iter ( ) . for_each ( |( k, v) | {
124
141
free. entry ( k. clone ( ) ) . or_insert ( * v) ;
125
142
} ) ,
126
- Bind :: Flow => { }
143
+ Bind :: IndirectReference ( _ ) | Bind :: Flow => { }
127
144
}
128
145
}
129
146
for x in bound. keys ( ) {
@@ -183,10 +200,19 @@ fn dot_access<'a>(lhs: &'a AstExpr, attribute: &'a AstString, res: &mut Vec<Bind
183
200
attributes. push ( attribute) ;
184
201
f ( lhs, attributes, res) ;
185
202
}
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) ;
189
205
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.
190
216
expr ( parameter. expr ( ) , res) ;
191
217
}
192
218
}
@@ -221,6 +247,24 @@ fn expr(x: &AstExpr, res: &mut Vec<Bind>) {
221
247
expr ( & x. 0 , res) ;
222
248
expr ( & x. 1 , res)
223
249
} ) ,
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
+ }
224
268
225
269
// Uninteresting - just recurse
226
270
_ => x. visit_expr ( |x| expr ( x, res) ) ,
0 commit comments