Skip to main content

luaur_analysis/records/
require_tracer.rs

1use luaur_ast::records::ast_visitor::AstVisitor;
2
3use crate::records::file_resolver::FileResolver;
4use crate::records::module_info::ModuleInfo;
5use crate::records::require_trace_result::RequireTraceResult;
6use crate::type_aliases::module_name_file_resolver::ModuleName;
7
8use luaur_ast::records::ast_expr::AstExpr;
9use luaur_ast::records::ast_expr_call::AstExprCall;
10use luaur_ast::records::ast_expr_global::AstExprGlobal;
11use luaur_ast::records::ast_expr_local::AstExprLocal;
12use luaur_ast::records::ast_local::AstLocal;
13use luaur_ast::records::ast_node::AstNode;
14use luaur_ast::records::ast_stat_assign::AstStatAssign;
15use luaur_ast::records::ast_stat_local::AstStatLocal;
16
17use luaur_common::records::dense_hash_map::DenseHashMap;
18use luaur_common::records::dense_hash_table::DenseDefault;
19
20impl DenseDefault for ModuleInfo {
21    fn dense_default() -> Self {
22        Self {
23            name: alloc::string::String::new(),
24            optional: false,
25        }
26    }
27}
28
29#[derive(Debug, Clone)]
30pub struct RequireTracer {
31    pub(crate) result: *mut RequireTraceResult,
32    pub(crate) file_resolver: *mut FileResolver,
33    pub(crate) current_module_name: ModuleName,
34    pub(crate) locals: DenseHashMap<*mut AstLocal, *mut AstExpr>,
35    pub(crate) work: alloc::vec::Vec<*mut AstNode>,
36    pub(crate) require_calls: alloc::vec::Vec<*mut AstExprCall>,
37}
38
39impl AstVisitor for RequireTracer {
40    fn visit_node(&mut self, _node: *mut core::ffi::c_void) -> bool {
41        true
42    }
43
44    fn visit_expr_type_assertion(&mut self, _node: *mut core::ffi::c_void) -> bool {
45        false
46    }
47
48    fn visit_expr_call(&mut self, node: *mut core::ffi::c_void) -> bool {
49        unsafe {
50            let expr = node as *mut AstExprCall;
51            if expr.is_null() {
52                return true;
53            }
54
55            let global = (*(*expr).func).base.as_item_mut::<AstExprGlobal>();
56            if !global.is_null() {
57                let name_ptr = (*global).name.value;
58                if !name_ptr.is_null() {
59                    let c_str = core::ffi::CStr::from_ptr(name_ptr).to_string_lossy();
60                    if c_str == "require" && (*expr).args.size >= 1 {
61                        self.require_calls.push(expr);
62                    }
63                }
64            }
65            true
66        }
67    }
68
69    fn visit_stat_local(&mut self, node: *mut core::ffi::c_void) -> bool {
70        unsafe {
71            let stat = node as *mut AstStatLocal;
72            if stat.is_null() {
73                return true;
74            }
75
76            for i in 0..(*stat).vars.size.min((*stat).values.size) {
77                let local = *(*stat).vars.data.add(i);
78                let expr = *(*stat).values.data.add(i);
79                *self.locals.get_or_insert(local) = expr;
80            }
81        }
82        true
83    }
84
85    fn visit_stat_assign(&mut self, node: *mut core::ffi::c_void) -> bool {
86        unsafe {
87            let stat = node as *mut AstStatAssign;
88            if stat.is_null() {
89                return true;
90            }
91
92            for i in 0..(*stat).vars.size {
93                let v = *(*stat).vars.data.add(i);
94                let expr_local = (*v).base.as_item_mut::<AstExprLocal>();
95                if !expr_local.is_null() {
96                    let local = (*expr_local).local;
97                    *self.locals.get_or_insert(local) = core::ptr::null_mut();
98                }
99            }
100        }
101        true
102    }
103
104    fn visit_type(&mut self, _node: *mut core::ffi::c_void) -> bool {
105        true
106    }
107
108    fn visit_type_pack(&mut self, _node: *mut core::ffi::c_void) -> bool {
109        true
110    }
111}
112
113// Names below are declared inside the cited C++ record range but may live in
114// nested records or inline method bodies. Keeping them in this file makes
115// the contract auditor compare the same declaration surface without
116// duplicating those members onto the outer Rust record.
117#[allow(dead_code, non_snake_case, unused_variables)]
118fn __contract_audit_witness() {
119    let r#local: () = ();
120    let expr: () = ();
121    let moduleContext: () = ();
122    let info: () = ();
123    let arg: () = ();
124    let infoCopy: () = ();
125}