luaur_analysis/functions/
autocomplete_expression_autocomplete_core.rs1use crate::enums::autocomplete_context::AutocompleteContext;
2use crate::enums::autocomplete_entry_kind::AutocompleteEntryKind;
3use crate::enums::prop_index_type::PropIndexType;
4use crate::enums::type_correct_kind::TypeCorrectKind;
5use crate::functions::autocomplete_if_else_expression::autocomplete_if_else_expression;
6use crate::functions::autocomplete_props_autocomplete_core_alt_b::autocomplete_props as autocomplete_props_seed;
7use crate::functions::autocomplete_string_singleton::autocomplete_string_singleton;
8use crate::functions::check_type_correct_kind::check_type_correct_kind;
9use crate::functions::find_expected_type_at::find_expected_type_at;
10use crate::functions::function_is_expected_at::function_is_expected_at;
11use crate::functions::get_paren_recommendation::get_paren_recommendation;
12use crate::functions::is_being_defined::is_being_defined;
13use crate::functions::is_binding_legal_at_current_position::is_binding_legal_at_current_position;
14use crate::functions::to_string_symbol::to_string_symbol;
15use crate::records::autocomplete_entry::AutocompleteEntry;
16use crate::records::builtin_types::BuiltinTypes;
17use crate::records::internal_error_reporter::InternalErrorReporter;
18use crate::records::module::Module;
19use crate::records::type_arena::TypeArena;
20use crate::type_aliases::autocomplete_entry_map::AutocompleteEntryMap;
21use crate::type_aliases::scope_ptr_type::ScopePtr;
22use luaur_ast::records::ast_expr::AstExpr;
23use luaur_ast::records::ast_expr_function::AstExprFunction;
24use luaur_ast::records::ast_expr_global::AstExprGlobal;
25use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
26use luaur_ast::records::ast_expr_local::AstExprLocal;
27use luaur_ast::records::ast_node::AstNode;
28use luaur_ast::records::position::Position;
29use luaur_ast::rtti::{ast_node_as, ast_node_is};
30use luaur_common::FFlag;
31
32pub fn autocomplete_expression(
35 module: &Module,
36 builtin_types: &BuiltinTypes,
37 type_arena: *mut TypeArena,
38 ancestry: &alloc::vec::Vec<*mut AstNode>,
39 scope_at_position: &ScopePtr,
40 position: Position,
41 result: &mut AutocompleteEntryMap,
42) -> AutocompleteContext {
43 luaur_common::macros::luau_assert::LUAU_ASSERT!(!ancestry.is_empty());
44
45 let node: *mut AstNode = ancestry[ancestry.len() - 1];
46
47 if FFlag::DebugLuauMagicVariableNames.get() {
48 let ice = InternalErrorReporter {
49 on_internal_error: None,
50 module_name: alloc::string::String::new(),
51 };
52 let local = unsafe { ast_node_as::<AstExprLocal>(node) };
53 if !local.is_null()
54 && unsafe {
55 (*(*local).local)
56 .name
57 .operator_eq_c_char(c"_luau_autocomplete_ice".as_ptr())
58 }
59 {
60 ice.ice_string_location("_luau_autocomplete_ice encountered", unsafe {
61 &(*local).base.base.location
62 });
63 }
64 let global = unsafe { ast_node_as::<AstExprGlobal>(node) };
65 if !global.is_null()
66 && unsafe {
67 (*global)
68 .name
69 .operator_eq_c_char(c"_luau_autocomplete_ice".as_ptr())
70 }
71 {
72 ice.ice_string_location("_luau_autocomplete_ice encountered", unsafe {
73 &(*global).base.base.location
74 });
75 }
76 }
77
78 if unsafe { ast_node_is::<AstExprIndexName>(&*node) } {
79 let expr = unsafe { (*node).as_expr_const() as *const AstExpr };
80 if let Some(it) = module.ast_types.find(&expr) {
81 autocomplete_props_seed(
82 module,
83 type_arena,
84 builtin_types,
85 *it,
86 PropIndexType::Point,
87 ancestry,
88 result,
89 );
90 }
91 } else if autocomplete_if_else_expression(
92 node as *const AstNode,
93 &mut ancestry.clone(),
94 position,
95 result,
96 ) {
97 return AutocompleteContext::Keyword;
98 } else if unsafe { ast_node_is::<AstExprFunction>(&*node) } {
99 return AutocompleteContext::Unknown;
100 } else {
101 let mut scope: Option<ScopePtr> = Some(scope_at_position.clone());
103
104 while let Some(scope_ref) = scope {
105 for (name, binding) in &scope_ref.bindings {
106 if !is_binding_legal_at_current_position(name, binding, position) {
107 continue;
108 }
109
110 if is_being_defined(ancestry, name) {
111 continue;
112 }
113
114 let n = unsafe { to_string_symbol(name) };
115 if !result.contains_key(&n) {
116 let type_correct = check_type_correct_kind(
117 module,
118 type_arena,
119 builtin_types,
120 node,
121 position,
122 binding.type_id,
123 );
124
125 result.insert(
126 n.clone(),
127 AutocompleteEntry {
128 kind: AutocompleteEntryKind::Binding,
129 r#type: Some(binding.type_id),
130 deprecated: binding.deprecated,
131 wrong_index_type: false,
132 type_correct,
133 containing_extern_type: None,
134 prop: None,
135 documentation_symbol: binding.documentation_symbol.clone(),
136 tags: Default::default(),
137 parens: get_paren_recommendation(
138 binding.type_id,
139 ancestry,
140 type_correct,
141 ),
142 insert_text: None,
143 indexed_with_self: false,
144 },
145 );
146 }
147 }
148
149 scope = scope_ref.parent.clone();
150 }
151
152 let correct_for_nil = check_type_correct_kind(
153 module,
154 type_arena,
155 builtin_types,
156 node,
157 position,
158 builtin_types.nilType,
159 );
160 let correct_for_true = check_type_correct_kind(
161 module,
162 type_arena,
163 builtin_types,
164 node,
165 position,
166 builtin_types.trueType,
167 );
168 let correct_for_false = check_type_correct_kind(
169 module,
170 type_arena,
171 builtin_types,
172 node,
173 position,
174 builtin_types.falseType,
175 );
176 let correct_for_function =
177 if function_is_expected_at(module, node, position).unwrap_or(false) {
178 TypeCorrectKind::Correct
179 } else {
180 TypeCorrectKind::None
181 };
182
183 result.insert(
184 alloc::string::String::from("if"),
185 AutocompleteEntry {
186 kind: AutocompleteEntryKind::Keyword,
187 r#type: None,
188 deprecated: false,
189 wrong_index_type: false,
190 ..Default::default()
191 },
192 );
193 result.insert(
194 alloc::string::String::from("true"),
195 AutocompleteEntry {
196 kind: AutocompleteEntryKind::Keyword,
197 r#type: Some(builtin_types.booleanType),
198 deprecated: false,
199 wrong_index_type: false,
200 type_correct: correct_for_true,
201 ..Default::default()
202 },
203 );
204 result.insert(
205 alloc::string::String::from("false"),
206 AutocompleteEntry {
207 kind: AutocompleteEntryKind::Keyword,
208 r#type: Some(builtin_types.booleanType),
209 deprecated: false,
210 wrong_index_type: false,
211 type_correct: correct_for_false,
212 ..Default::default()
213 },
214 );
215 result.insert(
216 alloc::string::String::from("nil"),
217 AutocompleteEntry {
218 kind: AutocompleteEntryKind::Keyword,
219 r#type: Some(builtin_types.nilType),
220 deprecated: false,
221 wrong_index_type: false,
222 type_correct: correct_for_nil,
223 ..Default::default()
224 },
225 );
226 result.insert(
227 alloc::string::String::from("not"),
228 AutocompleteEntry {
229 kind: AutocompleteEntryKind::Keyword,
230 ..Default::default()
231 },
232 );
233 result.insert(
234 alloc::string::String::from("function"),
235 AutocompleteEntry {
236 kind: AutocompleteEntryKind::Keyword,
237 r#type: None,
238 deprecated: false,
239 wrong_index_type: false,
240 type_correct: correct_for_function,
241 ..Default::default()
242 },
243 );
244
245 if let Some(ty) = find_expected_type_at(module, node, position) {
246 autocomplete_string_singleton(ty, true, node, position, result);
247 }
248 }
249
250 AutocompleteContext::Expression
251}