1/**************************************************************************/
2/* gdscript_editor.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "gdscript.h"
32
33#include "gdscript_analyzer.h"
34#include "gdscript_compiler.h"
35#include "gdscript_parser.h"
36#include "gdscript_tokenizer.h"
37#include "gdscript_utility_functions.h"
38
39#ifdef TOOLS_ENABLED
40#include "editor/script_templates/templates.gen.h"
41#endif
42
43#include "core/config/engine.h"
44#include "core/core_constants.h"
45#include "core/io/file_access.h"
46
47#ifdef TOOLS_ENABLED
48#include "core/config/project_settings.h"
49#include "editor/editor_file_system.h"
50#include "editor/editor_settings.h"
51#endif
52
53void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
54 p_delimiters->push_back("#");
55}
56
57void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
58 p_delimiters->push_back("\" \"");
59 p_delimiters->push_back("' '");
60 p_delimiters->push_back("\"\"\" \"\"\"");
61 p_delimiters->push_back("''' '''");
62}
63
64bool GDScriptLanguage::is_using_templates() {
65 return true;
66}
67
68Ref<Script> GDScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const {
69 Ref<GDScript> scr;
70 scr.instantiate();
71 String processed_template = p_template;
72 bool type_hints = false;
73#ifdef TOOLS_ENABLED
74 type_hints = EDITOR_GET("text_editor/completion/add_type_hints");
75#endif
76 if (!type_hints) {
77 processed_template = processed_template.replace(": int", "")
78 .replace(": String", "")
79 .replace(": Array[String]", "")
80 .replace(": float", "")
81 .replace(": CharFXTransform", "")
82 .replace(":=", "=")
83 .replace(" -> String", "")
84 .replace(" -> int", "")
85 .replace(" -> bool", "")
86 .replace(" -> void", "");
87 }
88
89 processed_template = processed_template.replace("_BASE_", p_base_class_name)
90 .replace("_CLASS_", p_class_name.to_pascal_case())
91 .replace("_TS_", _get_indentation());
92 scr->set_source_code(processed_template);
93 return scr;
94}
95
96Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) {
97 Vector<ScriptLanguage::ScriptTemplate> templates;
98#ifdef TOOLS_ENABLED
99 for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
100 if (TEMPLATES[i].inherit == p_object) {
101 templates.append(TEMPLATES[i]);
102 }
103 }
104#endif
105 return templates;
106}
107
108static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, HashMap<int, String> &r_funcs) {
109 for (int i = 0; i < p_class->members.size(); i++) {
110 if (p_class->members[i].type == GDScriptParser::ClassNode::Member::FUNCTION) {
111 const GDScriptParser::FunctionNode *function = p_class->members[i].function;
112 r_funcs[function->start_line] = p_prefix.is_empty() ? String(function->identifier->name) : p_prefix + "." + String(function->identifier->name);
113 } else if (p_class->members[i].type == GDScriptParser::ClassNode::Member::CLASS) {
114 String new_prefix = p_class->members[i].m_class->identifier->name;
115 get_function_names_recursively(p_class->members[i].m_class, p_prefix.is_empty() ? new_prefix : p_prefix + "." + new_prefix, r_funcs);
116 }
117 }
118}
119
120bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const {
121 GDScriptParser parser;
122 GDScriptAnalyzer analyzer(&parser);
123
124 Error err = parser.parse(p_script, p_path, false);
125 if (err == OK) {
126 err = analyzer.analyze();
127 }
128#ifdef DEBUG_ENABLED
129 if (r_warnings) {
130 for (const GDScriptWarning &E : parser.get_warnings()) {
131 const GDScriptWarning &warn = E;
132 ScriptLanguage::Warning w;
133 w.start_line = warn.start_line;
134 w.end_line = warn.end_line;
135 w.leftmost_column = warn.leftmost_column;
136 w.rightmost_column = warn.rightmost_column;
137 w.code = (int)warn.code;
138 w.string_code = GDScriptWarning::get_name_from_code(warn.code);
139 w.message = warn.get_message();
140 r_warnings->push_back(w);
141 }
142 }
143#endif
144 if (err) {
145 if (r_errors) {
146 for (const GDScriptParser::ParserError &pe : parser.get_errors()) {
147 ScriptLanguage::ScriptError e;
148 e.path = p_path;
149 e.line = pe.line;
150 e.column = pe.column;
151 e.message = pe.message;
152 r_errors->push_back(e);
153 }
154
155 for (KeyValue<String, Ref<GDScriptParserRef>> E : analyzer.get_depended_parsers()) {
156 GDScriptParser *depended_parser = E.value->get_parser();
157 for (const GDScriptParser::ParserError &pe : depended_parser->get_errors()) {
158 ScriptLanguage::ScriptError e;
159 e.path = E.key;
160 e.line = pe.line;
161 e.column = pe.column;
162 e.message = pe.message;
163 r_errors->push_back(e);
164 }
165 }
166 }
167 return false;
168 } else {
169 const GDScriptParser::ClassNode *cl = parser.get_tree();
170 HashMap<int, String> funcs;
171
172 get_function_names_recursively(cl, "", funcs);
173
174 for (const KeyValue<int, String> &E : funcs) {
175 r_functions->push_back(E.value + ":" + itos(E.key));
176 }
177 }
178
179#ifdef DEBUG_ENABLED
180 if (r_safe_lines) {
181 const HashSet<int> &unsafe_lines = parser.get_unsafe_lines();
182 for (int i = 1; i <= parser.get_last_line_number(); i++) {
183 if (!unsafe_lines.has(i)) {
184 r_safe_lines->insert(i);
185 }
186 }
187 }
188#endif
189
190 return true;
191}
192
193bool GDScriptLanguage::has_named_classes() const {
194 return false;
195}
196
197bool GDScriptLanguage::supports_builtin_mode() const {
198 return true;
199}
200
201bool GDScriptLanguage::supports_documentation() const {
202 return true;
203}
204
205int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const {
206 GDScriptTokenizer tokenizer;
207 tokenizer.set_source_code(p_code);
208 int indent = 0;
209 GDScriptTokenizer::Token current = tokenizer.scan();
210 while (current.type != GDScriptTokenizer::Token::TK_EOF && current.type != GDScriptTokenizer::Token::ERROR) {
211 if (current.type == GDScriptTokenizer::Token::INDENT) {
212 indent++;
213 } else if (current.type == GDScriptTokenizer::Token::DEDENT) {
214 indent--;
215 }
216 if (indent == 0 && current.type == GDScriptTokenizer::Token::FUNC) {
217 current = tokenizer.scan();
218 if (current.is_identifier()) {
219 String identifier = current.get_identifier();
220 if (identifier == p_function) {
221 return current.start_line;
222 }
223 }
224 }
225 current = tokenizer.scan();
226 }
227 return -1;
228}
229
230Script *GDScriptLanguage::create_script() const {
231 return memnew(GDScript);
232}
233
234/* DEBUGGER FUNCTIONS */
235
236thread_local int GDScriptLanguage::_debug_parse_err_line = -1;
237thread_local String GDScriptLanguage::_debug_parse_err_file;
238thread_local String GDScriptLanguage::_debug_error;
239
240bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
241 // break because of parse error
242
243 if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
244 _debug_parse_err_line = p_line;
245 _debug_parse_err_file = p_file;
246 _debug_error = p_error;
247 EngineDebugger::get_script_debugger()->debug(this, false, true);
248 // Because this is thread local, clear the memory afterwards.
249 _debug_parse_err_file = String();
250 _debug_error = String();
251 return true;
252 } else {
253 return false;
254 }
255}
256
257bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) {
258 if (EngineDebugger::is_active()) {
259 _debug_parse_err_line = -1;
260 _debug_parse_err_file = "";
261 _debug_error = p_error;
262 bool is_error_breakpoint = p_error != "Breakpoint";
263 EngineDebugger::get_script_debugger()->debug(this, p_allow_continue, is_error_breakpoint);
264 // Because this is thread local, clear the memory afterwards.
265 _debug_parse_err_file = String();
266 _debug_error = String();
267 return true;
268 } else {
269 return false;
270 }
271}
272
273String GDScriptLanguage::debug_get_error() const {
274 return _debug_error;
275}
276
277int GDScriptLanguage::debug_get_stack_level_count() const {
278 if (_debug_parse_err_line >= 0) {
279 return 1;
280 }
281
282 return _call_stack.stack_pos;
283}
284
285int GDScriptLanguage::debug_get_stack_level_line(int p_level) const {
286 if (_debug_parse_err_line >= 0) {
287 return _debug_parse_err_line;
288 }
289
290 ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, -1);
291
292 int l = _call_stack.stack_pos - p_level - 1;
293
294 return *(_call_stack.levels[l].line);
295}
296
297String GDScriptLanguage::debug_get_stack_level_function(int p_level) const {
298 if (_debug_parse_err_line >= 0) {
299 return "";
300 }
301
302 ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, "");
303 int l = _call_stack.stack_pos - p_level - 1;
304 return _call_stack.levels[l].function->get_name();
305}
306
307String GDScriptLanguage::debug_get_stack_level_source(int p_level) const {
308 if (_debug_parse_err_line >= 0) {
309 return _debug_parse_err_file;
310 }
311
312 ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, "");
313 int l = _call_stack.stack_pos - p_level - 1;
314 return _call_stack.levels[l].function->get_source();
315}
316
317void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
318 if (_debug_parse_err_line >= 0) {
319 return;
320 }
321
322 ERR_FAIL_INDEX(p_level, _call_stack.stack_pos);
323 int l = _call_stack.stack_pos - p_level - 1;
324
325 GDScriptFunction *f = _call_stack.levels[l].function;
326
327 List<Pair<StringName, int>> locals;
328
329 f->debug_get_stack_member_state(*_call_stack.levels[l].line, &locals);
330 for (const Pair<StringName, int> &E : locals) {
331 p_locals->push_back(E.first);
332 p_values->push_back(_call_stack.levels[l].stack[E.second]);
333 }
334}
335
336void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
337 if (_debug_parse_err_line >= 0) {
338 return;
339 }
340
341 ERR_FAIL_INDEX(p_level, _call_stack.stack_pos);
342 int l = _call_stack.stack_pos - p_level - 1;
343
344 GDScriptInstance *instance = _call_stack.levels[l].instance;
345
346 if (!instance) {
347 return;
348 }
349
350 Ref<GDScript> scr = instance->get_script();
351 ERR_FAIL_COND(scr.is_null());
352
353 const HashMap<StringName, GDScript::MemberInfo> &mi = scr->debug_get_member_indices();
354
355 for (const KeyValue<StringName, GDScript::MemberInfo> &E : mi) {
356 p_members->push_back(E.key);
357 p_values->push_back(instance->debug_get_member_by_index(E.value.index));
358 }
359}
360
361ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
362 if (_debug_parse_err_line >= 0) {
363 return nullptr;
364 }
365
366 ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, nullptr);
367
368 int l = _call_stack.stack_pos - p_level - 1;
369 ScriptInstance *instance = _call_stack.levels[l].instance;
370
371 return instance;
372}
373
374void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
375 const HashMap<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
376 const Variant *gl_array = GDScriptLanguage::get_singleton()->get_global_array();
377
378 List<Pair<String, Variant>> cinfo;
379 get_public_constants(&cinfo);
380
381 for (const KeyValue<StringName, int> &E : name_idx) {
382 if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) {
383 continue;
384 }
385
386 bool is_script_constant = false;
387 for (List<Pair<String, Variant>>::Element *CE = cinfo.front(); CE; CE = CE->next()) {
388 if (CE->get().first == E.key) {
389 is_script_constant = true;
390 break;
391 }
392 }
393 if (is_script_constant) {
394 continue;
395 }
396
397 const Variant &var = gl_array[E.value];
398 if (Object *obj = var) {
399 if (Object::cast_to<GDScriptNativeClass>(obj)) {
400 continue;
401 }
402 }
403
404 bool skip = false;
405 for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
406 if (E.key == CoreConstants::get_global_constant_name(i)) {
407 skip = true;
408 break;
409 }
410 }
411 if (skip) {
412 continue;
413 }
414
415 p_globals->push_back(E.key);
416 p_values->push_back(var);
417 }
418}
419
420String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
421 return "";
422}
423
424void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
425 p_extensions->push_back("gd");
426}
427
428void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
429 List<StringName> functions;
430 GDScriptUtilityFunctions::get_function_list(&functions);
431
432 for (const StringName &E : functions) {
433 p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E));
434 }
435
436 // Not really "functions", but show in documentation.
437 {
438 MethodInfo mi;
439 mi.name = "preload";
440 mi.arguments.push_back(PropertyInfo(Variant::STRING, "path"));
441 mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "Resource");
442 p_functions->push_back(mi);
443 }
444 {
445 MethodInfo mi;
446 mi.name = "assert";
447 mi.return_val.type = Variant::NIL;
448 mi.arguments.push_back(PropertyInfo(Variant::BOOL, "condition"));
449 mi.arguments.push_back(PropertyInfo(Variant::STRING, "message"));
450 mi.default_arguments.push_back(String());
451 p_functions->push_back(mi);
452 }
453}
454
455void GDScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const {
456 Pair<String, Variant> pi;
457 pi.first = "PI";
458 pi.second = Math_PI;
459 p_constants->push_back(pi);
460
461 Pair<String, Variant> tau;
462 tau.first = "TAU";
463 tau.second = Math_TAU;
464 p_constants->push_back(tau);
465
466 Pair<String, Variant> infinity;
467 infinity.first = "INF";
468 infinity.second = INFINITY;
469 p_constants->push_back(infinity);
470
471 Pair<String, Variant> nan;
472 nan.first = "NAN";
473 nan.second = NAN;
474 p_constants->push_back(nan);
475}
476
477void GDScriptLanguage::get_public_annotations(List<MethodInfo> *p_annotations) const {
478 GDScriptParser parser;
479 List<MethodInfo> annotations;
480 parser.get_annotation_list(&annotations);
481
482 for (const MethodInfo &E : annotations) {
483 p_annotations->push_back(E);
484 }
485}
486
487String GDScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const {
488#ifdef TOOLS_ENABLED
489 bool th = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints");
490#else
491 bool th = false;
492#endif
493
494 String s = "func " + p_name + "(";
495 if (p_args.size()) {
496 for (int i = 0; i < p_args.size(); i++) {
497 if (i > 0) {
498 s += ", ";
499 }
500 s += p_args[i].get_slice(":", 0);
501 if (th) {
502 String type = p_args[i].get_slice(":", 1);
503 if (!type.is_empty() && type != "var") {
504 s += ": " + type;
505 }
506 }
507 }
508 }
509 s += String(")") + (th ? " -> void" : "") + ":\n" + _get_indentation() + "pass # Replace with function body.\n";
510
511 return s;
512}
513
514//////// COMPLETION //////////
515
516#ifdef TOOLS_ENABLED
517
518#define COMPLETION_RECURSION_LIMIT 200
519
520struct GDScriptCompletionIdentifier {
521 GDScriptParser::DataType type;
522 String enumeration;
523 Variant value;
524 const GDScriptParser::ExpressionNode *assigned_expression = nullptr;
525};
526
527// LOCATION METHODS
528// These methods are used to populate the `CodeCompletionOption::location` integer.
529// For these methods, the location is based on the depth in the inheritance chain that the property
530// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D
531// will have a "better" (lower) location "score" than a property that is found on CanvasItem.
532
533static int _get_property_location(StringName p_class, StringName p_property) {
534 if (!ClassDB::has_property(p_class, p_property)) {
535 return ScriptLanguage::LOCATION_OTHER;
536 }
537
538 int depth = 0;
539 StringName class_test = p_class;
540 while (class_test && !ClassDB::has_property(class_test, p_property, true)) {
541 class_test = ClassDB::get_parent_class(class_test);
542 depth++;
543 }
544
545 return depth | ScriptLanguage::LOCATION_PARENT_MASK;
546}
547
548static int _get_constant_location(StringName p_class, StringName p_constant) {
549 if (!ClassDB::has_integer_constant(p_class, p_constant)) {
550 return ScriptLanguage::LOCATION_OTHER;
551 }
552
553 int depth = 0;
554 StringName class_test = p_class;
555 while (class_test && !ClassDB::has_integer_constant(class_test, p_constant, true)) {
556 class_test = ClassDB::get_parent_class(class_test);
557 depth++;
558 }
559
560 return depth | ScriptLanguage::LOCATION_PARENT_MASK;
561}
562
563static int _get_signal_location(StringName p_class, StringName p_signal) {
564 if (!ClassDB::has_signal(p_class, p_signal)) {
565 return ScriptLanguage::LOCATION_OTHER;
566 }
567
568 int depth = 0;
569 StringName class_test = p_class;
570 while (class_test && !ClassDB::has_signal(class_test, p_signal, true)) {
571 class_test = ClassDB::get_parent_class(class_test);
572 depth++;
573 }
574
575 return depth | ScriptLanguage::LOCATION_PARENT_MASK;
576}
577
578static int _get_method_location(StringName p_class, StringName p_method) {
579 if (!ClassDB::has_method(p_class, p_method)) {
580 return ScriptLanguage::LOCATION_OTHER;
581 }
582
583 int depth = 0;
584 StringName class_test = p_class;
585 while (class_test && !ClassDB::has_method(class_test, p_method, true)) {
586 class_test = ClassDB::get_parent_class(class_test);
587 depth++;
588 }
589
590 return depth | ScriptLanguage::LOCATION_PARENT_MASK;
591}
592
593static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) {
594 if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) {
595 return ScriptLanguage::LOCATION_OTHER;
596 }
597
598 int depth = 0;
599 StringName class_test = p_class;
600 while (class_test && !ClassDB::get_integer_constant_enum(class_test, p_enum_constant, true)) {
601 class_test = ClassDB::get_parent_class(class_test);
602 depth++;
603 }
604
605 return depth | ScriptLanguage::LOCATION_PARENT_MASK;
606}
607
608// END LOCATION METHODS
609
610static String _trim_parent_class(const String &p_class, const String &p_base_class) {
611 if (p_base_class.is_empty()) {
612 return p_class;
613 }
614 Vector<String> names = p_class.split(".", false, 1);
615 if (names.size() == 2) {
616 String first = names[0];
617 String rest = names[1];
618 if (ClassDB::class_exists(p_base_class) && ClassDB::class_exists(first) && ClassDB::is_parent_class(p_base_class, first)) {
619 return rest;
620 }
621 }
622 return p_class;
623}
624
625static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg, const String &p_base_class = "") {
626 String class_name = p_info.class_name;
627 bool is_enum = p_info.type == Variant::INT && p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM;
628 // PROPERTY_USAGE_CLASS_IS_BITFIELD: BitField[T] isn't supported (yet?), use plain int.
629
630 if ((p_info.type == Variant::OBJECT || is_enum) && !class_name.is_empty()) {
631 if (is_enum && CoreConstants::is_global_enum(p_info.class_name)) {
632 return class_name;
633 }
634 return _trim_parent_class(class_name, p_base_class);
635 } else if (p_info.type == Variant::ARRAY && p_info.hint == PROPERTY_HINT_ARRAY_TYPE && !p_info.hint_string.is_empty()) {
636 return "Array[" + _trim_parent_class(p_info.hint_string, p_base_class) + "]";
637 } else if (p_info.type == Variant::NIL) {
638 if (p_is_arg || (p_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) {
639 return "Variant";
640 } else {
641 return "void";
642 }
643 }
644
645 return Variant::get_type_name(p_info.type);
646}
647
648static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool p_is_annotation = false) {
649 String arghint;
650 if (!p_is_annotation) {
651 arghint += _get_visual_datatype(p_info.return_val, false) + " ";
652 }
653 arghint += p_info.name + "(";
654
655 int def_args = p_info.arguments.size() - p_info.default_arguments.size();
656 int i = 0;
657 for (const PropertyInfo &E : p_info.arguments) {
658 if (i > 0) {
659 arghint += ", ";
660 }
661
662 if (i == p_arg_idx) {
663 arghint += String::chr(0xFFFF);
664 }
665 arghint += E.name + ": " + _get_visual_datatype(E, true);
666
667 if (i - def_args >= 0) {
668 arghint += String(" = ") + p_info.default_arguments[i - def_args].get_construct_string();
669 }
670
671 if (i == p_arg_idx) {
672 arghint += String::chr(0xFFFF);
673 }
674
675 i++;
676 }
677
678 if (p_info.flags & METHOD_FLAG_VARARG) {
679 if (p_info.arguments.size() > 0) {
680 arghint += ", ";
681 }
682 if (p_arg_idx >= p_info.arguments.size()) {
683 arghint += String::chr(0xFFFF);
684 }
685 arghint += "...";
686 if (p_arg_idx >= p_info.arguments.size()) {
687 arghint += String::chr(0xFFFF);
688 }
689 }
690
691 arghint += ")";
692
693 return arghint;
694}
695
696static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx) {
697 String arghint;
698
699 if (p_function->get_datatype().builtin_type == Variant::NIL) {
700 arghint = "void " + p_function->identifier->name.operator String() + "(";
701 } else {
702 arghint = p_function->get_datatype().to_string() + " " + p_function->identifier->name.operator String() + "(";
703 }
704
705 for (int i = 0; i < p_function->parameters.size(); i++) {
706 if (i > 0) {
707 arghint += ", ";
708 }
709
710 if (i == p_arg_idx) {
711 arghint += String::chr(0xFFFF);
712 }
713 const GDScriptParser::ParameterNode *par = p_function->parameters[i];
714 if (!par->get_datatype().is_hard_type()) {
715 arghint += par->identifier->name.operator String() + ": Variant";
716 } else {
717 arghint += par->identifier->name.operator String() + ": " + par->get_datatype().to_string();
718 }
719
720 if (par->initializer) {
721 String def_val = "<unknown>";
722 switch (par->initializer->type) {
723 case GDScriptParser::Node::LITERAL: {
724 const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->initializer);
725 def_val = literal->value.get_construct_string();
726 } break;
727 case GDScriptParser::Node::IDENTIFIER: {
728 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->initializer);
729 def_val = id->name.operator String();
730 } break;
731 case GDScriptParser::Node::CALL: {
732 const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(par->initializer);
733 if (call->is_constant && call->reduced) {
734 def_val = call->function_name.operator String() + call->reduced_value.operator String();
735 }
736 } break;
737 case GDScriptParser::Node::ARRAY: {
738 const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->initializer);
739 if (arr->is_constant && arr->reduced) {
740 def_val = arr->reduced_value.operator String();
741 }
742 } break;
743 case GDScriptParser::Node::DICTIONARY: {
744 const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->initializer);
745 if (dict->is_constant && dict->reduced) {
746 def_val = dict->reduced_value.operator String();
747 }
748 } break;
749 case GDScriptParser::Node::SUBSCRIPT: {
750 const GDScriptParser::SubscriptNode *sub = static_cast<const GDScriptParser::SubscriptNode *>(par->initializer);
751 if (sub->is_constant) {
752 if (sub->datatype.kind == GDScriptParser::DataType::ENUM) {
753 def_val = sub->get_datatype().to_string();
754 } else if (sub->reduced) {
755 const Variant::Type vt = sub->reduced_value.get_type();
756 if (vt == Variant::Type::NIL || vt == Variant::Type::FLOAT || vt == Variant::Type::INT || vt == Variant::Type::STRING || vt == Variant::Type::STRING_NAME || vt == Variant::Type::BOOL || vt == Variant::Type::NODE_PATH) {
757 def_val = sub->reduced_value.operator String();
758 } else {
759 def_val = sub->get_datatype().to_string() + sub->reduced_value.operator String();
760 }
761 }
762 }
763 } break;
764 default:
765 break;
766 }
767 arghint += " = " + def_val;
768 }
769 if (i == p_arg_idx) {
770 arghint += String::chr(0xFFFF);
771 }
772 }
773
774 arghint += ")";
775
776 return arghint;
777}
778
779static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list) {
780 const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
781
782 for (int i = 0; i < p_dir->get_file_count(); i++) {
783 ScriptLanguage::CodeCompletionOption option(p_dir->get_file_path(i), ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH);
784 option.insert_text = option.display.quote(quote_style);
785 r_list.insert(option.display, option);
786 }
787
788 for (int i = 0; i < p_dir->get_subdir_count(); i++) {
789 _get_directory_contents(p_dir->get_subdir(i), r_list);
790 }
791}
792
793static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
794 if (p_annotation->name == SNAME("@export_range")) {
795 if (p_argument == 3 || p_argument == 4 || p_argument == 5) {
796 // Slider hint.
797 ScriptLanguage::CodeCompletionOption slider1("or_greater", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
798 slider1.insert_text = slider1.display.quote(p_quote_style);
799 r_result.insert(slider1.display, slider1);
800 ScriptLanguage::CodeCompletionOption slider2("or_less", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
801 slider2.insert_text = slider2.display.quote(p_quote_style);
802 r_result.insert(slider2.display, slider2);
803 ScriptLanguage::CodeCompletionOption slider3("hide_slider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
804 slider3.insert_text = slider3.display.quote(p_quote_style);
805 r_result.insert(slider3.display, slider3);
806 }
807 } else if (p_annotation->name == SNAME("@export_exp_easing")) {
808 if (p_argument == 0 || p_argument == 1) {
809 // Easing hint.
810 ScriptLanguage::CodeCompletionOption hint1("attenuation", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
811 hint1.insert_text = hint1.display.quote(p_quote_style);
812 r_result.insert(hint1.display, hint1);
813 ScriptLanguage::CodeCompletionOption hint2("inout", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
814 hint2.insert_text = hint2.display.quote(p_quote_style);
815 r_result.insert(hint2.display, hint2);
816 }
817 } else if (p_annotation->name == SNAME("@export_node_path")) {
818 ScriptLanguage::CodeCompletionOption node("Node", ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
819 node.insert_text = node.display.quote(p_quote_style);
820 r_result.insert(node.display, node);
821
822 List<StringName> native_classes;
823 ClassDB::get_inheriters_from_class("Node", &native_classes);
824 for (const StringName &E : native_classes) {
825 if (!ClassDB::is_class_exposed(E)) {
826 continue;
827 }
828 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
829 option.insert_text = option.display.quote(p_quote_style);
830 r_result.insert(option.display, option);
831 }
832
833 List<StringName> global_script_classes;
834 ScriptServer::get_global_class_list(&global_script_classes);
835 for (const StringName &E : global_script_classes) {
836 if (!ClassDB::is_parent_class(ScriptServer::get_global_class_native_base(E), "Node")) {
837 continue;
838 }
839 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
840 option.insert_text = option.display.quote(p_quote_style);
841 r_result.insert(option.display, option);
842 }
843 } else if (p_annotation->name == SNAME("@warning_ignore")) {
844 for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) {
845 ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
846 warning.insert_text = warning.display.quote(p_quote_style);
847 r_result.insert(warning.display, warning);
848 }
849 } else if (p_annotation->name == SNAME("@rpc")) {
850 if (p_argument == 0 || p_argument == 1 || p_argument == 2) {
851 static const char *options[7] = { "call_local", "call_remote", "any_peer", "authority", "reliable", "unreliable", "unreliable_ordered" };
852 for (int i = 0; i < 7; i++) {
853 ScriptLanguage::CodeCompletionOption option(options[i], ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
854 option.insert_text = option.display.quote(p_quote_style);
855 r_result.insert(option.display, option);
856 }
857 }
858 }
859}
860
861static void _find_built_in_variants(HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) {
862 for (int i = 0; i < Variant::VARIANT_MAX; i++) {
863 if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) {
864 ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
865 r_result.insert(option.display, option);
866 } else {
867 ScriptLanguage::CodeCompletionOption option(Variant::get_type_name(Variant::Type(i)), ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
868 r_result.insert(option.display, option);
869 }
870 }
871}
872
873static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
874 // Built-in Variant Types
875 _find_built_in_variants(r_result, true);
876
877 List<StringName> native_types;
878 ClassDB::get_class_list(&native_types);
879 for (const StringName &E : native_types) {
880 if (ClassDB::is_class_exposed(E) && !Engine::get_singleton()->has_singleton(E)) {
881 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
882 r_result.insert(option.display, option);
883 }
884 }
885
886 if (p_context.current_class) {
887 if (!p_inherit_only && p_context.current_class->base_type.is_set()) {
888 // Native enums from base class
889 List<StringName> enums;
890 ClassDB::get_enum_list(p_context.current_class->base_type.native_type, &enums);
891 for (const StringName &E : enums) {
892 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
893 r_result.insert(option.display, option);
894 }
895 }
896 // Check current class for potential types
897 const GDScriptParser::ClassNode *current = p_context.current_class;
898 while (current) {
899 for (int i = 0; i < current->members.size(); i++) {
900 const GDScriptParser::ClassNode::Member &member = current->members[i];
901 switch (member.type) {
902 case GDScriptParser::ClassNode::Member::CLASS: {
903 ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
904 r_result.insert(option.display, option);
905 } break;
906 case GDScriptParser::ClassNode::Member::ENUM: {
907 if (!p_inherit_only) {
908 ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, ScriptLanguage::LOCATION_LOCAL);
909 r_result.insert(option.display, option);
910 }
911 } break;
912 case GDScriptParser::ClassNode::Member::CONSTANT: {
913 if (member.constant->get_datatype().is_meta_type && p_context.current_class->outer != nullptr) {
914 ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
915 r_result.insert(option.display, option);
916 }
917 } break;
918 default:
919 break;
920 }
921 }
922 current = current->outer;
923 }
924 }
925
926 // Global scripts
927 List<StringName> global_classes;
928 ScriptServer::get_global_class_list(&global_classes);
929 for (const StringName &E : global_classes) {
930 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
931 r_result.insert(option.display, option);
932 }
933
934 // Autoload singletons
935 HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
936
937 for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
938 const ProjectSettings::AutoloadInfo &info = E.value;
939 if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") {
940 continue;
941 }
942 ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
943 r_result.insert(option.display, option);
944 }
945}
946
947static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth = 0) {
948 for (int i = 0; i < p_suite->locals.size(); i++) {
949 ScriptLanguage::CodeCompletionOption option;
950 int location = p_recursion_depth == 0 ? ScriptLanguage::LOCATION_LOCAL : (p_recursion_depth | ScriptLanguage::LOCATION_PARENT_MASK);
951 if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) {
952 option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
953 option.default_value = p_suite->locals[i].constant->initializer->reduced_value;
954 } else {
955 option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE, location);
956 }
957 r_result.insert(option.display, option);
958 }
959 if (p_suite->parent_block) {
960 _find_identifiers_in_suite(p_suite->parent_block, r_result, p_recursion_depth + 1);
961 }
962}
963
964static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth);
965
966static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
967 ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
968
969 if (!p_parent_only) {
970 bool outer = false;
971 const GDScriptParser::ClassNode *clss = p_class;
972 int classes_processed = 0;
973 while (clss) {
974 for (int i = 0; i < clss->members.size(); i++) {
975 const int location = p_recursion_depth == 0 ? classes_processed : (p_recursion_depth | ScriptLanguage::LOCATION_PARENT_MASK);
976 const GDScriptParser::ClassNode::Member &member = clss->members[i];
977 ScriptLanguage::CodeCompletionOption option;
978 switch (member.type) {
979 case GDScriptParser::ClassNode::Member::VARIABLE:
980 if (p_only_functions || outer || (p_static)) {
981 continue;
982 }
983 option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
984 break;
985 case GDScriptParser::ClassNode::Member::CONSTANT:
986 if (p_only_functions) {
987 continue;
988 }
989 if (r_result.has(member.constant->identifier->name)) {
990 continue;
991 }
992 option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
993 if (member.constant->initializer) {
994 option.default_value = member.constant->initializer->reduced_value;
995 }
996 break;
997 case GDScriptParser::ClassNode::Member::CLASS:
998 if (p_only_functions) {
999 continue;
1000 }
1001 option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, location);
1002 break;
1003 case GDScriptParser::ClassNode::Member::ENUM_VALUE:
1004 if (p_only_functions) {
1005 continue;
1006 }
1007 option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
1008 break;
1009 case GDScriptParser::ClassNode::Member::ENUM:
1010 if (p_only_functions) {
1011 continue;
1012 }
1013 option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
1014 break;
1015 case GDScriptParser::ClassNode::Member::FUNCTION:
1016 if (outer || (p_static && !member.function->is_static) || member.function->identifier->name.operator String().begins_with("@")) {
1017 continue;
1018 }
1019 option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
1020 if (member.function->parameters.size() > 0) {
1021 option.insert_text += "(";
1022 } else {
1023 option.insert_text += "()";
1024 }
1025 break;
1026 case GDScriptParser::ClassNode::Member::SIGNAL:
1027 if (p_only_functions || outer || p_static) {
1028 continue;
1029 }
1030 option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
1031 break;
1032 case GDScriptParser::ClassNode::Member::GROUP:
1033 break; // No-op, but silences warnings.
1034 case GDScriptParser::ClassNode::Member::UNDEFINED:
1035 break;
1036 }
1037 r_result.insert(option.display, option);
1038 }
1039 outer = true;
1040 clss = clss->outer;
1041 classes_processed++;
1042 }
1043 }
1044
1045 // Parents.
1046 GDScriptCompletionIdentifier base_type;
1047 base_type.type = p_class->base_type;
1048 base_type.type.is_meta_type = p_static;
1049
1050 _find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1);
1051}
1052
1053static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
1054 ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
1055
1056 GDScriptParser::DataType base_type = p_base.type;
1057
1058 if (base_type.is_meta_type && base_type.kind != GDScriptParser::DataType::BUILTIN && base_type.kind != GDScriptParser::DataType::ENUM) {
1059 ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL);
1060 option.insert_text += "(";
1061 r_result.insert(option.display, option);
1062 }
1063
1064 while (!base_type.has_no_type()) {
1065 switch (base_type.kind) {
1066 case GDScriptParser::DataType::CLASS: {
1067 _find_identifiers_in_class(base_type.class_type, p_only_functions, base_type.is_meta_type, false, r_result, p_recursion_depth);
1068 // This already finds all parent identifiers, so we are done.
1069 base_type = GDScriptParser::DataType();
1070 } break;
1071 case GDScriptParser::DataType::SCRIPT: {
1072 Ref<Script> scr = base_type.script_type;
1073 if (scr.is_valid()) {
1074 if (!p_only_functions) {
1075 if (!base_type.is_meta_type) {
1076 List<PropertyInfo> members;
1077 scr->get_script_property_list(&members);
1078 for (const PropertyInfo &E : members) {
1079 int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.name);
1080 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
1081 r_result.insert(option.display, option);
1082 }
1083
1084 List<MethodInfo> signals;
1085 scr->get_script_signal_list(&signals);
1086 for (const MethodInfo &E : signals) {
1087 int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name);
1088 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
1089 r_result.insert(option.display, option);
1090 }
1091 }
1092 HashMap<StringName, Variant> constants;
1093 scr->get_constants(&constants);
1094 for (const KeyValue<StringName, Variant> &E : constants) {
1095 int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key);
1096 ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
1097 r_result.insert(option.display, option);
1098 }
1099 }
1100
1101 List<MethodInfo> methods;
1102 scr->get_script_method_list(&methods);
1103 for (const MethodInfo &E : methods) {
1104 if (E.name.begins_with("@")) {
1105 continue;
1106 }
1107 int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
1108 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
1109 if (E.arguments.size()) {
1110 option.insert_text += "(";
1111 } else {
1112 option.insert_text += "()";
1113 }
1114 r_result.insert(option.display, option);
1115 }
1116
1117 Ref<Script> base_script = scr->get_base_script();
1118 if (base_script.is_valid()) {
1119 base_type.script_type = base_script;
1120 } else {
1121 base_type.kind = GDScriptParser::DataType::NATIVE;
1122 base_type.native_type = scr->get_instance_base_type();
1123 }
1124 } else {
1125 return;
1126 }
1127 } break;
1128 case GDScriptParser::DataType::NATIVE: {
1129 StringName type = base_type.native_type;
1130 if (!ClassDB::class_exists(type)) {
1131 return;
1132 }
1133
1134 if (!p_only_functions) {
1135 List<String> constants;
1136 ClassDB::get_integer_constant_list(type, &constants);
1137 for (const String &E : constants) {
1138 int location = p_recursion_depth + _get_constant_location(type, StringName(E));
1139 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
1140 r_result.insert(option.display, option);
1141 }
1142
1143 if (!base_type.is_meta_type || Engine::get_singleton()->has_singleton(type)) {
1144 List<PropertyInfo> pinfo;
1145 ClassDB::get_property_list(type, &pinfo);
1146 for (const PropertyInfo &E : pinfo) {
1147 if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) {
1148 continue;
1149 }
1150 if (E.name.contains("/")) {
1151 continue;
1152 }
1153 int location = p_recursion_depth + _get_property_location(type, E.name);
1154 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
1155 r_result.insert(option.display, option);
1156 }
1157
1158 List<MethodInfo> signals;
1159 ClassDB::get_signal_list(type, &signals);
1160 for (const MethodInfo &E : signals) {
1161 int location = p_recursion_depth + _get_signal_location(type, StringName(E.name));
1162 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
1163 r_result.insert(option.display, option);
1164 }
1165 }
1166 }
1167
1168 bool only_static = base_type.is_meta_type && !Engine::get_singleton()->has_singleton(type);
1169
1170 List<MethodInfo> methods;
1171 ClassDB::get_method_list(type, &methods, false, true);
1172 for (const MethodInfo &E : methods) {
1173 if (only_static && (E.flags & METHOD_FLAG_STATIC) == 0) {
1174 continue;
1175 }
1176 if (E.name.begins_with("_")) {
1177 continue;
1178 }
1179 int location = p_recursion_depth + _get_method_location(type, E.name);
1180 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
1181 if (E.arguments.size()) {
1182 option.insert_text += "(";
1183 } else {
1184 option.insert_text += "()";
1185 }
1186 r_result.insert(option.display, option);
1187 }
1188 return;
1189 } break;
1190 case GDScriptParser::DataType::ENUM:
1191 case GDScriptParser::DataType::BUILTIN: {
1192 Callable::CallError err;
1193 Variant tmp;
1194 Variant::construct(base_type.builtin_type, tmp, nullptr, 0, err);
1195 if (err.error != Callable::CallError::CALL_OK) {
1196 return;
1197 }
1198
1199 if (!p_only_functions) {
1200 List<PropertyInfo> members;
1201 if (p_base.value.get_type() != Variant::NIL) {
1202 p_base.value.get_property_list(&members);
1203 } else {
1204 tmp.get_property_list(&members);
1205 }
1206
1207 for (const PropertyInfo &E : members) {
1208 if (!String(E.name).contains("/")) {
1209 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
1210 if (GDScriptParser::theme_color_names.has(E.name)) {
1211 option.theme_color_name = GDScriptParser::theme_color_names[E.name];
1212 }
1213 r_result.insert(option.display, option);
1214 }
1215 }
1216 }
1217
1218 List<MethodInfo> methods;
1219 tmp.get_method_list(&methods);
1220 for (const MethodInfo &E : methods) {
1221 if (base_type.kind == GDScriptParser::DataType::ENUM && base_type.is_meta_type && !(E.flags & METHOD_FLAG_CONST)) {
1222 // Enum types are static and cannot change, therefore we skip non-const dictionary methods.
1223 continue;
1224 }
1225 ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
1226 if (E.arguments.size()) {
1227 option.insert_text += "(";
1228 } else {
1229 option.insert_text += "()";
1230 }
1231 r_result.insert(option.display, option);
1232 }
1233
1234 return;
1235 } break;
1236 default: {
1237 return;
1238 } break;
1239 }
1240 }
1241}
1242
1243static void _find_identifiers(const GDScriptParser::CompletionContext &p_context, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
1244 if (!p_only_functions && p_context.current_suite) {
1245 // This includes function parameters, since they are also locals.
1246 _find_identifiers_in_suite(p_context.current_suite, r_result);
1247 }
1248
1249 if (p_context.current_class) {
1250 _find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth);
1251 }
1252
1253 List<StringName> functions;
1254 GDScriptUtilityFunctions::get_function_list(&functions);
1255
1256 for (const StringName &E : functions) {
1257 MethodInfo function = GDScriptUtilityFunctions::get_function_info(E);
1258 ScriptLanguage::CodeCompletionOption option(String(E), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
1259 if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
1260 option.insert_text += "(";
1261 } else {
1262 option.insert_text += "()";
1263 }
1264 r_result.insert(option.display, option);
1265 }
1266
1267 if (p_only_functions) {
1268 return;
1269 }
1270
1271 _find_built_in_variants(r_result);
1272
1273 static const char *_keywords[] = {
1274 "true", "false", "PI", "TAU", "INF", "NAN", "null", "self", "super",
1275 "break", "breakpoint", "continue", "pass", "return",
1276 nullptr
1277 };
1278
1279 const char **kw = _keywords;
1280 while (*kw) {
1281 ScriptLanguage::CodeCompletionOption option(*kw, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
1282 r_result.insert(option.display, option);
1283 kw++;
1284 }
1285
1286 static const char *_keywords_with_space[] = {
1287 "and", "not", "or", "in", "as", "class", "class_name", "extends", "is", "func", "signal", "await",
1288 "const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
1289 nullptr
1290 };
1291
1292 const char **kws = _keywords_with_space;
1293 while (*kws) {
1294 ScriptLanguage::CodeCompletionOption option(*kws, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
1295 option.insert_text += " ";
1296 r_result.insert(option.display, option);
1297 kws++;
1298 }
1299
1300 static const char *_keywords_with_args[] = {
1301 "assert", "preload",
1302 nullptr
1303 };
1304
1305 const char **kwa = _keywords_with_args;
1306 while (*kwa) {
1307 ScriptLanguage::CodeCompletionOption option(*kwa, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
1308 option.insert_text += "(";
1309 r_result.insert(option.display, option);
1310 kwa++;
1311 }
1312
1313 List<StringName> utility_func_names;
1314 Variant::get_utility_function_list(&utility_func_names);
1315
1316 for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
1317 ScriptLanguage::CodeCompletionOption option(E->get(), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
1318 option.insert_text += "(";
1319 r_result.insert(option.display, option);
1320 }
1321
1322 for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
1323 if (!E.value.is_singleton) {
1324 continue;
1325 }
1326 ScriptLanguage::CodeCompletionOption option(E.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
1327 r_result.insert(option.display, option);
1328 }
1329
1330 // Native classes and global constants.
1331 for (const KeyValue<StringName, int> &E : GDScriptLanguage::get_singleton()->get_global_map()) {
1332 ScriptLanguage::CodeCompletionOption option;
1333 if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) {
1334 option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
1335 } else {
1336 option = ScriptLanguage::CodeCompletionOption(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
1337 }
1338 r_result.insert(option.display, option);
1339 }
1340
1341 // Global classes
1342 List<StringName> global_classes;
1343 ScriptServer::get_global_class_list(&global_classes);
1344 for (const StringName &E : global_classes) {
1345 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
1346 r_result.insert(option.display, option);
1347 }
1348}
1349
1350static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value) {
1351 GDScriptCompletionIdentifier ci;
1352 ci.value = p_value;
1353 ci.type.is_constant = true;
1354 ci.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
1355 ci.type.kind = GDScriptParser::DataType::BUILTIN;
1356 ci.type.builtin_type = p_value.get_type();
1357
1358 if (ci.type.builtin_type == Variant::OBJECT) {
1359 Object *obj = p_value.operator Object *();
1360 if (!obj) {
1361 return ci;
1362 }
1363 ci.type.native_type = obj->get_class_name();
1364 Ref<Script> scr = p_value;
1365 if (scr.is_valid()) {
1366 ci.type.is_meta_type = true;
1367 } else {
1368 ci.type.is_meta_type = false;
1369 scr = obj->get_script();
1370 }
1371 if (scr.is_valid()) {
1372 ci.type.script_type = scr;
1373 ci.type.kind = GDScriptParser::DataType::SCRIPT;
1374 ci.type.native_type = scr->get_instance_base_type();
1375 } else {
1376 ci.type.kind = GDScriptParser::DataType::NATIVE;
1377 }
1378 }
1379
1380 return ci;
1381}
1382
1383static GDScriptCompletionIdentifier _type_from_property(const PropertyInfo &p_property) {
1384 GDScriptCompletionIdentifier ci;
1385
1386 if (p_property.type == Variant::NIL) {
1387 // Variant
1388 return ci;
1389 }
1390
1391 if (p_property.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
1392 ci.enumeration = p_property.class_name;
1393 }
1394
1395 ci.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
1396 ci.type.builtin_type = p_property.type;
1397 if (p_property.type == Variant::OBJECT) {
1398 ci.type.kind = GDScriptParser::DataType::NATIVE;
1399 ci.type.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name;
1400 } else {
1401 ci.type.kind = GDScriptParser::DataType::BUILTIN;
1402 }
1403 return ci;
1404}
1405
1406#define MAX_COMPLETION_RECURSION 100
1407struct RecursionCheck {
1408 int *counter;
1409 _FORCE_INLINE_ bool check() {
1410 return (*counter) > MAX_COMPLETION_RECURSION;
1411 }
1412 RecursionCheck(int *p_counter) :
1413 counter(p_counter) {
1414 (*counter)++;
1415 }
1416 ~RecursionCheck() {
1417 (*counter)--;
1418 }
1419};
1420
1421static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::IdentifierNode *p_identifier, GDScriptCompletionIdentifier &r_type);
1422static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type);
1423static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type);
1424
1425static bool _is_expression_named_identifier(const GDScriptParser::ExpressionNode *p_expression, const StringName &p_name) {
1426 if (p_expression) {
1427 switch (p_expression->type) {
1428 case GDScriptParser::Node::IDENTIFIER: {
1429 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression);
1430 if (id->name == p_name) {
1431 return true;
1432 }
1433 } break;
1434 case GDScriptParser::Node::CAST: {
1435 const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
1436 return _is_expression_named_identifier(cn->operand, p_name);
1437 } break;
1438 default:
1439 break;
1440 }
1441 }
1442
1443 return false;
1444}
1445
1446static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) {
1447 bool found = false;
1448
1449 if (p_expression == nullptr) {
1450 return false;
1451 }
1452
1453 static int recursion_depth = 0;
1454 RecursionCheck recursion(&recursion_depth);
1455 if (unlikely(recursion.check())) {
1456 ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type.");
1457 }
1458
1459 if (p_expression->is_constant) {
1460 // Already has a value, so just use that.
1461 r_type = _type_from_variant(p_expression->reduced_value);
1462 switch (p_expression->get_datatype().kind) {
1463 case GDScriptParser::DataType::ENUM:
1464 case GDScriptParser::DataType::CLASS:
1465 r_type.type = p_expression->get_datatype();
1466 break;
1467 default:
1468 break;
1469 }
1470 found = true;
1471 } else {
1472 switch (p_expression->type) {
1473 case GDScriptParser::Node::LITERAL: {
1474 const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(p_expression);
1475 r_type = _type_from_variant(literal->value);
1476 found = true;
1477 } break;
1478 case GDScriptParser::Node::SELF: {
1479 if (p_context.current_class) {
1480 if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) {
1481 r_type.type = p_context.current_class->get_datatype();
1482 } else {
1483 r_type.type = p_context.current_class->base_type;
1484 }
1485 found = true;
1486 }
1487 } break;
1488 case GDScriptParser::Node::IDENTIFIER: {
1489 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression);
1490 found = _guess_identifier_type(p_context, id, r_type);
1491 } break;
1492 case GDScriptParser::Node::DICTIONARY: {
1493 // Try to recreate the dictionary.
1494 const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(p_expression);
1495 Dictionary d;
1496 bool full = true;
1497 for (int i = 0; i < dn->elements.size(); i++) {
1498 GDScriptCompletionIdentifier key;
1499 if (_guess_expression_type(p_context, dn->elements[i].key, key)) {
1500 if (!key.type.is_constant) {
1501 full = false;
1502 break;
1503 }
1504 GDScriptCompletionIdentifier value;
1505 if (_guess_expression_type(p_context, dn->elements[i].value, value)) {
1506 if (!value.type.is_constant) {
1507 full = false;
1508 break;
1509 }
1510 d[key.value] = value.value;
1511 } else {
1512 full = false;
1513 break;
1514 }
1515 } else {
1516 full = false;
1517 break;
1518 }
1519 }
1520 if (full) {
1521 r_type.value = d;
1522 r_type.type.is_constant = true;
1523 }
1524 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
1525 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
1526 r_type.type.builtin_type = Variant::DICTIONARY;
1527 found = true;
1528 } break;
1529 case GDScriptParser::Node::ARRAY: {
1530 // Try to recreate the array
1531 const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_expression);
1532 Array a;
1533 bool full = true;
1534 a.resize(an->elements.size());
1535 for (int i = 0; i < an->elements.size(); i++) {
1536 GDScriptCompletionIdentifier value;
1537 if (_guess_expression_type(p_context, an->elements[i], value)) {
1538 if (value.type.is_constant) {
1539 a[i] = value.value;
1540 } else {
1541 full = false;
1542 break;
1543 }
1544 } else {
1545 full = false;
1546 break;
1547 }
1548 }
1549 if (full) {
1550 // If not fully constant, setting this value is detrimental to the inference.
1551 r_type.value = a;
1552 }
1553 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
1554 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
1555 r_type.type.builtin_type = Variant::ARRAY;
1556 found = true;
1557 } break;
1558 case GDScriptParser::Node::CAST: {
1559 const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
1560 GDScriptCompletionIdentifier value;
1561 if (_guess_expression_type(p_context, cn->operand, r_type)) {
1562 r_type.type = cn->get_datatype();
1563 found = true;
1564 }
1565 } break;
1566 case GDScriptParser::Node::CALL: {
1567 const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
1568 if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
1569 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
1570 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
1571 r_type.type.builtin_type = GDScriptParser::get_builtin_type(call->function_name);
1572 found = true;
1573 break;
1574 } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
1575 MethodInfo mi = GDScriptUtilityFunctions::get_function_info(call->function_name);
1576 r_type = _type_from_property(mi.return_val);
1577 found = true;
1578 break;
1579 } else {
1580 GDScriptParser::CompletionContext c = p_context;
1581 c.current_line = call->start_line;
1582
1583 GDScriptParser::Node::Type callee_type = call->get_callee_type();
1584
1585 GDScriptCompletionIdentifier base;
1586 if (callee_type == GDScriptParser::Node::IDENTIFIER || call->is_super) {
1587 // Simple call, so base is 'self'.
1588 if (p_context.current_class) {
1589 if (call->is_super) {
1590 base.type = p_context.current_class->base_type;
1591 base.value = p_context.base;
1592 } else {
1593 base.type.kind = GDScriptParser::DataType::CLASS;
1594 base.type.type_source = GDScriptParser::DataType::INFERRED;
1595 base.type.is_constant = true;
1596 base.type.class_type = p_context.current_class;
1597 base.value = p_context.base;
1598 }
1599 } else {
1600 break;
1601 }
1602 } else if (callee_type == GDScriptParser::Node::SUBSCRIPT && static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->is_attribute) {
1603 if (!_guess_expression_type(c, static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->base, base)) {
1604 found = false;
1605 break;
1606 }
1607 } else {
1608 break;
1609 }
1610
1611 // Try call if constant methods with constant arguments
1612 if (base.type.is_constant && base.value.get_type() == Variant::OBJECT) {
1613 GDScriptParser::DataType native_type = base.type;
1614
1615 while (native_type.kind == GDScriptParser::DataType::CLASS) {
1616 native_type = native_type.class_type->base_type;
1617 }
1618
1619 while (native_type.kind == GDScriptParser::DataType::SCRIPT) {
1620 if (native_type.script_type.is_valid()) {
1621 Ref<Script> parent = native_type.script_type->get_base_script();
1622 if (parent.is_valid()) {
1623 native_type.script_type = parent;
1624 } else {
1625 native_type.kind = GDScriptParser::DataType::NATIVE;
1626 native_type.native_type = native_type.script_type->get_instance_base_type();
1627 if (!ClassDB::class_exists(native_type.native_type)) {
1628 native_type.kind = GDScriptParser::DataType::UNRESOLVED;
1629 }
1630 }
1631 }
1632 }
1633
1634 if (native_type.kind == GDScriptParser::DataType::NATIVE) {
1635 MethodBind *mb = ClassDB::get_method(native_type.native_type, call->function_name);
1636 if (mb && mb->is_const()) {
1637 bool all_is_const = true;
1638 Vector<Variant> args;
1639 GDScriptParser::CompletionContext c2 = p_context;
1640 c2.current_line = call->start_line;
1641 for (int i = 0; all_is_const && i < call->arguments.size(); i++) {
1642 GDScriptCompletionIdentifier arg;
1643
1644 if (!call->arguments[i]->is_constant) {
1645 all_is_const = false;
1646 }
1647 }
1648
1649 Object *baseptr = base.value;
1650
1651 if (all_is_const && call->function_name == SNAME("get_node") && ClassDB::is_parent_class(native_type.native_type, SNAME("Node")) && args.size()) {
1652 String arg1 = args[0];
1653 if (arg1.begins_with("/root/")) {
1654 String which = arg1.get_slice("/", 2);
1655 if (!which.is_empty()) {
1656 // Try singletons first
1657 if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(which)) {
1658 r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]);
1659 found = true;
1660 } else {
1661 for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
1662 String name = E.key;
1663 if (name == which) {
1664 String script = E.value.path;
1665
1666 if (!script.begins_with("res://")) {
1667 script = "res://" + script;
1668 }
1669
1670 if (!script.ends_with(".gd")) {
1671 // not a script, try find the script anyway,
1672 // may have some success
1673 script = script.get_basename() + ".gd";
1674 }
1675
1676 if (FileAccess::exists(script)) {
1677 Error err = OK;
1678 Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err);
1679 if (err == OK) {
1680 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
1681 r_type.type.script_path = script;
1682 r_type.type.class_type = parser->get_parser()->get_tree();
1683 r_type.type.is_constant = false;
1684 r_type.type.kind = GDScriptParser::DataType::CLASS;
1685 r_type.value = Variant();
1686 p_context.dependent_parsers.push_back(parser);
1687 found = true;
1688 }
1689 }
1690 break;
1691 }
1692 }
1693 }
1694 }
1695 }
1696 }
1697
1698 if (!found && all_is_const && baseptr) {
1699 Vector<const Variant *> argptr;
1700 for (int i = 0; i < args.size(); i++) {
1701 argptr.push_back(&args[i]);
1702 }
1703
1704 Callable::CallError ce;
1705 Variant ret = mb->call(baseptr, (const Variant **)argptr.ptr(), argptr.size(), ce);
1706
1707 if (ce.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
1708 if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != nullptr) {
1709 r_type = _type_from_variant(ret);
1710 found = true;
1711 }
1712 }
1713 }
1714 }
1715 }
1716 }
1717
1718 if (!found && base.value.get_type() != Variant::NIL) {
1719 found = _guess_method_return_type_from_base(c, base, call->function_name, r_type);
1720 }
1721 }
1722 } break;
1723 case GDScriptParser::Node::SUBSCRIPT: {
1724 const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(p_expression);
1725 if (subscript->is_attribute) {
1726 GDScriptParser::CompletionContext c = p_context;
1727 c.current_line = subscript->start_line;
1728
1729 GDScriptCompletionIdentifier base;
1730 if (!_guess_expression_type(c, subscript->base, base)) {
1731 found = false;
1732 break;
1733 }
1734
1735 if (base.value.get_type() == Variant::DICTIONARY && base.value.operator Dictionary().has(String(subscript->attribute->name))) {
1736 Variant value = base.value.operator Dictionary()[String(subscript->attribute->name)];
1737 r_type = _type_from_variant(value);
1738 found = true;
1739 break;
1740 }
1741
1742 const GDScriptParser::DictionaryNode *dn = nullptr;
1743 if (subscript->base->type == GDScriptParser::Node::DICTIONARY) {
1744 dn = static_cast<const GDScriptParser::DictionaryNode *>(subscript->base);
1745 } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::DICTIONARY) {
1746 dn = static_cast<const GDScriptParser::DictionaryNode *>(base.assigned_expression);
1747 }
1748
1749 if (dn) {
1750 for (int i = 0; i < dn->elements.size(); i++) {
1751 GDScriptCompletionIdentifier key;
1752 if (!_guess_expression_type(c, dn->elements[i].key, key)) {
1753 continue;
1754 }
1755 if (key.value == String(subscript->attribute->name)) {
1756 r_type.assigned_expression = dn->elements[i].value;
1757 found = _guess_expression_type(c, dn->elements[i].value, r_type);
1758 break;
1759 }
1760 }
1761 }
1762
1763 if (!found) {
1764 found = _guess_identifier_type_from_base(c, base, subscript->attribute->name, r_type);
1765 }
1766 } else {
1767 if (subscript->index == nullptr) {
1768 found = false;
1769 break;
1770 }
1771
1772 GDScriptParser::CompletionContext c = p_context;
1773 c.current_line = subscript->start_line;
1774
1775 GDScriptCompletionIdentifier base;
1776 if (!_guess_expression_type(c, subscript->base, base)) {
1777 found = false;
1778 break;
1779 }
1780
1781 GDScriptCompletionIdentifier index;
1782 if (!_guess_expression_type(c, subscript->index, index)) {
1783 found = false;
1784 break;
1785 }
1786
1787 if (base.value.in(index.value)) {
1788 Variant value = base.value.get(index.value);
1789 r_type = _type_from_variant(value);
1790 found = true;
1791 break;
1792 }
1793
1794 // Look if it is a dictionary node.
1795 const GDScriptParser::DictionaryNode *dn = nullptr;
1796 if (subscript->base->type == GDScriptParser::Node::DICTIONARY) {
1797 dn = static_cast<const GDScriptParser::DictionaryNode *>(subscript->base);
1798 } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::DICTIONARY) {
1799 dn = static_cast<const GDScriptParser::DictionaryNode *>(base.assigned_expression);
1800 }
1801
1802 if (dn) {
1803 for (int i = 0; i < dn->elements.size(); i++) {
1804 GDScriptCompletionIdentifier key;
1805 if (!_guess_expression_type(c, dn->elements[i].key, key)) {
1806 continue;
1807 }
1808 if (key.value == index.value) {
1809 r_type.assigned_expression = dn->elements[i].value;
1810 found = _guess_expression_type(p_context, dn->elements[i].value, r_type);
1811 break;
1812 }
1813 }
1814 }
1815
1816 // Look if it is an array node.
1817 if (!found && index.value.is_num()) {
1818 int idx = index.value;
1819 const GDScriptParser::ArrayNode *an = nullptr;
1820 if (subscript->base->type == GDScriptParser::Node::ARRAY) {
1821 an = static_cast<const GDScriptParser::ArrayNode *>(subscript->base);
1822 } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::ARRAY) {
1823 an = static_cast<const GDScriptParser::ArrayNode *>(base.assigned_expression);
1824 }
1825
1826 if (an && idx >= 0 && an->elements.size() > idx) {
1827 r_type.assigned_expression = an->elements[idx];
1828 found = _guess_expression_type(c, an->elements[idx], r_type);
1829 break;
1830 }
1831 }
1832
1833 // Look for valid indexing in other types
1834 if (!found && (index.value.get_type() == Variant::STRING || index.value.get_type() == Variant::NODE_PATH)) {
1835 StringName id = index.value;
1836 found = _guess_identifier_type_from_base(c, base, id, r_type);
1837 } else if (!found && index.type.kind == GDScriptParser::DataType::BUILTIN) {
1838 Callable::CallError err;
1839 Variant base_val;
1840 Variant::construct(base.type.builtin_type, base_val, nullptr, 0, err);
1841 bool valid = false;
1842 Variant res = base_val.get(index.value, &valid);
1843 if (valid) {
1844 r_type = _type_from_variant(res);
1845 r_type.value = Variant();
1846 r_type.type.is_constant = false;
1847 found = true;
1848 }
1849 }
1850 }
1851 } break;
1852 case GDScriptParser::Node::BINARY_OPERATOR: {
1853 const GDScriptParser::BinaryOpNode *op = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression);
1854
1855 if (op->variant_op == Variant::OP_MAX) {
1856 break;
1857 }
1858
1859 GDScriptParser::CompletionContext context = p_context;
1860 context.current_line = op->start_line;
1861
1862 GDScriptCompletionIdentifier p1;
1863 GDScriptCompletionIdentifier p2;
1864
1865 if (!_guess_expression_type(context, op->left_operand, p1)) {
1866 found = false;
1867 break;
1868 }
1869
1870 if (!_guess_expression_type(context, op->right_operand, p2)) {
1871 found = false;
1872 break;
1873 }
1874
1875 Callable::CallError ce;
1876 bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT;
1877 Variant d1;
1878 Variant::construct(p1.type.builtin_type, d1, nullptr, 0, ce);
1879 Variant d2;
1880 Variant::construct(p2.type.builtin_type, d2, nullptr, 0, ce);
1881
1882 Variant v1 = (v1_use_value) ? p1.value : d1;
1883 bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT;
1884 Variant v2 = (v2_use_value) ? p2.value : d2;
1885 // avoid potential invalid ops
1886 if ((op->variant_op == Variant::OP_DIVIDE || op->variant_op == Variant::OP_MODULE) && v2.get_type() == Variant::INT) {
1887 v2 = 1;
1888 v2_use_value = false;
1889 }
1890 if (op->variant_op == Variant::OP_DIVIDE && v2.get_type() == Variant::FLOAT) {
1891 v2 = 1.0;
1892 v2_use_value = false;
1893 }
1894
1895 Variant res;
1896 bool valid;
1897 Variant::evaluate(op->variant_op, v1, v2, res, valid);
1898 if (!valid) {
1899 found = false;
1900 break;
1901 }
1902 r_type = _type_from_variant(res);
1903 if (!v1_use_value || !v2_use_value) {
1904 r_type.value = Variant();
1905 r_type.type.is_constant = false;
1906 }
1907
1908 found = true;
1909 } break;
1910 default:
1911 break;
1912 }
1913 }
1914
1915 // It may have found a null, but that's never useful
1916 if (found && r_type.type.kind == GDScriptParser::DataType::BUILTIN && r_type.type.builtin_type == Variant::NIL) {
1917 found = false;
1918 }
1919
1920 // Check type hint last. For collections we want chance to get the actual value first
1921 // This way we can detect types from the content of dictionaries and arrays
1922 if (!found && p_expression->get_datatype().is_hard_type()) {
1923 r_type.type = p_expression->get_datatype();
1924 if (!r_type.assigned_expression) {
1925 r_type.assigned_expression = p_expression;
1926 }
1927 found = true;
1928 }
1929
1930 return found;
1931}
1932
1933static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::IdentifierNode *p_identifier, GDScriptCompletionIdentifier &r_type) {
1934 static int recursion_depth = 0;
1935 RecursionCheck recursion(&recursion_depth);
1936 if (unlikely(recursion.check())) {
1937 ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type.");
1938 }
1939
1940 // Look in blocks first.
1941 int last_assign_line = -1;
1942 const GDScriptParser::ExpressionNode *last_assigned_expression = nullptr;
1943 GDScriptParser::DataType id_type;
1944 GDScriptParser::SuiteNode *suite = p_context.current_suite;
1945 bool is_function_parameter = false;
1946
1947 bool can_be_local = true;
1948 switch (p_identifier->source) {
1949 case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
1950 case GDScriptParser::IdentifierNode::MEMBER_CONSTANT:
1951 case GDScriptParser::IdentifierNode::MEMBER_FUNCTION:
1952 case GDScriptParser::IdentifierNode::MEMBER_SIGNAL:
1953 case GDScriptParser::IdentifierNode::MEMBER_CLASS:
1954 case GDScriptParser::IdentifierNode::INHERITED_VARIABLE:
1955 case GDScriptParser::IdentifierNode::STATIC_VARIABLE:
1956 can_be_local = false;
1957 break;
1958 default:
1959 break;
1960 }
1961
1962 if (can_be_local && suite && suite->has_local(p_identifier->name)) {
1963 const GDScriptParser::SuiteNode::Local &local = suite->get_local(p_identifier->name);
1964
1965 id_type = local.get_datatype();
1966
1967 // Check initializer as the first assignment.
1968 switch (local.type) {
1969 case GDScriptParser::SuiteNode::Local::VARIABLE:
1970 if (local.variable->initializer) {
1971 last_assign_line = local.variable->initializer->end_line;
1972 last_assigned_expression = local.variable->initializer;
1973 }
1974 break;
1975 case GDScriptParser::SuiteNode::Local::CONSTANT:
1976 if (local.constant->initializer) {
1977 last_assign_line = local.constant->initializer->end_line;
1978 last_assigned_expression = local.constant->initializer;
1979 }
1980 break;
1981 case GDScriptParser::SuiteNode::Local::PARAMETER:
1982 if (local.parameter->initializer) {
1983 last_assign_line = local.parameter->initializer->end_line;
1984 last_assigned_expression = local.parameter->initializer;
1985 }
1986 is_function_parameter = true;
1987 break;
1988 default:
1989 break;
1990 }
1991 }
1992
1993 while (suite) {
1994 for (int i = 0; i < suite->statements.size(); i++) {
1995 if (suite->statements[i]->end_line >= p_context.current_line) {
1996 break;
1997 }
1998
1999 switch (suite->statements[i]->type) {
2000 case GDScriptParser::Node::ASSIGNMENT: {
2001 const GDScriptParser::AssignmentNode *assign = static_cast<const GDScriptParser::AssignmentNode *>(suite->statements[i]);
2002 if (assign->end_line > last_assign_line && assign->assignee && assign->assigned_value && assign->assignee->type == GDScriptParser::Node::IDENTIFIER) {
2003 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(assign->assignee);
2004 if (id->name == p_identifier->name && id->source == p_identifier->source) {
2005 last_assign_line = assign->assigned_value->end_line;
2006 last_assigned_expression = assign->assigned_value;
2007 }
2008 }
2009 } break;
2010 default:
2011 // TODO: Check sub blocks (control flow statements) as they might also reassign stuff.
2012 break;
2013 }
2014 }
2015
2016 if (suite->parent_if && suite->parent_if->condition && suite->parent_if->condition->type == GDScriptParser::Node::TYPE_TEST) {
2017 // Operator `is` used, check if identifier is in there! this helps resolve in blocks that are (if (identifier is value)): which are very common..
2018 // Super dirty hack, but very useful.
2019 // Credit: Zylann.
2020 // TODO: this could be hacked to detect ANDed conditions too...
2021 const GDScriptParser::TypeTestNode *type_test = static_cast<const GDScriptParser::TypeTestNode *>(suite->parent_if->condition);
2022 if (type_test->operand && type_test->test_type && type_test->operand->type == GDScriptParser::Node::IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(type_test->operand)->name == p_identifier->name && static_cast<const GDScriptParser::IdentifierNode *>(type_test->operand)->source == p_identifier->source) {
2023 // Bingo.
2024 GDScriptParser::CompletionContext c = p_context;
2025 c.current_line = type_test->operand->start_line;
2026 c.current_suite = suite;
2027 if (type_test->test_datatype.is_hard_type()) {
2028 id_type = type_test->test_datatype;
2029 if (last_assign_line < c.current_line) {
2030 // Override last assignment.
2031 last_assign_line = c.current_line;
2032 last_assigned_expression = nullptr;
2033 }
2034 }
2035 }
2036 }
2037
2038 suite = suite->parent_block;
2039 }
2040
2041 if (last_assigned_expression && last_assign_line < p_context.current_line) {
2042 GDScriptParser::CompletionContext c = p_context;
2043 c.current_line = last_assign_line;
2044 r_type.assigned_expression = last_assigned_expression;
2045 if (_guess_expression_type(c, last_assigned_expression, r_type)) {
2046 return true;
2047 }
2048 }
2049
2050 if (is_function_parameter && p_context.current_function && p_context.current_function->source_lambda == nullptr && p_context.current_class) {
2051 // Check if it's override of native function, then we can assume the type from the signature.
2052 GDScriptParser::DataType base_type = p_context.current_class->base_type;
2053 while (base_type.is_set()) {
2054 switch (base_type.kind) {
2055 case GDScriptParser::DataType::CLASS:
2056 if (base_type.class_type->has_function(p_context.current_function->identifier->name)) {
2057 GDScriptParser::FunctionNode *parent_function = base_type.class_type->get_member(p_context.current_function->identifier->name).function;
2058 if (parent_function->parameters_indices.has(p_identifier->name)) {
2059 const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[p_identifier->name]];
2060 if ((!id_type.is_set() || id_type.is_variant()) && parameter->get_datatype().is_hard_type()) {
2061 id_type = parameter->get_datatype();
2062 }
2063 if (parameter->initializer) {
2064 GDScriptParser::CompletionContext c = p_context;
2065 c.current_function = parent_function;
2066 c.current_class = base_type.class_type;
2067 c.base = nullptr;
2068 if (_guess_expression_type(c, parameter->initializer, r_type)) {
2069 return true;
2070 }
2071 }
2072 }
2073 }
2074 base_type = base_type.class_type->base_type;
2075 break;
2076 case GDScriptParser::DataType::NATIVE: {
2077 if (id_type.is_set() && !id_type.is_variant()) {
2078 base_type = GDScriptParser::DataType();
2079 break;
2080 }
2081 MethodInfo info;
2082 if (ClassDB::get_method_info(base_type.native_type, p_context.current_function->identifier->name, &info)) {
2083 for (const PropertyInfo &E : info.arguments) {
2084 if (E.name == p_identifier->name) {
2085 r_type = _type_from_property(E);
2086 return true;
2087 }
2088 }
2089 }
2090 base_type = GDScriptParser::DataType();
2091 } break;
2092 default:
2093 break;
2094 }
2095 }
2096 }
2097
2098 if (id_type.is_set() && !id_type.is_variant()) {
2099 r_type.type = id_type;
2100 return true;
2101 }
2102
2103 // Check current class (including inheritance).
2104 if (p_context.current_class) {
2105 GDScriptCompletionIdentifier base;
2106 base.value = p_context.base;
2107 base.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2108 base.type.kind = GDScriptParser::DataType::CLASS;
2109 base.type.class_type = p_context.current_class;
2110 base.type.is_meta_type = p_context.current_function && p_context.current_function->is_static;
2111
2112 if (_guess_identifier_type_from_base(p_context, base, p_identifier->name, r_type)) {
2113 return true;
2114 }
2115 }
2116
2117 // Check global scripts.
2118 if (ScriptServer::is_global_class(p_identifier->name)) {
2119 String script = ScriptServer::get_global_class_path(p_identifier->name);
2120 if (script.to_lower().ends_with(".gd")) {
2121 Error err = OK;
2122 Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err);
2123 if (err == OK) {
2124 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2125 r_type.type.script_path = script;
2126 r_type.type.class_type = parser->get_parser()->get_tree();
2127 r_type.type.is_meta_type = true;
2128 r_type.type.is_constant = false;
2129 r_type.type.kind = GDScriptParser::DataType::CLASS;
2130 r_type.value = Variant();
2131 p_context.dependent_parsers.push_back(parser);
2132 return true;
2133 }
2134 } else {
2135 Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_identifier->name));
2136 if (scr.is_valid()) {
2137 r_type = _type_from_variant(scr);
2138 r_type.type.is_meta_type = true;
2139 return true;
2140 }
2141 }
2142 return false;
2143 }
2144
2145 // Check global variables (including autoloads).
2146 if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(p_identifier->name)) {
2147 r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[p_identifier->name]);
2148 return true;
2149 }
2150
2151 // Check ClassDB.
2152 if (ClassDB::class_exists(p_identifier->name) && ClassDB::is_class_exposed(p_identifier->name)) {
2153 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2154 r_type.type.kind = GDScriptParser::DataType::NATIVE;
2155 r_type.type.native_type = p_identifier->name;
2156 r_type.type.is_constant = true;
2157 if (Engine::get_singleton()->has_singleton(p_identifier->name)) {
2158 r_type.type.is_meta_type = false;
2159 r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier->name);
2160 } else {
2161 r_type.type.is_meta_type = true;
2162 r_type.value = Variant();
2163 }
2164 }
2165
2166 return false;
2167}
2168
2169static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) {
2170 static int recursion_depth = 0;
2171 RecursionCheck recursion(&recursion_depth);
2172 if (unlikely(recursion.check())) {
2173 ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type.");
2174 }
2175
2176 GDScriptParser::DataType base_type = p_base.type;
2177 bool is_static = base_type.is_meta_type;
2178 while (base_type.is_set()) {
2179 switch (base_type.kind) {
2180 case GDScriptParser::DataType::CLASS:
2181 if (base_type.class_type->has_member(p_identifier)) {
2182 const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(p_identifier);
2183 switch (member.type) {
2184 case GDScriptParser::ClassNode::Member::CONSTANT:
2185 r_type.type = member.constant->get_datatype();
2186 if (member.constant->initializer && member.constant->initializer->is_constant) {
2187 r_type.value = member.constant->initializer->reduced_value;
2188 }
2189 return true;
2190 case GDScriptParser::ClassNode::Member::VARIABLE:
2191 if (!is_static) {
2192 if (member.variable->get_datatype().is_set() && !member.variable->get_datatype().is_variant()) {
2193 r_type.type = member.variable->get_datatype();
2194 return true;
2195 } else if (member.variable->initializer) {
2196 const GDScriptParser::ExpressionNode *init = member.variable->initializer;
2197 if (init->is_constant) {
2198 r_type.value = init->reduced_value;
2199 r_type = _type_from_variant(init->reduced_value);
2200 return true;
2201 } else if (init->start_line == p_context.current_line) {
2202 return false;
2203 // Detects if variable is assigned to itself
2204 } else if (_is_expression_named_identifier(init, member.variable->identifier->name)) {
2205 if (member.variable->initializer->get_datatype().is_set()) {
2206 r_type.type = member.variable->initializer->get_datatype();
2207 } else if (member.variable->get_datatype().is_set() && !member.variable->get_datatype().is_variant()) {
2208 r_type.type = member.variable->get_datatype();
2209 }
2210 return true;
2211 } else if (_guess_expression_type(p_context, init, r_type)) {
2212 return true;
2213 } else if (init->get_datatype().is_set() && !init->get_datatype().is_variant()) {
2214 r_type.type = init->get_datatype();
2215 return true;
2216 }
2217 }
2218 }
2219 // TODO: Check assignments in constructor.
2220 return false;
2221 case GDScriptParser::ClassNode::Member::ENUM:
2222 r_type.type = member.m_enum->get_datatype();
2223 r_type.enumeration = member.m_enum->identifier->name;
2224 return true;
2225 case GDScriptParser::ClassNode::Member::ENUM_VALUE:
2226 r_type = _type_from_variant(member.enum_value.value);
2227 return true;
2228 case GDScriptParser::ClassNode::Member::SIGNAL:
2229 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2230 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
2231 r_type.type.builtin_type = Variant::SIGNAL;
2232 return true;
2233 case GDScriptParser::ClassNode::Member::FUNCTION:
2234 if (is_static && !member.function->is_static) {
2235 return false;
2236 }
2237 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2238 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
2239 r_type.type.builtin_type = Variant::CALLABLE;
2240 return true;
2241 case GDScriptParser::ClassNode::Member::CLASS:
2242 r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2243 r_type.type.kind = GDScriptParser::DataType::CLASS;
2244 r_type.type.class_type = member.m_class;
2245 r_type.type.is_meta_type = true;
2246 return true;
2247 case GDScriptParser::ClassNode::Member::GROUP:
2248 return false; // No-op, but silences warnings.
2249 case GDScriptParser::ClassNode::Member::UNDEFINED:
2250 return false; // Unreachable.
2251 }
2252 return false;
2253 }
2254 base_type = base_type.class_type->base_type;
2255 break;
2256 case GDScriptParser::DataType::SCRIPT: {
2257 Ref<Script> scr = base_type.script_type;
2258 if (scr.is_valid()) {
2259 HashMap<StringName, Variant> constants;
2260 scr->get_constants(&constants);
2261 if (constants.has(p_identifier)) {
2262 r_type = _type_from_variant(constants[p_identifier]);
2263 return true;
2264 }
2265
2266 if (!is_static) {
2267 List<PropertyInfo> members;
2268 scr->get_script_property_list(&members);
2269 for (const PropertyInfo &prop : members) {
2270 if (prop.name == p_identifier) {
2271 r_type = _type_from_property(prop);
2272 return true;
2273 }
2274 }
2275 }
2276 Ref<Script> parent = scr->get_base_script();
2277 if (parent.is_valid()) {
2278 base_type.script_type = parent;
2279 } else {
2280 base_type.kind = GDScriptParser::DataType::NATIVE;
2281 base_type.native_type = scr->get_instance_base_type();
2282 }
2283 } else {
2284 return false;
2285 }
2286 } break;
2287 case GDScriptParser::DataType::NATIVE: {
2288 StringName class_name = base_type.native_type;
2289 if (!ClassDB::class_exists(class_name)) {
2290 return false;
2291 }
2292
2293 // Skip constants since they're all integers. Type does not matter because int has no members.
2294
2295 PropertyInfo prop;
2296 if (ClassDB::get_property_info(class_name, p_identifier, &prop)) {
2297 StringName getter = ClassDB::get_property_getter(class_name, p_identifier);
2298 if (getter != StringName()) {
2299 MethodBind *g = ClassDB::get_method(class_name, getter);
2300 if (g) {
2301 r_type = _type_from_property(g->get_return_info());
2302 return true;
2303 }
2304 } else {
2305 r_type = _type_from_property(prop);
2306 return true;
2307 }
2308 }
2309 return false;
2310 } break;
2311 case GDScriptParser::DataType::BUILTIN: {
2312 Callable::CallError err;
2313 Variant tmp;
2314 Variant::construct(base_type.builtin_type, tmp, nullptr, 0, err);
2315
2316 if (err.error != Callable::CallError::CALL_OK) {
2317 return false;
2318 }
2319 bool valid = false;
2320 Variant res = tmp.get(p_identifier, &valid);
2321 if (valid) {
2322 r_type = _type_from_variant(res);
2323 r_type.value = Variant();
2324 r_type.type.is_constant = false;
2325 return true;
2326 }
2327 return false;
2328 } break;
2329 default: {
2330 return false;
2331 } break;
2332 }
2333 }
2334 return false;
2335}
2336
2337static void _find_last_return_in_block(GDScriptParser::CompletionContext &p_context, int &r_last_return_line, const GDScriptParser::ExpressionNode **r_last_returned_value) {
2338 if (!p_context.current_suite) {
2339 return;
2340 }
2341
2342 for (int i = 0; i < p_context.current_suite->statements.size(); i++) {
2343 if (p_context.current_suite->statements[i]->start_line < r_last_return_line) {
2344 break;
2345 }
2346
2347 GDScriptParser::CompletionContext c = p_context;
2348 switch (p_context.current_suite->statements[i]->type) {
2349 case GDScriptParser::Node::FOR:
2350 c.current_suite = static_cast<const GDScriptParser::ForNode *>(p_context.current_suite->statements[i])->loop;
2351 _find_last_return_in_block(c, r_last_return_line, r_last_returned_value);
2352 break;
2353 case GDScriptParser::Node::WHILE:
2354 c.current_suite = static_cast<const GDScriptParser::WhileNode *>(p_context.current_suite->statements[i])->loop;
2355 _find_last_return_in_block(c, r_last_return_line, r_last_returned_value);
2356 break;
2357 case GDScriptParser::Node::IF: {
2358 const GDScriptParser::IfNode *_if = static_cast<const GDScriptParser::IfNode *>(p_context.current_suite->statements[i]);
2359 c.current_suite = _if->true_block;
2360 _find_last_return_in_block(c, r_last_return_line, r_last_returned_value);
2361 if (_if->false_block) {
2362 c.current_suite = _if->false_block;
2363 _find_last_return_in_block(c, r_last_return_line, r_last_returned_value);
2364 }
2365 } break;
2366 case GDScriptParser::Node::MATCH: {
2367 const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(p_context.current_suite->statements[i]);
2368 for (int j = 0; j < match->branches.size(); j++) {
2369 c.current_suite = match->branches[j]->block;
2370 _find_last_return_in_block(c, r_last_return_line, r_last_returned_value);
2371 }
2372 } break;
2373 case GDScriptParser::Node::RETURN: {
2374 const GDScriptParser::ReturnNode *ret = static_cast<const GDScriptParser::ReturnNode *>(p_context.current_suite->statements[i]);
2375 if (ret->return_value) {
2376 if (ret->start_line > r_last_return_line) {
2377 r_last_return_line = ret->start_line;
2378 *r_last_returned_value = ret->return_value;
2379 }
2380 }
2381 } break;
2382 default:
2383 break;
2384 }
2385 }
2386}
2387
2388static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) {
2389 static int recursion_depth = 0;
2390 RecursionCheck recursion(&recursion_depth);
2391 if (unlikely(recursion.check())) {
2392 ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type.");
2393 }
2394
2395 GDScriptParser::DataType base_type = p_base.type;
2396 bool is_static = base_type.is_meta_type;
2397
2398 if (is_static && p_method == SNAME("new")) {
2399 r_type.type = base_type;
2400 r_type.type.is_meta_type = false;
2401 r_type.type.is_constant = false;
2402 return true;
2403 }
2404
2405 while (base_type.is_set() && !base_type.is_variant()) {
2406 switch (base_type.kind) {
2407 case GDScriptParser::DataType::CLASS:
2408 if (base_type.class_type->has_function(p_method)) {
2409 const GDScriptParser::FunctionNode *method = base_type.class_type->get_member(p_method).function;
2410 if (!is_static || method->is_static) {
2411 if (method->get_datatype().is_set() && !method->get_datatype().is_variant()) {
2412 r_type.type = method->get_datatype();
2413 return true;
2414 }
2415
2416 int last_return_line = -1;
2417 const GDScriptParser::ExpressionNode *last_returned_value = nullptr;
2418 GDScriptParser::CompletionContext c = p_context;
2419 c.current_class = base_type.class_type;
2420 c.current_function = const_cast<GDScriptParser::FunctionNode *>(method);
2421 c.current_suite = method->body;
2422
2423 _find_last_return_in_block(c, last_return_line, &last_returned_value);
2424 if (last_returned_value) {
2425 c.current_line = c.current_suite->end_line;
2426 if (_guess_expression_type(c, last_returned_value, r_type)) {
2427 return true;
2428 }
2429 }
2430 }
2431 }
2432 base_type = base_type.class_type->base_type;
2433 break;
2434 case GDScriptParser::DataType::SCRIPT: {
2435 Ref<Script> scr = base_type.script_type;
2436 if (scr.is_valid()) {
2437 List<MethodInfo> methods;
2438 scr->get_script_method_list(&methods);
2439 for (const MethodInfo &mi : methods) {
2440 if (mi.name == p_method) {
2441 r_type = _type_from_property(mi.return_val);
2442 return true;
2443 }
2444 }
2445 Ref<Script> base_script = scr->get_base_script();
2446 if (base_script.is_valid()) {
2447 base_type.script_type = base_script;
2448 } else {
2449 base_type.kind = GDScriptParser::DataType::NATIVE;
2450 base_type.native_type = scr->get_instance_base_type();
2451 }
2452 } else {
2453 return false;
2454 }
2455 } break;
2456 case GDScriptParser::DataType::NATIVE: {
2457 if (!ClassDB::class_exists(base_type.native_type)) {
2458 return false;
2459 }
2460 MethodBind *mb = ClassDB::get_method(base_type.native_type, p_method);
2461 if (mb) {
2462 r_type = _type_from_property(mb->get_return_info());
2463 return true;
2464 }
2465 return false;
2466 } break;
2467 case GDScriptParser::DataType::BUILTIN: {
2468 Callable::CallError err;
2469 Variant tmp;
2470 Variant::construct(base_type.builtin_type, tmp, nullptr, 0, err);
2471 if (err.error != Callable::CallError::CALL_OK) {
2472 return false;
2473 }
2474
2475 List<MethodInfo> methods;
2476 tmp.get_method_list(&methods);
2477
2478 for (const MethodInfo &mi : methods) {
2479 if (mi.name == p_method) {
2480 r_type = _type_from_property(mi.return_val);
2481 return true;
2482 }
2483 }
2484 return false;
2485 } break;
2486 default: {
2487 return false;
2488 }
2489 }
2490 }
2491
2492 return false;
2493}
2494
2495static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
2496 if (!p_enum_hint.contains(".")) {
2497 // Global constant or in the current class.
2498 StringName current_enum = p_enum_hint;
2499 if (p_context.current_class && p_context.current_class->has_member(current_enum) && p_context.current_class->get_member(current_enum).type == GDScriptParser::ClassNode::Member::ENUM) {
2500 const GDScriptParser::EnumNode *_enum = p_context.current_class->get_member(current_enum).m_enum;
2501 for (int i = 0; i < _enum->values.size(); i++) {
2502 ScriptLanguage::CodeCompletionOption option(_enum->values[i].identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
2503 r_result.insert(option.display, option);
2504 }
2505 } else {
2506 for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
2507 if (CoreConstants::get_global_constant_enum(i) == current_enum) {
2508 ScriptLanguage::CodeCompletionOption option(CoreConstants::get_global_constant_name(i), ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
2509 r_result.insert(option.display, option);
2510 }
2511 }
2512 }
2513 } else {
2514 String class_name = p_enum_hint.get_slice(".", 0);
2515 String enum_name = p_enum_hint.get_slice(".", 1);
2516
2517 if (!ClassDB::class_exists(class_name)) {
2518 return;
2519 }
2520
2521 List<StringName> enum_constants;
2522 ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
2523 for (const StringName &E : enum_constants) {
2524 String candidate = class_name + "." + E;
2525 int location = _get_enum_constant_location(class_name, E);
2526 ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
2527 r_result.insert(option.display, option);
2528 }
2529 }
2530}
2531
2532static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) {
2533 Variant base = p_base.value;
2534 GDScriptParser::DataType base_type = p_base.type;
2535
2536 const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
2537
2538 while (base_type.is_set() && !base_type.is_variant()) {
2539 switch (base_type.kind) {
2540 case GDScriptParser::DataType::CLASS: {
2541 if (base_type.class_type->has_member(p_method)) {
2542 const GDScriptParser::ClassNode::Member &member = base_type.class_type->get_member(p_method);
2543
2544 if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
2545 r_arghint = _make_arguments_hint(member.function, p_argidx);
2546 return;
2547 }
2548 }
2549
2550 base_type = base_type.class_type->base_type;
2551 } break;
2552 case GDScriptParser::DataType::NATIVE: {
2553 StringName class_name = base_type.native_type;
2554 if (!ClassDB::class_exists(class_name)) {
2555 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
2556 break;
2557 }
2558
2559 MethodInfo info;
2560 int method_args = 0;
2561
2562 if (ClassDB::get_method_info(class_name, p_method, &info)) {
2563 method_args = info.arguments.size();
2564 if (base.get_type() == Variant::OBJECT) {
2565 Object *obj = base.operator Object *();
2566 if (obj) {
2567 List<String> options;
2568 obj->get_argument_options(p_method, p_argidx, &options);
2569 for (String &opt : options) {
2570 if (opt.is_quoted()) {
2571 opt = opt.unquote().quote(quote_style); // Handle user preference.
2572 }
2573 ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
2574 r_result.insert(option.display, option);
2575 }
2576 }
2577 }
2578
2579 if (p_argidx < method_args) {
2580 PropertyInfo arg_info = info.arguments[p_argidx];
2581 if (arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
2582 _find_enumeration_candidates(p_context, arg_info.class_name, r_result);
2583 }
2584 }
2585
2586 r_arghint = _make_arguments_hint(info, p_argidx);
2587 }
2588
2589 if (p_argidx == 0 && ClassDB::is_parent_class(class_name, SNAME("Node")) && (p_method == SNAME("get_node") || p_method == SNAME("has_node"))) {
2590 // Get autoloads
2591 List<PropertyInfo> props;
2592 ProjectSettings::get_singleton()->get_property_list(&props);
2593
2594 for (const PropertyInfo &E : props) {
2595 String s = E.name;
2596 if (!s.begins_with("autoload/")) {
2597 continue;
2598 }
2599 String name = s.get_slice("/", 1);
2600 ScriptLanguage::CodeCompletionOption option("/root/" + name, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
2601 option.insert_text = option.display.quote(quote_style);
2602 r_result.insert(option.display, option);
2603 }
2604 }
2605
2606 if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, SNAME("InputEvent")) && p_method.operator String().contains("action")) {
2607 // Get input actions
2608 List<PropertyInfo> props;
2609 ProjectSettings::get_singleton()->get_property_list(&props);
2610 for (const PropertyInfo &E : props) {
2611 String s = E.name;
2612 if (!s.begins_with("input/")) {
2613 continue;
2614 }
2615 String name = s.get_slice("/", 1);
2616 ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
2617 option.insert_text = option.display.quote(quote_style);
2618 r_result.insert(option.display, option);
2619 }
2620 }
2621
2622 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
2623 } break;
2624 case GDScriptParser::DataType::BUILTIN: {
2625 if (base.get_type() == Variant::NIL) {
2626 Callable::CallError err;
2627 Variant::construct(base_type.builtin_type, base, nullptr, 0, err);
2628 if (err.error != Callable::CallError::CALL_OK) {
2629 return;
2630 }
2631 }
2632
2633 List<MethodInfo> methods;
2634 base.get_method_list(&methods);
2635 for (const MethodInfo &E : methods) {
2636 if (E.name == p_method) {
2637 r_arghint = _make_arguments_hint(E, p_argidx);
2638 return;
2639 }
2640 }
2641
2642 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
2643 } break;
2644 default: {
2645 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
2646 } break;
2647 }
2648 }
2649}
2650
2651static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::SubscriptNode *p_subscript, GDScriptParser::DataType &r_base_type, Variant *r_base = nullptr) {
2652 if (p_context.base == nullptr) {
2653 return false;
2654 }
2655 const GDScriptParser::GetNodeNode *get_node = nullptr;
2656
2657 switch (p_subscript->base->type) {
2658 case GDScriptParser::Node::GET_NODE: {
2659 get_node = static_cast<GDScriptParser::GetNodeNode *>(p_subscript->base);
2660 } break;
2661
2662 case GDScriptParser::Node::IDENTIFIER: {
2663 const GDScriptParser::IdentifierNode *identifier_node = static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base);
2664
2665 switch (identifier_node->source) {
2666 case GDScriptParser::IdentifierNode::Source::MEMBER_VARIABLE: {
2667 if (p_context.current_class != nullptr) {
2668 const StringName &member_name = identifier_node->name;
2669 const GDScriptParser::ClassNode *current_class = p_context.current_class;
2670
2671 if (current_class->has_member(member_name)) {
2672 const GDScriptParser::ClassNode::Member &member = current_class->get_member(member_name);
2673
2674 if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
2675 const GDScriptParser::VariableNode *variable = static_cast<GDScriptParser::VariableNode *>(member.variable);
2676
2677 if (variable->initializer && variable->initializer->type == GDScriptParser::Node::GET_NODE) {
2678 get_node = static_cast<GDScriptParser::GetNodeNode *>(variable->initializer);
2679 }
2680 }
2681 }
2682 }
2683 } break;
2684 case GDScriptParser::IdentifierNode::Source::LOCAL_VARIABLE: {
2685 if (identifier_node->next != nullptr && identifier_node->next->type == GDScriptParser::ClassNode::Node::GET_NODE) {
2686 get_node = static_cast<GDScriptParser::GetNodeNode *>(identifier_node->next);
2687 }
2688 } break;
2689 default: {
2690 } break;
2691 }
2692 } break;
2693 default: {
2694 } break;
2695 }
2696
2697 if (get_node != nullptr) {
2698 const Object *node = p_context.base->call("get_node_or_null", NodePath(get_node->full_path));
2699 if (node != nullptr) {
2700 if (r_base != nullptr) {
2701 *r_base = node;
2702 }
2703 r_base_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
2704 r_base_type.kind = GDScriptParser::DataType::NATIVE;
2705 r_base_type.native_type = node->get_class_name();
2706 r_base_type.builtin_type = Variant::OBJECT;
2707 return true;
2708 }
2709 }
2710
2711 return false;
2712}
2713
2714static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
2715 if (p_call->type == GDScriptParser::Node::PRELOAD) {
2716 if (p_argidx == 0 && bool(EDITOR_GET("text_editor/completion/complete_file_paths"))) {
2717 _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
2718 }
2719
2720 MethodInfo mi(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "preload", PropertyInfo(Variant::STRING, "path"));
2721 r_arghint = _make_arguments_hint(mi, p_argidx);
2722 return;
2723 } else if (p_call->type != GDScriptParser::Node::CALL) {
2724 return;
2725 }
2726
2727 Variant base;
2728 GDScriptParser::DataType base_type;
2729 bool _static = false;
2730 const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call);
2731 GDScriptParser::Node::Type callee_type = call->get_callee_type();
2732
2733 GDScriptCompletionIdentifier connect_base;
2734
2735 if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
2736 const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
2737
2738 if (subscript->base != nullptr && subscript->base->type == GDScriptParser::Node::IDENTIFIER) {
2739 const GDScriptParser::IdentifierNode *base_identifier = static_cast<const GDScriptParser::IdentifierNode *>(subscript->base);
2740
2741 Variant::Type method_type = GDScriptParser::get_builtin_type(base_identifier->name);
2742 if (method_type < Variant::VARIANT_MAX) {
2743 Variant v;
2744 Callable::CallError err;
2745 Variant::construct(method_type, v, nullptr, 0, err);
2746 if (err.error != Callable::CallError::CALL_OK) {
2747 return;
2748 }
2749 List<MethodInfo> methods;
2750 v.get_method_list(&methods);
2751
2752 for (MethodInfo &E : methods) {
2753 if (p_argidx >= E.arguments.size()) {
2754 continue;
2755 }
2756 if (E.name == call->function_name) {
2757 r_arghint += _make_arguments_hint(E, p_argidx);
2758 return;
2759 }
2760 }
2761 }
2762 }
2763
2764 if (subscript->is_attribute) {
2765 bool found_type = _get_subscript_type(p_context, subscript, base_type, &base);
2766
2767 if (!found_type) {
2768 GDScriptCompletionIdentifier ci;
2769 if (_guess_expression_type(p_context, subscript->base, ci)) {
2770 base_type = ci.type;
2771 base = ci.value;
2772 } else {
2773 return;
2774 }
2775 }
2776
2777 _static = base_type.is_meta_type;
2778 }
2779 } else if (Variant::has_utility_function(call->function_name)) {
2780 MethodInfo info = Variant::get_utility_function_info(call->function_name);
2781 r_arghint = _make_arguments_hint(info, p_argidx);
2782 return;
2783 } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
2784 MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
2785 r_arghint = _make_arguments_hint(info, p_argidx);
2786 return;
2787 } else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
2788 // Complete constructor.
2789 List<MethodInfo> constructors;
2790 Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors);
2791
2792 int i = 0;
2793 for (const MethodInfo &E : constructors) {
2794 if (p_argidx >= E.arguments.size()) {
2795 continue;
2796 }
2797 if (i > 0) {
2798 r_arghint += "\n";
2799 }
2800 r_arghint += _make_arguments_hint(E, p_argidx);
2801 i++;
2802 }
2803 return;
2804 } else if (call->is_super || callee_type == GDScriptParser::Node::IDENTIFIER) {
2805 base = p_context.base;
2806
2807 if (p_context.current_class) {
2808 base_type = p_context.current_class->get_datatype();
2809 _static = !p_context.current_function || p_context.current_function->is_static;
2810 }
2811 } else {
2812 return;
2813 }
2814
2815 GDScriptCompletionIdentifier ci;
2816 ci.type = base_type;
2817 ci.value = base;
2818 _find_call_arguments(p_context, ci, call->function_name, p_argidx, _static, r_result, r_arghint);
2819
2820 r_forced = r_result.size() > 0;
2821}
2822
2823::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
2824 const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
2825
2826 GDScriptParser parser;
2827 GDScriptAnalyzer analyzer(&parser);
2828
2829 parser.parse(p_code, p_path, true);
2830 analyzer.analyze();
2831
2832 r_forced = false;
2833 HashMap<String, ScriptLanguage::CodeCompletionOption> options;
2834
2835 GDScriptParser::CompletionContext completion_context = parser.get_completion_context();
2836 completion_context.base = p_owner;
2837 bool is_function = false;
2838
2839 switch (completion_context.type) {
2840 case GDScriptParser::COMPLETION_NONE:
2841 break;
2842 case GDScriptParser::COMPLETION_ANNOTATION: {
2843 List<MethodInfo> annotations;
2844 parser.get_annotation_list(&annotations);
2845 for (const MethodInfo &E : annotations) {
2846 ScriptLanguage::CodeCompletionOption option(E.name.substr(1), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
2847 if (E.arguments.size() > 0) {
2848 option.insert_text += "(";
2849 }
2850 options.insert(option.display, option);
2851 }
2852 r_forced = true;
2853 } break;
2854 case GDScriptParser::COMPLETION_ANNOTATION_ARGUMENTS: {
2855 if (completion_context.node == nullptr || completion_context.node->type != GDScriptParser::Node::ANNOTATION) {
2856 break;
2857 }
2858 const GDScriptParser::AnnotationNode *annotation = static_cast<const GDScriptParser::AnnotationNode *>(completion_context.node);
2859 _find_annotation_arguments(annotation, completion_context.current_argument, quote_style, options);
2860 r_forced = true;
2861 } break;
2862 case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: {
2863 // Constants.
2864 {
2865 List<StringName> constants;
2866 Variant::get_constants_for_type(completion_context.builtin_type, &constants);
2867 for (const StringName &E : constants) {
2868 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
2869 bool valid = false;
2870 Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid);
2871 if (valid) {
2872 option.default_value = default_value;
2873 }
2874 options.insert(option.display, option);
2875 }
2876 }
2877 // Methods.
2878 {
2879 List<StringName> methods;
2880 Variant::get_builtin_method_list(completion_context.builtin_type, &methods);
2881 for (const StringName &E : methods) {
2882 if (Variant::is_builtin_method_static(completion_context.builtin_type, E)) {
2883 ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
2884 if (Variant::get_builtin_method_argument_count(completion_context.builtin_type, E) > 0 || Variant::is_builtin_method_vararg(completion_context.builtin_type, E)) {
2885 option.insert_text += "(";
2886 } else {
2887 option.insert_text += "()";
2888 }
2889 options.insert(option.display, option);
2890 }
2891 }
2892 }
2893 } break;
2894 case GDScriptParser::COMPLETION_INHERIT_TYPE: {
2895 _list_available_types(true, completion_context, options);
2896 r_forced = true;
2897 } break;
2898 case GDScriptParser::COMPLETION_TYPE_NAME_OR_VOID: {
2899 ScriptLanguage::CodeCompletionOption option("void", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
2900 options.insert(option.display, option);
2901 }
2902 [[fallthrough]];
2903 case GDScriptParser::COMPLETION_TYPE_NAME: {
2904 _list_available_types(false, completion_context, options);
2905 r_forced = true;
2906 } break;
2907 case GDScriptParser::COMPLETION_PROPERTY_DECLARATION_OR_TYPE: {
2908 _list_available_types(false, completion_context, options);
2909 ScriptLanguage::CodeCompletionOption get("get", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
2910 options.insert(get.display, get);
2911 ScriptLanguage::CodeCompletionOption set("set", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
2912 options.insert(set.display, set);
2913 r_forced = true;
2914 } break;
2915 case GDScriptParser::COMPLETION_PROPERTY_DECLARATION: {
2916 ScriptLanguage::CodeCompletionOption get("get", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
2917 options.insert(get.display, get);
2918 ScriptLanguage::CodeCompletionOption set("set", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
2919 options.insert(set.display, set);
2920 r_forced = true;
2921 } break;
2922 case GDScriptParser::COMPLETION_PROPERTY_METHOD: {
2923 if (!completion_context.current_class) {
2924 break;
2925 }
2926 for (int i = 0; i < completion_context.current_class->members.size(); i++) {
2927 const GDScriptParser::ClassNode::Member &member = completion_context.current_class->members[i];
2928 if (member.type != GDScriptParser::ClassNode::Member::FUNCTION) {
2929 continue;
2930 }
2931 if (member.function->is_static) {
2932 continue;
2933 }
2934 ScriptLanguage::CodeCompletionOption option(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
2935 options.insert(option.display, option);
2936 }
2937 r_forced = true;
2938 } break;
2939 case GDScriptParser::COMPLETION_ASSIGN: {
2940 GDScriptCompletionIdentifier type;
2941 if (!completion_context.node || completion_context.node->type != GDScriptParser::Node::ASSIGNMENT) {
2942 break;
2943 }
2944 if (!_guess_expression_type(completion_context, static_cast<const GDScriptParser::AssignmentNode *>(completion_context.node)->assignee, type)) {
2945 _find_identifiers(completion_context, false, options, 0);
2946 r_forced = true;
2947 break;
2948 }
2949
2950 if (!type.enumeration.is_empty()) {
2951 _find_enumeration_candidates(completion_context, type.enumeration, options);
2952 r_forced = options.size() > 0;
2953 } else {
2954 _find_identifiers(completion_context, false, options, 0);
2955 r_forced = true;
2956 }
2957 } break;
2958 case GDScriptParser::COMPLETION_METHOD:
2959 is_function = true;
2960 [[fallthrough]];
2961 case GDScriptParser::COMPLETION_IDENTIFIER: {
2962 _find_identifiers(completion_context, is_function, options, 0);
2963 } break;
2964 case GDScriptParser::COMPLETION_ATTRIBUTE_METHOD:
2965 is_function = true;
2966 [[fallthrough]];
2967 case GDScriptParser::COMPLETION_ATTRIBUTE: {
2968 r_forced = true;
2969 const GDScriptParser::SubscriptNode *attr = static_cast<const GDScriptParser::SubscriptNode *>(completion_context.node);
2970 if (attr->base) {
2971 GDScriptCompletionIdentifier base;
2972 bool found_type = _get_subscript_type(completion_context, attr, base.type);
2973 if (!found_type && !_guess_expression_type(completion_context, attr->base, base)) {
2974 break;
2975 }
2976
2977 _find_identifiers_in_base(base, is_function, options, 0);
2978 }
2979 } break;
2980 case GDScriptParser::COMPLETION_SUBSCRIPT: {
2981 const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(completion_context.node);
2982 GDScriptCompletionIdentifier base;
2983 if (!_guess_expression_type(completion_context, subscript->base, base)) {
2984 break;
2985 }
2986
2987 _find_identifiers_in_base(base, false, options, 0);
2988 } break;
2989 case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
2990 if (!completion_context.current_class) {
2991 break;
2992 }
2993 const GDScriptParser::TypeNode *type = static_cast<const GDScriptParser::TypeNode *>(completion_context.node);
2994 bool found = true;
2995 GDScriptCompletionIdentifier base;
2996 base.type.kind = GDScriptParser::DataType::CLASS;
2997 base.type.type_source = GDScriptParser::DataType::INFERRED;
2998 base.type.is_constant = true;
2999 base.type.class_type = completion_context.current_class;
3000 base.value = completion_context.base;
3001
3002 for (int i = 0; i < completion_context.current_argument; i++) {
3003 GDScriptCompletionIdentifier ci;
3004 if (!_guess_identifier_type_from_base(completion_context, base, type->type_chain[i]->name, ci)) {
3005 found = false;
3006 break;
3007 }
3008 base = ci;
3009 }
3010
3011 // TODO: Improve this to only list types.
3012 if (found) {
3013 _find_identifiers_in_base(base, false, options, 0);
3014 }
3015 r_forced = true;
3016 } break;
3017 case GDScriptParser::COMPLETION_RESOURCE_PATH: {
3018 if (EDITOR_GET("text_editor/completion/complete_file_paths")) {
3019 _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options);
3020 r_forced = true;
3021 }
3022 } break;
3023 case GDScriptParser::COMPLETION_CALL_ARGUMENTS: {
3024 if (!completion_context.node) {
3025 break;
3026 }
3027 _find_call_arguments(completion_context, completion_context.node, completion_context.current_argument, options, r_forced, r_call_hint);
3028 } break;
3029 case GDScriptParser::COMPLETION_OVERRIDE_METHOD: {
3030 GDScriptParser::DataType native_type = completion_context.current_class->base_type;
3031 while (native_type.is_set() && native_type.kind != GDScriptParser::DataType::NATIVE) {
3032 switch (native_type.kind) {
3033 case GDScriptParser::DataType::CLASS: {
3034 native_type = native_type.class_type->base_type;
3035 } break;
3036 default: {
3037 native_type.kind = GDScriptParser::DataType::UNRESOLVED;
3038 } break;
3039 }
3040 }
3041
3042 if (!native_type.is_set()) {
3043 break;
3044 }
3045
3046 StringName class_name = native_type.native_type;
3047 if (!ClassDB::class_exists(class_name)) {
3048 break;
3049 }
3050
3051 bool use_type_hint = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints").operator bool();
3052
3053 List<MethodInfo> virtual_methods;
3054 ClassDB::get_virtual_methods(class_name, &virtual_methods);
3055
3056 {
3057 // Not truly a virtual method, but can also be "overridden".
3058 MethodInfo static_init("_static_init");
3059 static_init.return_val.type = Variant::NIL;
3060 static_init.flags |= METHOD_FLAG_STATIC | METHOD_FLAG_VIRTUAL;
3061 virtual_methods.push_back(static_init);
3062 }
3063
3064 for (const MethodInfo &mi : virtual_methods) {
3065 String method_hint = mi.name;
3066 if (method_hint.contains(":")) {
3067 method_hint = method_hint.get_slice(":", 0);
3068 }
3069 method_hint += "(";
3070
3071 if (mi.arguments.size()) {
3072 for (int i = 0; i < mi.arguments.size(); i++) {
3073 if (i > 0) {
3074 method_hint += ", ";
3075 }
3076 String arg = mi.arguments[i].name;
3077 if (arg.contains(":")) {
3078 arg = arg.substr(0, arg.find(":"));
3079 }
3080 method_hint += arg;
3081 if (use_type_hint) {
3082 method_hint += ": " + _get_visual_datatype(mi.arguments[i], true, class_name);
3083 }
3084 }
3085 }
3086 method_hint += ")";
3087 if (use_type_hint) {
3088 method_hint += " -> " + _get_visual_datatype(mi.return_val, false, class_name);
3089 }
3090 method_hint += ":";
3091
3092 ScriptLanguage::CodeCompletionOption option(method_hint, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
3093 options.insert(option.display, option);
3094 }
3095 } break;
3096 case GDScriptParser::COMPLETION_GET_NODE: {
3097 // Handles the `$Node/Path` or `$"Some NodePath"` syntax specifically.
3098 if (p_owner) {
3099 List<String> opts;
3100 p_owner->get_argument_options("get_node", 0, &opts);
3101
3102 for (const String &E : opts) {
3103 r_forced = true;
3104 String opt = E.strip_edges();
3105 if (opt.is_quoted()) {
3106 // Remove quotes so that we can handle user preferred quote style,
3107 // or handle NodePaths which are valid identifiers and don't need quotes.
3108 opt = opt.unquote();
3109 }
3110 // The path needs quotes if it's not a valid identifier (with an exception
3111 // for "/" as path separator, which also doesn't require quotes).
3112 if (!opt.replace("/", "_").is_valid_identifier()) {
3113 // Ignore quote_style and just use double quotes for paths with apostrophes.
3114 // Double quotes don't need to be checked because they're not valid in node and property names.
3115 opt = opt.quote(opt.contains("'") ? "\"" : quote_style); // Handle user preference.
3116 }
3117 ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
3118 options.insert(option.display, option);
3119 }
3120
3121 // Get autoloads.
3122 for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
3123 String path = "/root/" + E.key;
3124 ScriptLanguage::CodeCompletionOption option(path.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
3125 options.insert(option.display, option);
3126 }
3127 }
3128 } break;
3129 case GDScriptParser::COMPLETION_SUPER_METHOD: {
3130 if (!completion_context.current_class) {
3131 break;
3132 }
3133 _find_identifiers_in_class(completion_context.current_class, true, false, true, options, 0);
3134 } break;
3135 }
3136
3137 for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &E : options) {
3138 r_options->push_back(E.value);
3139 }
3140
3141 return OK;
3142}
3143
3144#else
3145
3146Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
3147 return OK;
3148}
3149
3150#endif
3151
3152//////// END COMPLETION //////////
3153
3154String GDScriptLanguage::_get_indentation() const {
3155#ifdef TOOLS_ENABLED
3156 if (Engine::get_singleton()->is_editor_hint()) {
3157 bool use_space_indentation = EDITOR_GET("text_editor/behavior/indent/type");
3158
3159 if (use_space_indentation) {
3160 int indent_size = EDITOR_GET("text_editor/behavior/indent/size");
3161 return String(" ").repeat(indent_size);
3162 }
3163 }
3164#endif
3165 return "\t";
3166}
3167
3168void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {
3169 String indent = _get_indentation();
3170
3171 Vector<String> lines = p_code.split("\n");
3172 List<int> indent_stack;
3173
3174 for (int i = 0; i < lines.size(); i++) {
3175 String l = lines[i];
3176 int tc = 0;
3177 for (int j = 0; j < l.length(); j++) {
3178 if (l[j] == ' ' || l[j] == '\t') {
3179 tc++;
3180 } else {
3181 break;
3182 }
3183 }
3184
3185 String st = l.substr(tc, l.length()).strip_edges();
3186 if (st.is_empty() || st.begins_with("#")) {
3187 continue; //ignore!
3188 }
3189
3190 int ilevel = 0;
3191 if (indent_stack.size()) {
3192 ilevel = indent_stack.back()->get();
3193 }
3194
3195 if (tc > ilevel) {
3196 indent_stack.push_back(tc);
3197 } else if (tc < ilevel) {
3198 while (indent_stack.size() && indent_stack.back()->get() > tc) {
3199 indent_stack.pop_back();
3200 }
3201
3202 if (indent_stack.size() && indent_stack.back()->get() != tc) {
3203 indent_stack.push_back(tc); // this is not right but gets the job done
3204 }
3205 }
3206
3207 if (i >= p_from_line) {
3208 l = indent.repeat(indent_stack.size()) + st;
3209 } else if (i > p_to_line) {
3210 break;
3211 }
3212
3213 lines.write[i] = l;
3214 }
3215
3216 p_code = "";
3217 for (int i = 0; i < lines.size(); i++) {
3218 if (i > 0) {
3219 p_code += "\n";
3220 }
3221 p_code += lines[i];
3222 }
3223}
3224
3225#ifdef TOOLS_ENABLED
3226
3227static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, const String &p_symbol, bool p_is_function, GDScriptLanguage::LookupResult &r_result) {
3228 GDScriptParser::DataType base_type = p_base;
3229
3230 while (base_type.is_set()) {
3231 switch (base_type.kind) {
3232 case GDScriptParser::DataType::CLASS: {
3233 if (base_type.class_type) {
3234 if (base_type.class_type->has_member(p_symbol)) {
3235 r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
3236 r_result.location = base_type.class_type->get_member(p_symbol).get_line();
3237 r_result.class_path = base_type.script_path;
3238 Error err = OK;
3239 r_result.script = GDScriptCache::get_shallow_script(r_result.class_path, err);
3240 return err;
3241 }
3242 base_type = base_type.class_type->base_type;
3243 }
3244 } break;
3245 case GDScriptParser::DataType::SCRIPT: {
3246 Ref<Script> scr = base_type.script_type;
3247 if (scr.is_valid()) {
3248 int line = scr->get_member_line(p_symbol);
3249 if (line >= 0) {
3250 r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
3251 r_result.location = line;
3252 r_result.script = scr;
3253 return OK;
3254 }
3255 Ref<Script> base_script = scr->get_base_script();
3256 if (base_script.is_valid()) {
3257 base_type.script_type = base_script;
3258 } else {
3259 base_type.kind = GDScriptParser::DataType::NATIVE;
3260 base_type.native_type = scr->get_instance_base_type();
3261 }
3262 } else {
3263 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
3264 }
3265 } break;
3266 case GDScriptParser::DataType::NATIVE: {
3267 StringName class_name = base_type.native_type;
3268 if (!ClassDB::class_exists(class_name)) {
3269 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
3270 break;
3271 }
3272
3273 if (ClassDB::has_method(class_name, p_symbol, true)) {
3274 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
3275 r_result.class_name = base_type.native_type;
3276 r_result.class_member = p_symbol;
3277 return OK;
3278 }
3279
3280 List<MethodInfo> virtual_methods;
3281 ClassDB::get_virtual_methods(class_name, &virtual_methods, true);
3282 for (const MethodInfo &E : virtual_methods) {
3283 if (E.name == p_symbol) {
3284 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
3285 r_result.class_name = base_type.native_type;
3286 r_result.class_member = p_symbol;
3287 return OK;
3288 }
3289 }
3290
3291 if (ClassDB::has_signal(class_name, p_symbol, true)) {
3292 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL;
3293 r_result.class_name = base_type.native_type;
3294 r_result.class_member = p_symbol;
3295 return OK;
3296 }
3297
3298 StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true);
3299 if (enum_name != StringName()) {
3300 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
3301 r_result.class_name = base_type.native_type;
3302 r_result.class_member = enum_name;
3303 return OK;
3304 }
3305
3306 List<String> constants;
3307 ClassDB::get_integer_constant_list(class_name, &constants, true);
3308 for (const String &E : constants) {
3309 if (E == p_symbol) {
3310 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
3311 r_result.class_name = base_type.native_type;
3312 r_result.class_member = p_symbol;
3313 return OK;
3314 }
3315 }
3316
3317 if (ClassDB::has_property(class_name, p_symbol, true)) {
3318 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY;
3319 r_result.class_name = base_type.native_type;
3320 r_result.class_member = p_symbol;
3321 return OK;
3322 }
3323
3324 StringName parent = ClassDB::get_parent_class(class_name);
3325 if (parent != StringName()) {
3326 base_type.native_type = parent;
3327 } else {
3328 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
3329 }
3330 } break;
3331 case GDScriptParser::DataType::BUILTIN: {
3332 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
3333
3334 if (Variant::has_constant(base_type.builtin_type, p_symbol)) {
3335 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
3336 r_result.class_name = Variant::get_type_name(base_type.builtin_type);
3337 r_result.class_member = p_symbol;
3338 return OK;
3339 }
3340
3341 Variant v;
3342 Ref<RefCounted> v_ref;
3343 if (base_type.builtin_type == Variant::OBJECT) {
3344 v_ref.instantiate();
3345 v = v_ref;
3346 } else {
3347 Callable::CallError err;
3348 Variant::construct(base_type.builtin_type, v, nullptr, 0, err);
3349 if (err.error != Callable::CallError::CALL_OK) {
3350 break;
3351 }
3352 }
3353
3354 if (v.has_method(p_symbol)) {
3355 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
3356 r_result.class_name = Variant::get_type_name(base_type.builtin_type);
3357 r_result.class_member = p_symbol;
3358 return OK;
3359 }
3360
3361 bool valid = false;
3362 v.get(p_symbol, &valid);
3363 if (valid) {
3364 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY;
3365 r_result.class_name = Variant::get_type_name(base_type.builtin_type);
3366 r_result.class_member = p_symbol;
3367 return OK;
3368 }
3369 } break;
3370 default: {
3371 base_type.kind = GDScriptParser::DataType::UNRESOLVED;
3372 } break;
3373 }
3374 }
3375
3376 return ERR_CANT_RESOLVE;
3377}
3378
3379::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) {
3380 // Before parsing, try the usual stuff.
3381 if (ClassDB::class_exists(p_symbol)) {
3382 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
3383 r_result.class_name = p_symbol;
3384 return OK;
3385 }
3386
3387 for (int i = 0; i < Variant::VARIANT_MAX; i++) {
3388 Variant::Type t = Variant::Type(i);
3389 if (Variant::get_type_name(t) == p_symbol) {
3390 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
3391 r_result.class_name = Variant::get_type_name(t);
3392 return OK;
3393 }
3394 }
3395
3396 if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) {
3397 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
3398 r_result.class_name = "@GDScript";
3399 r_result.class_member = p_symbol;
3400 return OK;
3401 }
3402
3403 GDScriptParser parser;
3404 parser.parse(p_code, p_path, true);
3405
3406 GDScriptParser::CompletionContext context = parser.get_completion_context();
3407 context.base = p_owner;
3408
3409 // Allows class functions with the names like built-ins to be handled properly.
3410 if (context.type != GDScriptParser::COMPLETION_ATTRIBUTE) {
3411 // Need special checks for assert and preload as they are technically
3412 // keywords, so are not registered in GDScriptUtilityFunctions.
3413 if (GDScriptUtilityFunctions::function_exists(p_symbol) || "assert" == p_symbol || "preload" == p_symbol) {
3414 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD;
3415 r_result.class_name = "@GDScript";
3416 r_result.class_member = p_symbol;
3417 return OK;
3418 }
3419 }
3420
3421 GDScriptAnalyzer analyzer(&parser);
3422 analyzer.analyze();
3423
3424 if (context.current_class && context.current_class->extends.size() > 0) {
3425 bool success = false;
3426 ClassDB::get_integer_constant(context.current_class->extends[0]->name, p_symbol, &success);
3427 if (success) {
3428 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
3429 r_result.class_name = context.current_class->extends[0]->name;
3430 r_result.class_member = p_symbol;
3431 return OK;
3432 }
3433 }
3434
3435 bool is_function = false;
3436
3437 switch (context.type) {
3438 case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT_OR_STATIC_METHOD: {
3439 if (!Variant::has_builtin_method(context.builtin_type, StringName(p_symbol))) {
3440 // A constant.
3441 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
3442 r_result.class_name = Variant::get_type_name(context.builtin_type);
3443 r_result.class_member = p_symbol;
3444 return OK;
3445 }
3446 // A method.
3447 GDScriptParser::DataType base_type;
3448 base_type.kind = GDScriptParser::DataType::BUILTIN;
3449 base_type.builtin_type = context.builtin_type;
3450 if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) {
3451 return OK;
3452 }
3453 } break;
3454 case GDScriptParser::COMPLETION_SUPER_METHOD:
3455 case GDScriptParser::COMPLETION_METHOD: {
3456 is_function = true;
3457 [[fallthrough]];
3458 }
3459 case GDScriptParser::COMPLETION_ASSIGN:
3460 case GDScriptParser::COMPLETION_CALL_ARGUMENTS:
3461 case GDScriptParser::COMPLETION_IDENTIFIER:
3462 case GDScriptParser::COMPLETION_PROPERTY_METHOD: {
3463 GDScriptParser::DataType base_type;
3464 if (context.current_class) {
3465 if (context.type != GDScriptParser::COMPLETION_SUPER_METHOD) {
3466 base_type = context.current_class->get_datatype();
3467 } else {
3468 base_type = context.current_class->base_type;
3469 }
3470 } else {
3471 break;
3472 }
3473
3474 if (!is_function && context.current_suite) {
3475 // Lookup local variables.
3476 const GDScriptParser::SuiteNode *suite = context.current_suite;
3477 while (suite) {
3478 if (suite->has_local(p_symbol)) {
3479 r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
3480 r_result.location = suite->get_local(p_symbol).start_line;
3481 return OK;
3482 }
3483 suite = suite->parent_block;
3484 }
3485 }
3486
3487 if (_lookup_symbol_from_base(base_type, p_symbol, is_function, r_result) == OK) {
3488 return OK;
3489 }
3490
3491 if (!is_function) {
3492 // Guess in autoloads as singletons.
3493 if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) {
3494 const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(p_symbol);
3495 if (autoload.is_singleton) {
3496 String scr_path = autoload.path;
3497 if (!scr_path.ends_with(".gd")) {
3498 // Not a script, try find the script anyway,
3499 // may have some success.
3500 scr_path = scr_path.get_basename() + ".gd";
3501 }
3502
3503 if (FileAccess::exists(scr_path)) {
3504 r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
3505 r_result.location = 0;
3506 r_result.script = ResourceLoader::load(scr_path);
3507 return OK;
3508 }
3509 }
3510 }
3511
3512 // Global.
3513 HashMap<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map();
3514 if (classes.has(p_symbol)) {
3515 Variant value = GDScriptLanguage::get_singleton()->get_global_array()[classes[p_symbol]];
3516 if (value.get_type() == Variant::OBJECT) {
3517 Object *obj = value;
3518 if (obj) {
3519 if (Object::cast_to<GDScriptNativeClass>(obj)) {
3520 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
3521 r_result.class_name = Object::cast_to<GDScriptNativeClass>(obj)->get_name();
3522 } else {
3523 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS;
3524 r_result.class_name = obj->get_class();
3525 }
3526
3527 // proxy class remove the underscore.
3528 if (r_result.class_name.begins_with("_")) {
3529 r_result.class_name = r_result.class_name.substr(1);
3530 }
3531 return OK;
3532 }
3533 } else {
3534 /*
3535 // Because get_integer_constant_enum and get_integer_constant don't work on @GlobalScope
3536 // We cannot determine the exact nature of the identifier here
3537 // Otherwise these codes would work
3538 StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true);
3539 if (enumName != nullptr) {
3540 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
3541 r_result.class_name = "@GlobalScope";
3542 r_result.class_member = enumName;
3543 return OK;
3544 }
3545 else {
3546 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
3547 r_result.class_name = "@GlobalScope";
3548 r_result.class_member = p_symbol;
3549 return OK;
3550 }*/
3551 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE;
3552 r_result.class_name = "@GlobalScope";
3553 r_result.class_member = p_symbol;
3554 return OK;
3555 }
3556 } else {
3557 List<StringName> utility_functions;
3558 Variant::get_utility_function_list(&utility_functions);
3559 if (utility_functions.find(p_symbol) != nullptr) {
3560 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE;
3561 r_result.class_name = "@GlobalScope";
3562 r_result.class_member = p_symbol;
3563 return OK;
3564 }
3565 }
3566 }
3567 } break;
3568 case GDScriptParser::COMPLETION_ATTRIBUTE_METHOD: {
3569 is_function = true;
3570 [[fallthrough]];
3571 }
3572 case GDScriptParser::COMPLETION_ATTRIBUTE: {
3573 if (context.node->type != GDScriptParser::Node::SUBSCRIPT) {
3574 break;
3575 }
3576 const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(context.node);
3577 if (!subscript->is_attribute) {
3578 break;
3579 }
3580 GDScriptCompletionIdentifier base;
3581
3582 bool found_type = _get_subscript_type(context, subscript, base.type);
3583 if (!found_type && !_guess_expression_type(context, subscript->base, base)) {
3584 break;
3585 }
3586
3587 if (_lookup_symbol_from_base(base.type, p_symbol, is_function, r_result) == OK) {
3588 return OK;
3589 }
3590 } break;
3591 case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
3592 if (context.node == nullptr || context.node->type != GDScriptParser::Node::TYPE) {
3593 break;
3594 }
3595 const GDScriptParser::TypeNode *type = static_cast<const GDScriptParser::TypeNode *>(context.node);
3596
3597 GDScriptParser::DataType base_type;
3598 const GDScriptParser::IdentifierNode *prev = nullptr;
3599 for (const GDScriptParser::IdentifierNode *E : type->type_chain) {
3600 if (E->name == p_symbol && prev != nullptr) {
3601 base_type = prev->get_datatype();
3602 break;
3603 }
3604 prev = E;
3605 }
3606 if (base_type.kind != GDScriptParser::DataType::CLASS) {
3607 GDScriptCompletionIdentifier base;
3608 if (!_guess_expression_type(context, prev, base)) {
3609 break;
3610 }
3611 base_type = base.type;
3612 }
3613
3614 if (_lookup_symbol_from_base(base_type, p_symbol, is_function, r_result) == OK) {
3615 return OK;
3616 }
3617 } break;
3618 case GDScriptParser::COMPLETION_OVERRIDE_METHOD: {
3619 GDScriptParser::DataType base_type = context.current_class->base_type;
3620
3621 if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) {
3622 return OK;
3623 }
3624 } break;
3625 case GDScriptParser::COMPLETION_PROPERTY_DECLARATION_OR_TYPE:
3626 case GDScriptParser::COMPLETION_TYPE_NAME_OR_VOID:
3627 case GDScriptParser::COMPLETION_TYPE_NAME: {
3628 GDScriptParser::DataType base_type = context.current_class->get_datatype();
3629
3630 if (_lookup_symbol_from_base(base_type, p_symbol, false, r_result) == OK) {
3631 return OK;
3632 }
3633 } break;
3634 case GDScriptParser::COMPLETION_ANNOTATION: {
3635 const String annotation_symbol = "@" + p_symbol;
3636 if (parser.annotation_exists(annotation_symbol)) {
3637 r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ANNOTATION;
3638 r_result.class_name = "@GDScript";
3639 r_result.class_member = annotation_symbol;
3640 return OK;
3641 }
3642 } break;
3643 default: {
3644 }
3645 }
3646
3647 return ERR_CANT_RESOLVE;
3648}
3649
3650#endif
3651