luaur_analysis/methods/
frontend_get_source_node.rs1use crate::functions::get_timestamp::get_timestamp;
2use crate::functions::trace_requires::trace_requires;
3use crate::records::file_resolver::FileResolver;
4use crate::records::frontend::Frontend;
5use crate::records::source_module::SourceModule;
6use crate::records::source_node::SourceNode;
7use crate::records::type_check_limits::TypeCheckLimits;
8use crate::type_aliases::module_name_file_resolver::ModuleName;
9use alloc::sync::Arc;
10use luaur_common::macros::luau_timetrace_argument::LUAU_TIMETRACE_ARGUMENT;
11use luaur_common::macros::luau_timetrace_scope::LUAU_TIMETRACE_SCOPE;
12use luaur_config::records::config::Config;
13
14impl Frontend {
15 pub fn get_source_node(
16 &mut self,
17 name: &ModuleName,
18 limits: &TypeCheckLimits,
19 ) -> (*mut SourceNode, *mut SourceModule) {
20 let already_present = match self.source_nodes.get(name) {
21 Some(node) if !node.has_dirty_source_module() => {
22 let node_ptr = Arc::as_ptr(node) as *mut SourceNode;
23 if let Some(module) = self.source_modules.get(name) {
24 return (node_ptr, Arc::as_ptr(module) as *mut SourceModule);
25 } else {
26 return (node_ptr, core::ptr::null_mut());
28 }
29 }
30 Some(_) => true,
31 None => false,
32 };
33
34 LUAU_TIMETRACE_SCOPE!("Frontend::getSourceNode", "Frontend");
35 LUAU_TIMETRACE_ARGUMENT!("name", name.as_str());
36
37 let timestamp = get_timestamp();
38
39 let source = unsafe { FileResolver::read_source(self.file_resolver, name) };
40 let environment_name =
41 unsafe { FileResolver::get_environment_for_module(self.file_resolver, name) };
42
43 self.stats.time_read += get_timestamp() - timestamp;
44
45 let source = match source {
46 Some(source) => source,
47 None => {
48 self.source_modules.remove(name);
49 return (core::ptr::null_mut(), core::ptr::null_mut());
50 }
51 };
52
53 let mut opts = {
54 let config: &Config = unsafe {
55 let get_config = (*self.config_resolver)
56 .get_config
57 .expect("ConfigResolver::getConfig is not set");
58 &*get_config(self.config_resolver, name, limits)
59 };
60 config.parse_options.clone()
61 };
62 opts.capture_comments = true;
63 let mut result =
64 self.parse_module_name_string_view_parse_options(name, &source.source, &opts);
65 result.r#type = source.r#type;
66
67 let require = trace_requires(self.file_resolver, result.root, name.clone(), limits);
68 self.require_trace.insert(name.clone(), require.clone());
69
70 let source_node_arc = self
73 .source_nodes
74 .entry(name.clone())
75 .or_insert_with(|| Arc::new(default_source_node()));
76 let source_node_ptr = Arc::as_ptr(source_node_arc) as *mut SourceNode;
77
78 let source_module_arc = self
79 .source_modules
80 .entry(name.clone())
81 .or_insert_with(|| Arc::new(SourceModule::source_module()));
82 let source_module_ptr = Arc::as_ptr(source_module_arc) as *mut SourceModule;
83
84 unsafe {
85 *source_module_ptr = result;
87 (*source_module_ptr).environment_name = environment_name;
88
89 (*source_node_ptr).name = (*source_module_ptr).name.clone();
90 (*source_node_ptr).human_readable_name =
91 (*source_module_ptr).human_readable_name.clone();
92
93 let prior_locations = (*source_node_ptr).require_locations.clone();
98 let self_name = (*source_node_ptr).name.clone();
99 for (module_name, _) in prior_locations.iter() {
100 if let Some(dep) = self.source_nodes.get(module_name) {
101 let dep_ptr = Arc::as_ptr(dep) as *mut SourceNode;
102 let retained: alloc::vec::Vec<ModuleName> = (*dep_ptr)
103 .dependents
104 .iter()
105 .filter(|n| **n != self_name)
106 .cloned()
107 .collect();
108 (*dep_ptr).dependents.clear();
109 for n in retained {
110 (*dep_ptr).dependents.insert(n);
111 }
112 }
113 }
114
115 (*source_node_ptr).require_set.clear();
116 (*source_node_ptr).require_locations.clear();
117 (*source_node_ptr).dirty_source_module = false;
118
119 if !already_present {
122 (*source_node_ptr).dirty_module = true;
123 (*source_node_ptr).dirty_module_for_autocomplete = true;
124 }
125
126 for (module_name, _) in require.require_list.iter() {
127 (*source_node_ptr).require_set.insert(module_name.clone());
128 }
129
130 (*source_node_ptr).require_locations = require.require_list.clone();
131 }
132
133 (source_node_ptr, source_module_ptr)
134 }
135}
136
137fn default_source_node() -> SourceNode {
138 use luaur_common::records::dense_hash_set::DenseHashSet;
139 SourceNode {
140 name: ModuleName::default(),
141 human_readable_name: alloc::string::String::new(),
142 require_set: DenseHashSet::new(ModuleName::default()),
143 require_locations: alloc::vec::Vec::new(),
144 dependents: DenseHashSet::new(ModuleName::default()),
145 dirty_source_module: true,
146 dirty_module: true,
147 dirty_module_for_autocomplete: true,
148 invalid_module_dependency: true,
149 invalid_module_dependency_for_autocomplete: true,
150 autocomplete_limits_mult: 1.0,
151 }
152}