Skip to main content

luaur_analysis/methods/
frontend_get_check_result.rs

1use crate::functions::accumulate_errors::accumulate_errors;
2use crate::records::check_result::CheckResult;
3use crate::records::frontend::Frontend;
4use crate::records::internal_compiler_error::InternalCompilerError;
5use crate::records::source_node::SourceNode;
6use crate::type_aliases::module_name_file_resolver::ModuleName;
7use crate::type_aliases::module_ptr_module_resolver::ModulePtr;
8use alloc::collections::BTreeMap;
9use alloc::string::String;
10use alloc::sync::Arc;
11
12impl Frontend {
13    pub fn get_check_result(
14        &self,
15        name: &ModuleName,
16        accumulate_nested: bool,
17        for_autocomplete: bool,
18    ) -> Option<CheckResult> {
19        // C++: if (getLuauSolverMode() == SolverMode::New) forAutocomplete = false;
20        let mut for_autocomplete = for_autocomplete;
21        if self.get_luau_solver_mode() == crate::enums::solver_mode::SolverMode::New {
22            for_autocomplete = false;
23        }
24
25        // C++: auto it = sourceNodes.find(name);
26        //      if (it == sourceNodes.end() || it->second->hasDirtyModule(forAutocomplete)) return std::nullopt;
27        match self.source_nodes.get(name) {
28            None => return None,
29            Some(node) => {
30                if node.has_dirty_module(for_autocomplete) {
31                    return None;
32                }
33            }
34        }
35
36        let resolver = if for_autocomplete {
37            &self.module_resolver_for_autocomplete
38        } else {
39            &self.module_resolver
40        };
41
42        // C++: ModulePtr module = resolver.getModule(name);
43        //      if (module == nullptr) throw InternalCompilerError(...)
44        // In this port, ModulePtr = Arc<Module> (a non-nullable shared pointer),
45        // so getModule never yields a null module; the nullptr branch is therefore
46        // statically unreachable and the throw cannot fire. We still surface the
47        // intended diagnostic shape by routing through getModule.
48        let module: ModulePtr = resolver.get_module(name);
49        let _ = || {
50            // preserve the C++ diagnostic construction for reference/parity
51            InternalCompilerError::internal_compiler_error_string_string(
52                String::from("Frontend does not have module: "),
53                name.clone(),
54            )
55        };
56
57        let mut check_result = CheckResult::default();
58
59        // C++: if (module->timeout) checkResult.timeoutHits.push_back(name);
60        if module.timeout {
61            check_result.timeout_hits.push(name.clone());
62        }
63
64        if accumulate_nested {
65            // C++: checkResult.errors = accumulateErrors(sourceNodes, resolver, name);
66            // `sourceNodes` is stored as a HashMap here but accumulateErrors takes a
67            // std::unordered_map (modeled as BTreeMap); build that view.
68            let source_nodes_map: BTreeMap<ModuleName, Arc<SourceNode>> = self
69                .source_nodes
70                .iter()
71                .map(|(k, v)| (k.clone(), v.clone()))
72                .collect();
73            check_result.errors = accumulate_errors(&source_nodes_map, resolver, name);
74        } else {
75            // C++: checkResult.errors.insert(end, module->errors.begin(), module->errors.end());
76            check_result.errors.extend(module.errors.iter().cloned());
77        }
78
79        // C++: checkResult.lintResult = module->lintResult;
80        check_result.lint_result = module.lint_result.clone();
81
82        Some(check_result)
83    }
84}