Skip to main content

luaur_analysis/methods/
frontend_traverse_dependents.rs

1use crate::records::frontend::Frontend;
2use crate::records::source_node::SourceNode;
3use crate::type_aliases::module_name_file_resolver::ModuleName;
4use alloc::vec::Vec;
5use luaur_common::macros::luau_timetrace_scope::LUAU_TIMETRACE_SCOPE;
6
7impl Frontend {
8    pub fn traverse_dependents(
9        &mut self,
10        name: &ModuleName,
11        process_subtree: Box<dyn Fn(&mut SourceNode) -> bool>,
12    ) {
13        LUAU_TIMETRACE_SCOPE!("Frontend::traverseDependents", "Frontend");
14
15        if !self.source_nodes.contains_key(name) {
16            return;
17        }
18
19        let mut queue = Vec::new();
20        queue.push(name.clone());
21
22        while !queue.is_empty() {
23            let next = queue.pop().unwrap();
24
25            debug_assert!(self.source_nodes.contains_key(&next));
26            let source_node_arc = match self.source_nodes.get(&next) {
27                Some(v) => v,
28                None => continue,
29            };
30
31            // Clone to avoid borrowing `self.source_nodes` across callback and subsequent queue mutations.
32            let mut source_node_ref: *mut SourceNode =
33                source_node_arc.as_ref() as *const SourceNode as *mut SourceNode;
34
35            // SAFETY: `SourceNode` is owned by `Frontend.source_nodes` as an `Arc`. We do not free it here,
36            // and callback is expected to mutate the node. We avoid aliasing `&mut` borrows by using the raw pointer.
37            let keep_going = unsafe { process_subtree(&mut *source_node_ref) };
38
39            if !keep_going {
40                continue;
41            }
42
43            let dependents = unsafe { &(*source_node_ref).dependents };
44            for d in dependents.iter() {
45                queue.push(d.clone());
46            }
47        }
48    }
49}