luaur_analysis/functions/
autocomplete_string_singleton.rs1use 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}