Skip to main content

luaur_analysis/functions/
autocomplete_string_singleton.rs

1use crate::enums::autocomplete_entry_kind::AutocompleteEntryKind;
2use crate::enums::type_correct_kind::TypeCorrectKind;
3use crate::functions::follow_type::follow_type_id;
4use crate::functions::get_singleton_type::get_singleton_type;
5use crate::functions::get_type_alt_j::get_type_id;
6use crate::records::autocomplete_entry::AutocompleteEntry;
7use crate::records::intersection_type::IntersectionType;
8use crate::records::singleton_type::SingletonType;
9use crate::records::string_singleton::StringSingleton;
10use crate::records::union_type::UnionType;
11use crate::type_aliases::autocomplete_entry_map::AutocompleteEntryMap;
12use crate::type_aliases::type_id::TypeId;
13use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
14use luaur_ast::records::ast_expr_interp_string::AstExprInterpString;
15use luaur_ast::records::ast_node::AstNode;
16use luaur_ast::records::position::Position;
17use luaur_ast::rtti::{ast_node_as, ast_node_is};
18use luaur_common::functions::escape::escape;
19use luaur_common::FFlag;
20
21pub fn autocomplete_string_singleton(
22    ty: TypeId,
23    add_quotes: bool,
24    node: *mut AstNode,
25    position: Position,
26    result: &mut AutocompleteEntryMap,
27) {
28    unsafe {
29        let node_ref = &*node;
30        if position == node_ref.location.begin || position == node_ref.location.end {
31            let str_node = ast_node_as::<AstExprConstantString>(node);
32            if !str_node.is_null() {
33                let str_val = &*str_node;
34                if str_val.is_quoted() {
35                    return;
36                }
37            }
38
39            if ast_node_is::<AstExprInterpString>(node_ref) {
40                return;
41            }
42        }
43
44        let format_key = |key: &str| {
45            if add_quotes {
46                format!("\"{}\"", escape(key, false))
47            } else {
48                escape(key, false)
49            }
50        };
51
52        let ty = follow_type_id(ty);
53
54        let ss = get_type_id::<SingletonType>(ty);
55        if !ss.is_null() {
56            let sstv_inner = get_singleton_type::<StringSingleton>(ss);
57            if !sstv_inner.is_null() {
58                let key = format_key(&(*sstv_inner).value);
59                result.entry(key).or_insert_with(|| AutocompleteEntry {
60                    kind: AutocompleteEntryKind::String,
61                    r#type: Some(ty),
62                    deprecated: false,
63                    wrong_index_type: false,
64                    type_correct: TypeCorrectKind::Correct,
65                    containing_extern_type: None,
66                    prop: None,
67                    documentation_symbol: None,
68                    tags: Default::default(),
69                    parens: Default::default(),
70                    insert_text: None,
71                    indexed_with_self: false,
72                });
73            }
74            return;
75        }
76
77        let uty = get_type_id::<UnionType>(ty);
78        if !uty.is_null() {
79            let utv = &*uty;
80            for &el in &utv.options {
81                let ss_el = get_type_id::<SingletonType>(el);
82                if !ss_el.is_null() {
83                    let sstv_el_inner = get_singleton_type::<StringSingleton>(ss_el);
84                    if !sstv_el_inner.is_null() {
85                        let key = format_key(&(*sstv_el_inner).value);
86                        result.entry(key).or_insert_with(|| AutocompleteEntry {
87                            kind: AutocompleteEntryKind::String,
88                            r#type: Some(ty),
89                            deprecated: false,
90                            wrong_index_type: false,
91                            type_correct: TypeCorrectKind::Correct,
92                            containing_extern_type: None,
93                            prop: None,
94                            documentation_symbol: None,
95                            tags: Default::default(),
96                            parens: Default::default(),
97                            insert_text: None,
98                            indexed_with_self: false,
99                        });
100                    }
101                }
102            }
103            return;
104        }
105
106        let ity = get_type_id::<IntersectionType>(ty);
107        if FFlag::LuauAutocompleteStringSingletonIntersection.get() && !ity.is_null() {
108            let itv = &*ity;
109            for &el in &itv.parts {
110                autocomplete_string_singleton(el, add_quotes, node, position, result);
111            }
112        }
113    }
114}