11"""
22 compute_binding_occurrences(
33 ctx3::JL.VariableAnalysisContext, st3::Tree3, is_generated::Bool;
4- ismacro::Union{Nothing,Base.RefValue{ Bool}} = nothing
4+ include_global_bindings:: Bool = false
55 ) where Tree3<:JS.SyntaxTree
66 -> binding_occurrences::Dict{JL.BindingInfo,Set{BindingOccurrence{Tree3}}}
77
@@ -19,7 +19,6 @@ information:
1919# Arguments
2020- `ctx3`: Variable analysis context from JuliaLowering containing binding information
2121- `st3`: Lowered syntax tree (after scope resolution) to analyze
22- - `ismacro`: Optional mutable reference to track if any function binding is a macro
2322
2423# Returns
2524`binding_occurrences` is a dictionary mapping each non-internal local/argument binding to
@@ -34,7 +33,6 @@ a set of `BindingOccurrence` objects that record where and how the binding appea
3433"""
3534function compute_binding_occurrences (
3635 ctx3:: JL.VariableAnalysisContext , st3:: Tree3 , is_generated:: Bool ;
37- ismacro:: Union{Nothing,Base.RefValue{Bool}} = nothing ,
3836 include_global_bindings:: Bool = false
3937 ) where Tree3<: JS.SyntaxTree
4038 occurrences = Dict {JL.BindingInfo,Set{BindingOccurrence{Tree3}}} ()
@@ -65,7 +63,7 @@ function compute_binding_occurrences(
6563
6664 isempty (occurrences) && return occurrences
6765
68- compute_binding_occurrences! (occurrences, ctx3, st3; ismacro, include_global_bindings)
66+ compute_binding_occurrences! (occurrences, ctx3, st3; include_global_bindings)
6967
7068 # In `@generated` functions, arguments are typically used only inside returned
7169 # quoted expressions (`:(...)`) which appear as `inert` nodes after lowering.
@@ -164,30 +162,31 @@ self-recursive calls, which have distinct byte ranges.
164162"""
165163const SkipRecording = Dict{JL. BindingInfo,UnitRange{Int}}
166164
167- function record_occurrence ! (occurrences:: Dict{JL.BindingInfo,Set{BindingOccurrence{Tree3}}} ,
165+ function may_record_occurrence ! (occurrences:: Dict{JL.BindingInfo,Set{BindingOccurrence{Tree3}}} ,
168166 kind:: Symbol , st:: Tree3 , ctx3:: JL.VariableAnalysisContext ;
169167 skip_recording:: Union{Nothing,SkipRecording} = nothing
170168 ) where Tree3<: JS.SyntaxTree
171169 if JS. kind (st) === JS. K " BindingId"
172170 binfo = JL. get_binding (ctx3, st)
173- record_occurrence! (occurrences, kind, st, binfo; skip_recording)
171+ _may_record_occurrence! (occurrences, kind, st, binfo; skip_recording)
172+ return true
174173 end
175- return occurrences
174+ return false
176175end
177176
178- function record_occurrence ! (occurrences:: Dict{JL.BindingInfo,Set{BindingOccurrence{Tree3}}} ,
177+ function _may_record_occurrence ! (occurrences:: Dict{JL.BindingInfo,Set{BindingOccurrence{Tree3}}} ,
179178 kind:: Symbol , st:: Tree3 , binfo:: JL.BindingInfo ;
180179 skip_recording:: Union{Nothing,SkipRecording} = nothing
181180 ) where Tree3<: JS.SyntaxTree
182- haskey (occurrences, binfo) || return occurrences
181+ haskey (occurrences, binfo) || return
183182 if ! isnothing (skip_recording)
184183 skip_range = get (skip_recording, binfo, nothing )
185184 if skip_range != = nothing && JS. byte_range (st) == skip_range
186- return occurrences
185+ return
187186 end
188187 end
189188 push! (occurrences[binfo], BindingOccurrence (st, kind))
190- return occurrences
189+ occurrences
191190end
192191
193192is_selffunc (b:: JL.BindingInfo ) = b. name == " #self#"
@@ -197,46 +196,25 @@ function compute_binding_occurrences!(
197196 occurrences:: Dict{JL.BindingInfo,Set{BindingOccurrence{Tree3}}} ,
198197 ctx3:: JL.VariableAnalysisContext , st3:: Tree3 ;
199198 include_global_bindings:: Bool = false ,
200- ismacro:: Union{Nothing,Base.RefValue{Bool}} = nothing ,
201199 skip_recording_uses:: Union{Nothing,SkipRecording} = nothing
202200 ) where Tree3<: JS.SyntaxTree
203201 stack = JS. SyntaxList (st3)
204202 while ! isempty (stack)
205203 st = pop! (stack)
206204 k = JS. kind (st)
207205 nc = JS. numchildren (st)
208- if k === JS. K " local" || (include_global_bindings && k === JS. K " global" )
209- if nc ≥ 1
210- record_occurrence! (occurrences, :decl , st[1 ], ctx3)
211- continue # avoid to recurse to skip recording use
212- end
213- end
214-
215206 if k === JS. K " BindingId"
216- record_occurrence ! (occurrences, :use , st, ctx3; skip_recording= skip_recording_uses)
207+ may_record_occurrence ! (occurrences, :use , st, ctx3; skip_recording= skip_recording_uses)
217208 end
218209
219210 start_idx = 1
220- if k === JS. K " function_decl"
221- if nc ≥ 1
222- func = st[1 ]
223- if JS. kind (func) === JS. K " BindingId"
224- binfo = JL. get_binding (ctx3, func)
225- record_occurrence! (occurrences, :decl , func, binfo)
226- if ! isnothing (ismacro)
227- ismacro[] |= startswith (binfo. name, " @" )
228- end
229- start_idx = 2
230- end
211+ if k in JS. KSet " local function_decl" || (include_global_bindings && k === JS. K " global" )
212+ if nc ≥ 1 && may_record_occurrence! (occurrences, :decl , st[1 ], ctx3)
213+ start_idx = 2 # skip recording use
231214 end
232215 elseif k === JS. K " method_defs" || k === JS. K " constdecl"
233- if nc ≥ 1
234- local global_binding = st[1 ]
235- if JS. kind (global_binding) === JS. K " BindingId"
236- binfo = JL. get_binding (ctx3, global_binding)
237- record_occurrence! (occurrences, :def , global_binding, binfo)
238- start_idx = 2
239- end
216+ if nc ≥ 1 && may_record_occurrence! (occurrences, :def , st[1 ], ctx3)
217+ start_idx = 2
240218 end
241219 elseif k === JS. K " block" && nc ≥ 1 && JS. kind (st[1 ]) === JS. K " function_decl"
242220 # This block wraps a function definition. Each function's own binding
@@ -266,11 +244,11 @@ function compute_binding_occurrences!(
266244 if ! isempty (newly_added)
267245 if isnothing (skip_recording_uses)
268246 compute_binding_occurrences! (occurrences, ctx3, st;
269- ismacro, skip_recording_uses = SkipRecording (newly_added))
247+ skip_recording_uses = SkipRecording (newly_added))
270248 else
271249 for br in newly_added; push! (skip_recording_uses, br); end
272250 compute_binding_occurrences! (occurrences, ctx3, st;
273- ismacro, skip_recording_uses)
251+ skip_recording_uses)
274252 for (b, _) in newly_added; delete! (skip_recording_uses, b); end
275253 end
276254 continue
@@ -281,21 +259,21 @@ function compute_binding_occurrences!(
281259 if nc ≥ 2
282260 arglist = st[1 ]
283261 for i = 1 : JS. numchildren (arglist)
284- record_occurrence ! (occurrences, :def , arglist[i], ctx3)
262+ may_record_occurrence ! (occurrences, :def , arglist[i], ctx3)
285263 end
286264 start_idx = 2
287265 if nc ≥ 3
288266 sparamlist = st[2 ]
289267 for i = 1 : JS. numchildren (sparamlist)
290- record_occurrence ! (occurrences, :def , sparamlist[i], ctx3)
268+ may_record_occurrence ! (occurrences, :def , sparamlist[i], ctx3)
291269 end
292270 start_idx = 3
293271 end
294272 end
295273 elseif k === JS. K " ="
296274 start_idx = 2 # the left hand side, i.e. "definition", does not account for usage
297275 if nc ≥ 1
298- record_occurrence ! (occurrences, :def , st[1 ], ctx3)
276+ may_record_occurrence ! (occurrences, :def , st[1 ], ctx3)
299277 if nc ≥ 2
300278 rhs = st[2 ]
301279 # In struct definitions, `local struct_name` is somehow introduced,
@@ -350,7 +328,7 @@ function compute_binding_occurrences!(
350328 end
351329 end
352330
353- return occurrences, ismacro
331+ return occurrences
354332end
355333
356334function is_matching_global_binding (
0 commit comments