1 /*************************************************************************/
2 /* gdscript_editor.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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 "core/engine.h"
34 #include "core/global_constants.h"
35 #include "core/os/file_access.h"
36 #include "gdscript_compiler.h"
37
38 #ifdef TOOLS_ENABLED
39 #include "editor/editor_file_system.h"
40 #include "editor/editor_settings.h"
41 #endif
42
get_comment_delimiters(List<String> * p_delimiters) const43 void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
44
45 p_delimiters->push_back("#");
46 }
47
get_string_delimiters(List<String> * p_delimiters) const48 void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
49
50 p_delimiters->push_back("\" \"");
51 p_delimiters->push_back("' '");
52 p_delimiters->push_back("\"\"\" \"\"\"");
53 }
54
_get_processed_template(const String & p_template,const String & p_base_class_name) const55 String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const {
56
57 String processed_template = p_template;
58
59 #ifdef TOOLS_ENABLED
60 if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) {
61 processed_template = processed_template.replace("%INT_TYPE%", ": int");
62 processed_template = processed_template.replace("%STRING_TYPE%", ": String");
63 processed_template = processed_template.replace("%FLOAT_TYPE%", ": float");
64 processed_template = processed_template.replace("%VOID_RETURN%", " -> void");
65 } else {
66 processed_template = processed_template.replace("%INT_TYPE%", "");
67 processed_template = processed_template.replace("%STRING_TYPE%", "");
68 processed_template = processed_template.replace("%FLOAT_TYPE%", "");
69 processed_template = processed_template.replace("%VOID_RETURN%", "");
70 }
71 #else
72 processed_template = processed_template.replace("%INT_TYPE%", "");
73 processed_template = processed_template.replace("%STRING_TYPE%", "");
74 processed_template = processed_template.replace("%FLOAT_TYPE%", "");
75 processed_template = processed_template.replace("%VOID_RETURN%", "");
76 #endif
77
78 processed_template = processed_template.replace("%BASE%", p_base_class_name);
79 processed_template = processed_template.replace("%TS%", _get_indentation());
80
81 return processed_template;
82 }
83
get_template(const String & p_class_name,const String & p_base_class_name) const84 Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
85 String _template = "extends %BASE%\n"
86 "\n"
87 "\n"
88 "# Declare member variables here. Examples:\n"
89 "# var a%INT_TYPE% = 2\n"
90 "# var b%STRING_TYPE% = \"text\"\n"
91 "\n"
92 "\n"
93 "# Called when the node enters the scene tree for the first time.\n"
94 "func _ready()%VOID_RETURN%:\n"
95 "%TS%pass # Replace with function body.\n"
96 "\n"
97 "\n"
98 "# Called every frame. 'delta' is the elapsed time since the previous frame.\n"
99 "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n"
100 "#%TS%pass\n";
101
102 _template = _get_processed_template(_template, p_base_class_name);
103
104 Ref<GDScript> script;
105 script.instance();
106 script->set_source_code(_template);
107
108 return script;
109 }
110
is_using_templates()111 bool GDScriptLanguage::is_using_templates() {
112
113 return true;
114 }
115
make_template(const String & p_class_name,const String & p_base_class_name,Ref<Script> & p_script)116 void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {
117
118 String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name);
119 p_script->set_source_code(_template);
120 }
121
validate(const String & p_script,int & r_line_error,int & r_col_error,String & r_test_error,const String & p_path,List<String> * r_functions,List<ScriptLanguage::Warning> * r_warnings,Set<int> * r_safe_lines) const122 bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
123
124 GDScriptParser parser;
125
126 Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path, false, r_safe_lines);
127 #ifdef DEBUG_ENABLED
128 if (r_warnings) {
129 for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
130 const GDScriptWarning &warn = E->get();
131 ScriptLanguage::Warning w;
132 w.line = warn.line;
133 w.code = (int)warn.code;
134 w.string_code = GDScriptWarning::get_name_from_code(warn.code);
135 w.message = warn.get_message();
136 r_warnings->push_back(w);
137 }
138 }
139 #endif
140 if (err) {
141 r_line_error = parser.get_error_line();
142 r_col_error = parser.get_error_column();
143 r_test_error = parser.get_error();
144 return false;
145 } else {
146
147 const GDScriptParser::Node *root = parser.get_parse_tree();
148 ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, false);
149
150 const GDScriptParser::ClassNode *cl = static_cast<const GDScriptParser::ClassNode *>(root);
151 Map<int, String> funcs;
152 for (int i = 0; i < cl->functions.size(); i++) {
153
154 funcs[cl->functions[i]->line] = cl->functions[i]->name;
155 }
156
157 for (int i = 0; i < cl->static_functions.size(); i++) {
158
159 funcs[cl->static_functions[i]->line] = cl->static_functions[i]->name;
160 }
161
162 for (int i = 0; i < cl->subclasses.size(); i++) {
163 for (int j = 0; j < cl->subclasses[i]->functions.size(); j++) {
164
165 funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->functions[j]->name;
166 }
167 for (int j = 0; j < cl->subclasses[i]->static_functions.size(); j++) {
168
169 funcs[cl->subclasses[i]->static_functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->static_functions[j]->name;
170 }
171 }
172
173 for (Map<int, String>::Element *E = funcs.front(); E; E = E->next()) {
174
175 r_functions->push_back(E->get() + ":" + itos(E->key()));
176 }
177 }
178
179 return true;
180 }
181
has_named_classes() const182 bool GDScriptLanguage::has_named_classes() const {
183
184 return false;
185 }
186
supports_builtin_mode() const187 bool GDScriptLanguage::supports_builtin_mode() const {
188
189 return true;
190 }
191
find_function(const String & p_function,const String & p_code) const192 int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const {
193
194 GDScriptTokenizerText tokenizer;
195 tokenizer.set_code(p_code);
196 int indent = 0;
197 while (tokenizer.get_token() != GDScriptTokenizer::TK_EOF && tokenizer.get_token() != GDScriptTokenizer::TK_ERROR) {
198
199 if (tokenizer.get_token() == GDScriptTokenizer::TK_NEWLINE) {
200 indent = tokenizer.get_token_line_indent();
201 }
202 if (indent == 0 && tokenizer.get_token() == GDScriptTokenizer::TK_PR_FUNCTION && tokenizer.get_token(1) == GDScriptTokenizer::TK_IDENTIFIER) {
203
204 String identifier = tokenizer.get_token_identifier(1);
205 if (identifier == p_function) {
206 return tokenizer.get_token_line();
207 }
208 }
209 tokenizer.advance();
210 }
211 return -1;
212 }
213
create_script() const214 Script *GDScriptLanguage::create_script() const {
215
216 return memnew(GDScript);
217 }
218
219 /* DEBUGGER FUNCTIONS */
220
debug_break_parse(const String & p_file,int p_line,const String & p_error)221 bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
222 //break because of parse error
223
224 if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) {
225
226 _debug_parse_err_line = p_line;
227 _debug_parse_err_file = p_file;
228 _debug_error = p_error;
229 ScriptDebugger::get_singleton()->debug(this, false, true);
230 return true;
231 } else {
232 return false;
233 }
234 }
235
debug_break(const String & p_error,bool p_allow_continue)236 bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) {
237
238 if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) {
239
240 _debug_parse_err_line = -1;
241 _debug_parse_err_file = "";
242 _debug_error = p_error;
243 bool is_error_breakpoint = p_error != "Breakpoint";
244 ScriptDebugger::get_singleton()->debug(this, p_allow_continue, is_error_breakpoint);
245 return true;
246 } else {
247 return false;
248 }
249 }
250
debug_get_error() const251 String GDScriptLanguage::debug_get_error() const {
252
253 return _debug_error;
254 }
255
debug_get_stack_level_count() const256 int GDScriptLanguage::debug_get_stack_level_count() const {
257
258 if (_debug_parse_err_line >= 0)
259 return 1;
260
261 return _debug_call_stack_pos;
262 }
debug_get_stack_level_line(int p_level) const263 int GDScriptLanguage::debug_get_stack_level_line(int p_level) const {
264
265 if (_debug_parse_err_line >= 0)
266 return _debug_parse_err_line;
267
268 ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, -1);
269
270 int l = _debug_call_stack_pos - p_level - 1;
271
272 return *(_call_stack[l].line);
273 }
debug_get_stack_level_function(int p_level) const274 String GDScriptLanguage::debug_get_stack_level_function(int p_level) const {
275
276 if (_debug_parse_err_line >= 0)
277 return "";
278
279 ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, "");
280 int l = _debug_call_stack_pos - p_level - 1;
281 return _call_stack[l].function->get_name();
282 }
debug_get_stack_level_source(int p_level) const283 String GDScriptLanguage::debug_get_stack_level_source(int p_level) const {
284
285 if (_debug_parse_err_line >= 0)
286 return _debug_parse_err_file;
287
288 ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, "");
289 int l = _debug_call_stack_pos - p_level - 1;
290 return _call_stack[l].function->get_source();
291 }
debug_get_stack_level_locals(int p_level,List<String> * p_locals,List<Variant> * p_values,int p_max_subitems,int p_max_depth)292 void 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) {
293
294 if (_debug_parse_err_line >= 0)
295 return;
296
297 ERR_FAIL_INDEX(p_level, _debug_call_stack_pos);
298 int l = _debug_call_stack_pos - p_level - 1;
299
300 GDScriptFunction *f = _call_stack[l].function;
301
302 List<Pair<StringName, int> > locals;
303
304 f->debug_get_stack_member_state(*_call_stack[l].line, &locals);
305 for (List<Pair<StringName, int> >::Element *E = locals.front(); E; E = E->next()) {
306
307 p_locals->push_back(E->get().first);
308 p_values->push_back(_call_stack[l].stack[E->get().second]);
309 }
310 }
debug_get_stack_level_members(int p_level,List<String> * p_members,List<Variant> * p_values,int p_max_subitems,int p_max_depth)311 void 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) {
312
313 if (_debug_parse_err_line >= 0)
314 return;
315
316 ERR_FAIL_INDEX(p_level, _debug_call_stack_pos);
317 int l = _debug_call_stack_pos - p_level - 1;
318
319 GDScriptInstance *instance = _call_stack[l].instance;
320
321 if (!instance)
322 return;
323
324 Ref<GDScript> script = instance->get_script();
325 ERR_FAIL_COND(script.is_null());
326
327 const Map<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices();
328
329 for (const Map<StringName, GDScript::MemberInfo>::Element *E = mi.front(); E; E = E->next()) {
330
331 p_members->push_back(E->key());
332 p_values->push_back(instance->debug_get_member_by_index(E->get().index));
333 }
334 }
335
debug_get_stack_level_instance(int p_level)336 ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
337
338 if (_debug_parse_err_line >= 0)
339 return NULL;
340
341 ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, NULL);
342
343 int l = _debug_call_stack_pos - p_level - 1;
344 ScriptInstance *instance = _call_stack[l].instance;
345
346 return instance;
347 }
348
debug_get_globals(List<String> * p_globals,List<Variant> * p_values,int p_max_subitems,int p_max_depth)349 void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
350
351 const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
352 const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array();
353
354 List<Pair<String, Variant> > cinfo;
355 get_public_constants(&cinfo);
356
357 for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) {
358
359 if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key()))
360 continue;
361
362 bool is_script_constant = false;
363 for (List<Pair<String, Variant> >::Element *CE = cinfo.front(); CE; CE = CE->next()) {
364 if (CE->get().first == E->key()) {
365 is_script_constant = true;
366 break;
367 }
368 }
369 if (is_script_constant)
370 continue;
371
372 const Variant &var = globals[E->value()];
373 if (Object *obj = var) {
374 if (Object::cast_to<GDScriptNativeClass>(obj))
375 continue;
376 }
377
378 bool skip = false;
379 for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
380 if (E->key() == GlobalConstants::get_global_constant_name(i)) {
381 skip = true;
382 break;
383 }
384 }
385 if (skip)
386 continue;
387
388 p_globals->push_back(E->key());
389 p_values->push_back(var);
390 }
391 }
392
debug_parse_stack_level_expression(int p_level,const String & p_expression,int p_max_subitems,int p_max_depth)393 String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
394
395 return "";
396 }
397
get_recognized_extensions(List<String> * p_extensions) const398 void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
399
400 p_extensions->push_back("gd");
401 }
402
get_public_functions(List<MethodInfo> * p_functions) const403 void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
404
405 for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
406
407 p_functions->push_back(GDScriptFunctions::get_info(GDScriptFunctions::Function(i)));
408 }
409
410 //not really "functions", but..
411 {
412 MethodInfo mi;
413 mi.name = "preload";
414 mi.arguments.push_back(PropertyInfo(Variant::STRING, "path"));
415 mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "Resource");
416 p_functions->push_back(mi);
417 }
418 {
419 MethodInfo mi;
420 mi.name = "yield";
421 mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
422 mi.arguments.push_back(PropertyInfo(Variant::STRING, "signal"));
423 mi.default_arguments.push_back(Variant());
424 mi.default_arguments.push_back(String());
425 mi.return_val = PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "GDScriptFunctionState");
426 p_functions->push_back(mi);
427 }
428 {
429 MethodInfo mi;
430 mi.name = "assert";
431 mi.return_val.type = Variant::NIL;
432 mi.arguments.push_back(PropertyInfo(Variant::BOOL, "condition"));
433 mi.arguments.push_back(PropertyInfo(Variant::STRING, "message"));
434 mi.default_arguments.push_back(String());
435 p_functions->push_back(mi);
436 }
437 }
438
get_public_constants(List<Pair<String,Variant>> * p_constants) const439 void GDScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
440
441 Pair<String, Variant> pi;
442 pi.first = "PI";
443 pi.second = Math_PI;
444 p_constants->push_back(pi);
445
446 Pair<String, Variant> tau;
447 tau.first = "TAU";
448 tau.second = Math_TAU;
449 p_constants->push_back(tau);
450
451 Pair<String, Variant> infinity;
452 infinity.first = "INF";
453 infinity.second = Math_INF;
454 p_constants->push_back(infinity);
455
456 Pair<String, Variant> nan;
457 nan.first = "NAN";
458 nan.second = Math_NAN;
459 p_constants->push_back(nan);
460 }
461
make_function(const String & p_class,const String & p_name,const PoolStringArray & p_args) const462 String GDScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const {
463
464 #ifdef TOOLS_ENABLED
465 bool th = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints");
466 #else
467 bool th = false;
468 #endif
469
470 String s = "func " + p_name + "(";
471 if (p_args.size()) {
472 for (int i = 0; i < p_args.size(); i++) {
473 if (i > 0)
474 s += ", ";
475 s += p_args[i].get_slice(":", 0);
476 if (th) {
477 String type = p_args[i].get_slice(":", 1);
478 if (!type.empty() && type != "var") {
479 s += ": " + type;
480 }
481 }
482 }
483 }
484 s += String(")") + (th ? " -> void" : "") + ":\n" + _get_indentation() + "pass # Replace with function body.\n";
485
486 return s;
487 }
488
489 //////// COMPLETION //////////
490
491 #if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
492
493 struct GDScriptCompletionContext {
494
495 const GDScriptParser::ClassNode *_class;
496 const GDScriptParser::FunctionNode *function;
497 const GDScriptParser::BlockNode *block;
498 Object *base;
499 String base_path;
500 int line;
501 uint32_t depth;
502
GDScriptCompletionContextGDScriptCompletionContext503 GDScriptCompletionContext() :
504 _class(NULL),
505 function(NULL),
506 block(NULL),
507 base(NULL),
508 line(0),
509 depth(0) {}
510 };
511
512 struct GDScriptCompletionIdentifier {
513 GDScriptParser::DataType type;
514 String enumeration;
515 Variant value;
516 const GDScriptParser::Node *assigned_expression;
517
GDScriptCompletionIdentifierGDScriptCompletionIdentifier518 GDScriptCompletionIdentifier() :
519 assigned_expression(NULL) {}
520 };
521
_get_directory_contents(EditorFileSystemDirectory * p_dir,Map<String,ScriptCodeCompletionOption> & r_list,String p_ends_with="")522 static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list, String p_ends_with = "") {
523
524 const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
525
526 for (int i = 0; i < p_dir->get_file_count(); i++) {
527 ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH);
528 option.insert_text = quote_style + option.display + quote_style;
529 if (!p_ends_with.empty()) {
530 if (option.display.ends_with(p_ends_with)) {
531 r_list.insert(option.display, option);
532 }
533 } else {
534 r_list.insert(option.display, option);
535 }
536 }
537
538 for (int i = 0; i < p_dir->get_subdir_count(); i++) {
539 _get_directory_contents(p_dir->get_subdir(i), r_list, p_ends_with);
540 }
541 }
542
_get_visual_datatype(const PropertyInfo & p_info,bool p_isarg=true)543 static String _get_visual_datatype(const PropertyInfo &p_info, bool p_isarg = true) {
544
545 if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
546 String enum_name = p_info.class_name;
547 if (enum_name.find(".") == -1) {
548 return enum_name;
549 }
550 return enum_name.get_slice(".", 1);
551 }
552
553 String n = p_info.name;
554 int idx = n.find(":");
555 if (idx != -1) {
556 return n.substr(idx + 1, n.length());
557 }
558
559 if (p_info.type == Variant::OBJECT) {
560 if (p_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
561 return p_info.hint_string;
562 } else {
563 return p_info.class_name.operator String();
564 }
565 }
566 if (p_info.type == Variant::NIL) {
567 if (p_isarg || (p_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) {
568 return "Variant";
569 } else {
570 return "void";
571 }
572 }
573
574 return Variant::get_type_name(p_info.type);
575 }
576
_type_from_variant(const Variant & p_value)577 static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value) {
578 GDScriptCompletionIdentifier ci;
579 ci.value = p_value;
580 ci.type.is_constant = true;
581 ci.type.has_type = true;
582 ci.type.kind = GDScriptParser::DataType::BUILTIN;
583 ci.type.builtin_type = p_value.get_type();
584
585 if (ci.type.builtin_type == Variant::OBJECT) {
586 Object *obj = p_value.operator Object *();
587 if (!obj) {
588 return ci;
589 }
590 ci.type.native_type = obj->get_class_name();
591 Ref<Script> scr = p_value;
592 if (scr.is_valid()) {
593 ci.type.is_meta_type = true;
594 } else {
595 ci.type.is_meta_type = false;
596 scr = obj->get_script();
597 }
598 if (scr.is_valid()) {
599 ci.type.script_type = scr;
600 Ref<GDScript> gds = scr;
601 if (gds.is_valid()) {
602 ci.type.kind = GDScriptParser::DataType::GDSCRIPT;
603 } else {
604 ci.type.kind = GDScriptParser::DataType::SCRIPT;
605 }
606 ci.type.native_type = scr->get_instance_base_type();
607 } else {
608 ci.type.kind = GDScriptParser::DataType::NATIVE;
609 }
610 }
611
612 return ci;
613 }
614
_type_from_property(const PropertyInfo & p_property)615 static GDScriptCompletionIdentifier _type_from_property(const PropertyInfo &p_property) {
616 GDScriptCompletionIdentifier ci;
617
618 if (p_property.type == Variant::NIL) {
619 // Variant
620 return ci;
621 }
622
623 if (p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
624 ci.enumeration = p_property.class_name;
625 }
626
627 ci.type.has_type = true;
628 ci.type.builtin_type = p_property.type;
629 if (p_property.type == Variant::OBJECT) {
630 ci.type.kind = GDScriptParser::DataType::NATIVE;
631 ci.type.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name;
632 } else {
633 ci.type.kind = GDScriptParser::DataType::BUILTIN;
634 }
635 return ci;
636 }
637
_type_from_gdtype(const GDScriptDataType & p_gdtype)638 static GDScriptCompletionIdentifier _type_from_gdtype(const GDScriptDataType &p_gdtype) {
639 GDScriptCompletionIdentifier ci;
640 if (!p_gdtype.has_type) {
641 return ci;
642 }
643
644 ci.type.has_type = true;
645 ci.type.builtin_type = p_gdtype.builtin_type;
646 ci.type.native_type = p_gdtype.native_type;
647 ci.type.script_type = p_gdtype.script_type;
648
649 switch (p_gdtype.kind) {
650 case GDScriptDataType::UNINITIALIZED: {
651 ERR_PRINT("Uninitialized completion. Please report a bug.");
652 } break;
653 case GDScriptDataType::BUILTIN: {
654 ci.type.kind = GDScriptParser::DataType::BUILTIN;
655 } break;
656 case GDScriptDataType::NATIVE: {
657 ci.type.kind = GDScriptParser::DataType::NATIVE;
658 } break;
659 case GDScriptDataType::GDSCRIPT: {
660 ci.type.kind = GDScriptParser::DataType::GDSCRIPT;
661 } break;
662 case GDScriptDataType::SCRIPT: {
663 ci.type.kind = GDScriptParser::DataType::SCRIPT;
664 } break;
665 }
666 return ci;
667 }
668
669 static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type);
670 static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type);
671 static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type);
672
_guess_expression_type(GDScriptCompletionContext & p_context,const GDScriptParser::Node * p_expression,GDScriptCompletionIdentifier & r_type)673 static bool _guess_expression_type(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_expression, GDScriptCompletionIdentifier &r_type) {
674 bool found = false;
675
676 if (++p_context.depth > 100) {
677 print_error("Maximum _guess_expression_type depth limit reached. Please file a bugreport.");
678 return false;
679 }
680
681 switch (p_expression->type) {
682 case GDScriptParser::Node::TYPE_CONSTANT: {
683 const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(p_expression);
684 r_type = _type_from_variant(cn->value);
685 found = true;
686 } break;
687 case GDScriptParser::Node::TYPE_SELF: {
688 if (p_context._class) {
689 r_type.type.has_type = true;
690 r_type.type.kind = GDScriptParser::DataType::CLASS;
691 r_type.type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class);
692 r_type.type.is_constant = true;
693 r_type.value = p_context.base;
694 found = true;
695 }
696 } break;
697 case GDScriptParser::Node::TYPE_IDENTIFIER: {
698 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression);
699 found = _guess_identifier_type(p_context, id->name, r_type);
700 } break;
701 case GDScriptParser::Node::TYPE_DICTIONARY: {
702 // Try to recreate the dictionary
703 const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(p_expression);
704 Dictionary d;
705 bool full = true;
706 for (int i = 0; i < dn->elements.size(); i++) {
707 GDScriptCompletionIdentifier key;
708 if (_guess_expression_type(p_context, dn->elements[i].key, key)) {
709 GDScriptCompletionIdentifier value;
710 if (_guess_expression_type(p_context, dn->elements[i].value, value)) {
711 if (!value.type.is_constant) {
712 full = false;
713 break;
714 }
715 d[key.value] = value.value;
716 } else {
717 full = false;
718 break;
719 }
720 } else {
721 full = false;
722 break;
723 }
724 }
725 if (full) {
726 // If not fully constant, setting this value is detrimental to the inference
727 r_type.value = d;
728 r_type.type.is_constant = true;
729 }
730 r_type.type.has_type = true;
731 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
732 r_type.type.builtin_type = Variant::DICTIONARY;
733 } break;
734 case GDScriptParser::Node::TYPE_ARRAY: {
735 // Try to recreate the array
736 const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_expression);
737 Array a;
738 bool full = true;
739 a.resize(an->elements.size());
740 for (int i = 0; i < an->elements.size(); i++) {
741 GDScriptCompletionIdentifier value;
742 if (_guess_expression_type(p_context, an->elements[i], value)) {
743 a[i] = value.value;
744 } else {
745 full = false;
746 break;
747 }
748 }
749 if (full) {
750 // If not fully constant, setting this value is detrimental to the inference
751 r_type.value = a;
752 }
753 r_type.type.has_type = true;
754 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
755 r_type.type.builtin_type = Variant::ARRAY;
756 } break;
757 case GDScriptParser::Node::TYPE_CAST: {
758 const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
759 GDScriptCompletionIdentifier value;
760 if (_guess_expression_type(p_context, cn->source_node, r_type)) {
761 r_type.type = cn->get_datatype();
762 found = true;
763 }
764 } break;
765 case GDScriptParser::Node::TYPE_OPERATOR: {
766 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_expression);
767 switch (op->op) {
768 case GDScriptParser::OperatorNode::OP_CALL: {
769 if (op->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) {
770 const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(op->arguments[0]);
771 r_type.type.has_type = true;
772 r_type.type.kind = GDScriptParser::DataType::BUILTIN;
773 r_type.type.builtin_type = tn->vtype;
774 found = true;
775 break;
776 } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) {
777 const GDScriptParser::BuiltInFunctionNode *bin = static_cast<const GDScriptParser::BuiltInFunctionNode *>(op->arguments[0]);
778 MethodInfo mi = GDScriptFunctions::get_info(bin->function);
779 r_type = _type_from_property(mi.return_val);
780 found = true;
781 break;
782 } else if (op->arguments.size() >= 2 && op->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) {
783 StringName id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1])->name;
784
785 GDScriptCompletionContext c = p_context;
786 c.line = op->line;
787
788 GDScriptCompletionIdentifier base;
789 if (!_guess_expression_type(c, op->arguments[0], base)) {
790 found = false;
791 break;
792 }
793
794 // Try call if constant methods with constant arguments
795 if (base.type.is_constant && base.value.get_type() == Variant::OBJECT) {
796 GDScriptParser::DataType native_type = base.type;
797
798 while (native_type.kind == GDScriptParser::DataType::CLASS) {
799 native_type = native_type.class_type->base_type;
800 }
801
802 while (native_type.kind == GDScriptParser::DataType::GDSCRIPT || native_type.kind == GDScriptParser::DataType::SCRIPT) {
803 if (native_type.script_type.is_valid()) {
804 Ref<Script> parent = native_type.script_type->get_base_script();
805 if (parent.is_valid()) {
806 native_type.script_type = parent;
807 } else {
808 native_type.kind = GDScriptParser::DataType::NATIVE;
809 native_type.native_type = native_type.script_type->get_instance_base_type();
810 if (!ClassDB::class_exists(native_type.native_type)) {
811 native_type.native_type = String("_") + native_type.native_type;
812 if (!ClassDB::class_exists(native_type.native_type)) {
813 native_type.has_type = false;
814 }
815 }
816 }
817 }
818 }
819
820 if (native_type.has_type && native_type.kind == GDScriptParser::DataType::NATIVE) {
821 MethodBind *mb = ClassDB::get_method(native_type.native_type, id);
822 if (mb && mb->is_const()) {
823 bool all_is_const = true;
824 Vector<Variant> args;
825 GDScriptCompletionContext c2 = p_context;
826 c2.line = op->line;
827 for (int i = 2; all_is_const && i < op->arguments.size(); i++) {
828 GDScriptCompletionIdentifier arg;
829
830 if (_guess_expression_type(c2, op->arguments[i], arg)) {
831 if (arg.type.has_type && arg.type.is_constant && arg.value.get_type() != Variant::OBJECT) {
832 args.push_back(arg.value);
833 } else {
834 all_is_const = false;
835 }
836 } else {
837 all_is_const = false;
838 }
839 }
840
841 Object *baseptr = base.value;
842
843 if (all_is_const && String(id) == "get_node" && ClassDB::is_parent_class(native_type.native_type, "Node") && args.size()) {
844
845 String arg1 = args[0];
846 if (arg1.begins_with("/root/")) {
847 String which = arg1.get_slice("/", 2);
848 if (which != "") {
849 // Try singletons first
850 if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(which)) {
851 r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]);
852 found = true;
853 } else {
854 List<PropertyInfo> props;
855 ProjectSettings::get_singleton()->get_property_list(&props);
856
857 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
858
859 String s = E->get().name;
860 if (!s.begins_with("autoload/")) {
861 continue;
862 }
863 String name = s.get_slice("/", 1);
864 if (name == which) {
865 String script = ProjectSettings::get_singleton()->get(s);
866
867 if (script.begins_with("*")) {
868 script = script.right(1);
869 }
870
871 if (!script.begins_with("res://")) {
872 script = "res://" + script;
873 }
874
875 if (!script.ends_with(".gd")) {
876 //not a script, try find the script anyway,
877 //may have some success
878 script = script.get_basename() + ".gd";
879 }
880
881 if (FileAccess::exists(script)) {
882 Ref<Script> scr;
883 if (ScriptCodeCompletionCache::get_singleton()) {
884 scr = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(script);
885 } else {
886 scr = ResourceLoader::load(script);
887 }
888 if (scr.is_valid()) {
889 r_type.type.has_type = true;
890 r_type.type.script_type = scr;
891 r_type.type.is_constant = false;
892 Ref<GDScript> gds = scr;
893 if (gds.is_valid()) {
894 r_type.type.kind = GDScriptParser::DataType::GDSCRIPT;
895 } else {
896 r_type.type.kind = GDScriptParser::DataType::SCRIPT;
897 }
898 r_type.value = Variant();
899 found = true;
900 }
901 }
902 break;
903 }
904 }
905 }
906 }
907 }
908 }
909
910 if (!found && all_is_const && baseptr) {
911 Vector<const Variant *> argptr;
912 for (int i = 0; i < args.size(); i++) {
913 argptr.push_back(&args[i]);
914 }
915
916 Variant::CallError ce;
917 Variant ret = mb->call(baseptr, (const Variant **)argptr.ptr(), argptr.size(), ce);
918
919 if (ce.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
920 if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != NULL) {
921 r_type = _type_from_variant(ret);
922 found = true;
923 }
924 }
925 }
926 }
927 }
928 }
929
930 if (!found) {
931 found = _guess_method_return_type_from_base(c, base, id, r_type);
932 }
933 }
934 } break;
935 case GDScriptParser::OperatorNode::OP_PARENT_CALL: {
936 if (!p_context._class || !op->arguments.size() || op->arguments[0]->type != GDScriptParser::Node::TYPE_IDENTIFIER) {
937 break;
938 }
939
940 StringName id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name;
941
942 GDScriptCompletionIdentifier base;
943 base.value = p_context.base;
944 base.type = p_context._class->base_type;
945
946 GDScriptCompletionContext c = p_context;
947 c.line = op->line;
948
949 found = _guess_method_return_type_from_base(c, base, id, r_type);
950 } break;
951 case GDScriptParser::OperatorNode::OP_INDEX_NAMED: {
952 if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) {
953 found = false;
954 break;
955 }
956 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]);
957
958 GDScriptCompletionContext c = p_context;
959 c.line = op->line;
960
961 GDScriptCompletionIdentifier base;
962 if (!_guess_expression_type(c, op->arguments[0], base)) {
963 found = false;
964 break;
965 }
966
967 if (base.value.get_type() == Variant::DICTIONARY && base.value.operator Dictionary().has(String(id->name))) {
968 Variant value = base.value.operator Dictionary()[String(id->name)];
969 r_type = _type_from_variant(value);
970 found = true;
971 break;
972 }
973
974 const GDScriptParser::DictionaryNode *dn = NULL;
975 if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) {
976 dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]);
977 } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) {
978 dn = static_cast<const GDScriptParser::DictionaryNode *>(base.assigned_expression);
979 }
980
981 if (dn) {
982 for (int i = 0; i < dn->elements.size(); i++) {
983 GDScriptCompletionIdentifier key;
984 if (!_guess_expression_type(c, dn->elements[i].key, key)) {
985 continue;
986 }
987 if (key.value == String(id->name)) {
988 r_type.assigned_expression = dn->elements[i].value;
989 found = _guess_expression_type(c, dn->elements[i].value, r_type);
990 break;
991 }
992 }
993 }
994
995 if (!found) {
996 found = _guess_identifier_type_from_base(c, base, id->name, r_type);
997 }
998 } break;
999 case GDScriptParser::OperatorNode::OP_INDEX: {
1000 if (op->arguments.size() < 2) {
1001 found = false;
1002 break;
1003 }
1004
1005 GDScriptCompletionContext c = p_context;
1006 c.line = op->line;
1007
1008 GDScriptCompletionIdentifier base;
1009 if (!_guess_expression_type(c, op->arguments[0], base)) {
1010 found = false;
1011 break;
1012 }
1013
1014 GDScriptCompletionIdentifier index;
1015 if (!_guess_expression_type(c, op->arguments[1], index)) {
1016 found = false;
1017 break;
1018 }
1019
1020 if (base.value.in(index.value)) {
1021 Variant value = base.value.get(index.value);
1022 r_type = _type_from_variant(value);
1023 found = true;
1024 break;
1025 }
1026
1027 // Look if it is a dictionary node
1028 const GDScriptParser::DictionaryNode *dn = NULL;
1029 if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) {
1030 dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]);
1031 } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) {
1032 dn = static_cast<const GDScriptParser::DictionaryNode *>(base.assigned_expression);
1033 }
1034
1035 if (dn) {
1036 for (int i = 0; i < dn->elements.size(); i++) {
1037 GDScriptCompletionIdentifier key;
1038 if (!_guess_expression_type(c, dn->elements[i].key, key)) {
1039 continue;
1040 }
1041 if (key.value == index.value) {
1042 r_type.assigned_expression = dn->elements[i].value;
1043 found = _guess_expression_type(p_context, dn->elements[i].value, r_type);
1044 break;
1045 }
1046 }
1047 }
1048
1049 // Look if it is an array node
1050 if (!found && index.value.is_num()) {
1051 int idx = index.value;
1052 const GDScriptParser::ArrayNode *an = NULL;
1053 if (op->arguments[0]->type == GDScriptParser::Node::TYPE_ARRAY) {
1054 an = static_cast<const GDScriptParser::ArrayNode *>(op->arguments[0]);
1055 } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_ARRAY) {
1056 an = static_cast<const GDScriptParser::ArrayNode *>(base.assigned_expression);
1057 }
1058
1059 if (an && idx >= 0 && an->elements.size() > idx) {
1060 r_type.assigned_expression = an->elements[idx];
1061 found = _guess_expression_type(c, an->elements[idx], r_type);
1062 break;
1063 }
1064 }
1065
1066 // Look for valid indexing in other types
1067 if (!found && (index.value.get_type() == Variant::STRING || index.value.get_type() == Variant::NODE_PATH)) {
1068 StringName id = index.value;
1069 found = _guess_identifier_type_from_base(c, base, id, r_type);
1070 } else if (!found && index.type.kind == GDScriptParser::DataType::BUILTIN) {
1071 Variant::CallError err;
1072 Variant base_val = Variant::construct(base.type.builtin_type, NULL, 0, err);
1073 bool valid = false;
1074 Variant res = base_val.get(index.value, &valid);
1075 if (valid) {
1076 r_type = _type_from_variant(res);
1077 r_type.value = Variant();
1078 r_type.type.is_constant = false;
1079 found = true;
1080 }
1081 }
1082 } break;
1083 default: {
1084 if (op->arguments.size() < 2) {
1085 found = false;
1086 break;
1087 }
1088
1089 Variant::Operator vop = Variant::OP_MAX;
1090 switch (op->op) {
1091 case GDScriptParser::OperatorNode::OP_ADD: vop = Variant::OP_ADD; break;
1092 case GDScriptParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBTRACT; break;
1093 case GDScriptParser::OperatorNode::OP_MUL: vop = Variant::OP_MULTIPLY; break;
1094 case GDScriptParser::OperatorNode::OP_DIV: vop = Variant::OP_DIVIDE; break;
1095 case GDScriptParser::OperatorNode::OP_MOD: vop = Variant::OP_MODULE; break;
1096 case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: vop = Variant::OP_SHIFT_LEFT; break;
1097 case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: vop = Variant::OP_SHIFT_RIGHT; break;
1098 case GDScriptParser::OperatorNode::OP_BIT_AND: vop = Variant::OP_BIT_AND; break;
1099 case GDScriptParser::OperatorNode::OP_BIT_OR: vop = Variant::OP_BIT_OR; break;
1100 case GDScriptParser::OperatorNode::OP_BIT_XOR: vop = Variant::OP_BIT_XOR; break;
1101 default: {
1102 }
1103 }
1104
1105 if (vop == Variant::OP_MAX) {
1106 break;
1107 }
1108
1109 GDScriptCompletionContext context = p_context;
1110 context.line = op->line;
1111
1112 GDScriptCompletionIdentifier p1;
1113 GDScriptCompletionIdentifier p2;
1114
1115 if (!_guess_expression_type(context, op->arguments[0], p1)) {
1116 found = false;
1117 break;
1118 }
1119
1120 if (!_guess_expression_type(context, op->arguments[1], p2)) {
1121 found = false;
1122 break;
1123 }
1124
1125 Variant::CallError ce;
1126 bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT;
1127 Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, NULL, 0, ce);
1128 bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT;
1129 Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, NULL, 0, ce);
1130 // avoid potential invalid ops
1131 if ((vop == Variant::OP_DIVIDE || vop == Variant::OP_MODULE) && v2.get_type() == Variant::INT) {
1132 v2 = 1;
1133 v2_use_value = false;
1134 }
1135 if (vop == Variant::OP_DIVIDE && v2.get_type() == Variant::REAL) {
1136 v2 = 1.0;
1137 v2_use_value = false;
1138 }
1139
1140 Variant res;
1141 bool valid;
1142 Variant::evaluate(vop, v1, v2, res, valid);
1143 if (!valid) {
1144 found = false;
1145 break;
1146 }
1147 r_type = _type_from_variant(res);
1148 if (!v1_use_value || !v2_use_value) {
1149 r_type.value = Variant();
1150 r_type.type.is_constant = false;
1151 }
1152
1153 found = true;
1154 } break;
1155 }
1156 } break;
1157 default: {
1158 }
1159 }
1160
1161 // It may have found a null, but that's never useful
1162 if (found && r_type.type.has_type && r_type.type.kind == GDScriptParser::DataType::BUILTIN && r_type.type.builtin_type == Variant::NIL) {
1163 found = false;
1164 }
1165
1166 // Check type hint last. For collections we want chance to get the actual value first
1167 // This way we can detect types from the content of dictionaries and arrays
1168 if (!found && p_expression->get_datatype().has_type) {
1169 r_type.type = p_expression->get_datatype();
1170 if (!r_type.assigned_expression) {
1171 r_type.assigned_expression = p_expression;
1172 }
1173 found = true;
1174 }
1175
1176 return found;
1177 }
1178
_guess_identifier_type(GDScriptCompletionContext & p_context,const StringName & p_identifier,GDScriptCompletionIdentifier & r_type)1179 static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) {
1180
1181 // Look in blocks first
1182 const GDScriptParser::BlockNode *blk = p_context.block;
1183 int last_assign_line = -1;
1184 const GDScriptParser::Node *last_assigned_expression = NULL;
1185 GDScriptParser::DataType var_type;
1186 while (blk) {
1187 if (blk->variables.has(p_identifier)) {
1188 if (blk->variables[p_identifier]->line > p_context.line) {
1189 return false;
1190 }
1191
1192 var_type = blk->variables[p_identifier]->datatype;
1193
1194 if (!last_assigned_expression && blk->variables[p_identifier]->assign && blk->variables[p_identifier]->assign->type == GDScriptParser::Node::TYPE_OPERATOR) {
1195 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(blk->variables[p_identifier]->assign);
1196 if (op->op == GDScriptParser::OperatorNode::OP_ASSIGN && op->arguments.size() >= 2) {
1197 last_assign_line = op->line;
1198 last_assigned_expression = op->arguments[1];
1199 }
1200 }
1201 }
1202
1203 for (const List<GDScriptParser::Node *>::Element *E = blk->statements.front(); E; E = E->next()) {
1204 const GDScriptParser::Node *expr = E->get();
1205 if (expr->line > p_context.line || expr->type != GDScriptParser::Node::TYPE_OPERATOR) {
1206 continue;
1207 }
1208
1209 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(expr);
1210 if (op->op != GDScriptParser::OperatorNode::OP_ASSIGN || op->line < last_assign_line) {
1211 continue;
1212 }
1213
1214 if (op->arguments.size() >= 2 && op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER) {
1215 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0]);
1216 if (id->name == p_identifier) {
1217 last_assign_line = op->line;
1218 last_assigned_expression = op->arguments[1];
1219 }
1220 }
1221 }
1222
1223 if (blk->if_condition && blk->if_condition->type == GDScriptParser::Node::TYPE_OPERATOR && static_cast<const GDScriptParser::OperatorNode *>(blk->if_condition)->op == GDScriptParser::OperatorNode::OP_IS) {
1224 //is used, check if identifier is in there! this helps resolve in blocks that are (if (identifier is value)): which are very common..
1225 //super dirty hack, but very useful
1226 //credit: Zylann
1227 //TODO: this could be hacked to detect ANDed conditions too..
1228 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(blk->if_condition);
1229 if (op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name == p_identifier) {
1230 //bingo
1231 GDScriptCompletionContext c = p_context;
1232 c.line = op->line;
1233 c.block = blk;
1234 if (_guess_expression_type(p_context, op->arguments[1], r_type)) {
1235 r_type.type.is_meta_type = false; // Right-hand of `is` will be a meta type, but the left-hand value is not
1236 // Not an assignment, it shouldn't carry any value
1237 r_type.value = Variant();
1238 r_type.assigned_expression = NULL;
1239
1240 return true;
1241 }
1242 }
1243 }
1244
1245 blk = blk->parent_block;
1246 }
1247
1248 if (last_assigned_expression && last_assign_line != p_context.line) {
1249 GDScriptCompletionContext c = p_context;
1250 c.line = last_assign_line;
1251 r_type.assigned_expression = last_assigned_expression;
1252 if (_guess_expression_type(c, last_assigned_expression, r_type)) {
1253 if (var_type.has_type) {
1254 r_type.type = var_type;
1255 }
1256 return true;
1257 }
1258 }
1259
1260 if (var_type.has_type) {
1261 r_type.type = var_type;
1262 return true;
1263 }
1264
1265 if (p_context.function) {
1266 for (int i = 0; i < p_context.function->arguments.size(); i++) {
1267 if (p_context.function->arguments[i] == p_identifier) {
1268 if (p_context.function->argument_types[i].has_type) {
1269 r_type.type = p_context.function->argument_types[i];
1270 return true;
1271 }
1272
1273 int def_from = p_context.function->arguments.size() - p_context.function->default_values.size();
1274 if (i >= def_from) {
1275 int def_idx = i - def_from;
1276 if (p_context.function->default_values[def_idx]->type == GDScriptParser::Node::TYPE_OPERATOR) {
1277 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_context.function->default_values[def_idx]);
1278 if (op->arguments.size() < 2) {
1279 return false;
1280 }
1281 GDScriptCompletionContext c = p_context;
1282 c.function = NULL;
1283 c.block = NULL;
1284 return _guess_expression_type(c, op->arguments[1], r_type);
1285 }
1286 }
1287 break;
1288 }
1289 }
1290
1291 GDScriptParser::DataType base_type = p_context._class->base_type;
1292 while (base_type.has_type) {
1293 switch (base_type.kind) {
1294 case GDScriptParser::DataType::GDSCRIPT: {
1295 Ref<GDScript> gds = base_type.script_type;
1296 if (gds.is_valid() && gds->has_method(p_context.function->name)) {
1297 GDScriptFunction *func = gds->get_member_functions()[p_context.function->name];
1298 if (func) {
1299 for (int i = 0; i < func->get_argument_count(); i++) {
1300 if (func->get_argument_name(i) == p_identifier) {
1301 r_type = _type_from_gdtype(func->get_argument_type(i));
1302 return true;
1303 }
1304 }
1305 }
1306 Ref<GDScript> base_gds = gds->get_base_script();
1307 if (base_gds.is_valid()) {
1308 base_type.kind = GDScriptParser::DataType::GDSCRIPT;
1309 base_type.script_type = base_gds;
1310 } else {
1311 base_type.kind = GDScriptParser::DataType::NATIVE;
1312 base_type.native_type = gds->get_instance_base_type();
1313 }
1314 } else {
1315 base_type.kind = GDScriptParser::DataType::NATIVE;
1316 base_type.native_type = gds->get_instance_base_type();
1317 }
1318 } break;
1319 case GDScriptParser::DataType::NATIVE: {
1320 List<MethodInfo> methods;
1321 ClassDB::get_method_list(base_type.native_type, &methods);
1322 ClassDB::get_virtual_methods(base_type.native_type, &methods);
1323
1324 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
1325 if (E->get().name == p_context.function->name) {
1326 MethodInfo &mi = E->get();
1327 for (List<PropertyInfo>::Element *F = mi.arguments.front(); F; F = F->next()) {
1328 if (F->get().name == p_identifier) {
1329 r_type = _type_from_property(F->get());
1330 return true;
1331 }
1332 }
1333 }
1334 }
1335 base_type.has_type = false;
1336 } break;
1337 default: {
1338 base_type.has_type = false;
1339 } break;
1340 }
1341 }
1342 }
1343
1344 // Check current class (including inheritance)
1345 if (p_context._class) {
1346 GDScriptCompletionIdentifier context_base;
1347 context_base.value = p_context.base;
1348 context_base.type.has_type = true;
1349 context_base.type.kind = GDScriptParser::DataType::CLASS;
1350 context_base.type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class);
1351 context_base.type.is_meta_type = p_context.function && p_context.function->_static;
1352
1353 if (_guess_identifier_type_from_base(p_context, context_base, p_identifier, r_type)) {
1354 return true;
1355 }
1356 }
1357
1358 // Check named scripts
1359 if (ScriptServer::is_global_class(p_identifier)) {
1360 Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_identifier));
1361 if (scr.is_valid()) {
1362 r_type = _type_from_variant(scr);
1363 r_type.type.is_meta_type = true;
1364 return true;
1365 }
1366 return false;
1367 }
1368
1369 for (int i = 0; i < 2; i++) {
1370 StringName target_id;
1371 switch (i) {
1372 case 0:
1373 // Check ClassDB
1374 target_id = p_identifier;
1375 break;
1376 case 1:
1377 // ClassDB again for underscore-prefixed classes
1378 target_id = String("_") + p_identifier;
1379 break;
1380 }
1381
1382 if (ClassDB::class_exists(target_id)) {
1383 r_type.type.has_type = true;
1384 r_type.type.kind = GDScriptParser::DataType::NATIVE;
1385 r_type.type.native_type = target_id;
1386 if (Engine::get_singleton()->has_singleton(target_id)) {
1387 r_type.type.is_meta_type = false;
1388 r_type.value = Engine::get_singleton()->get_singleton_object(target_id);
1389 } else {
1390 r_type.type.is_meta_type = true;
1391 const Map<StringName, int>::Element *target_elem = GDScriptLanguage::get_singleton()->get_global_map().find(target_id);
1392 // Check because classes like EditorNode are in ClassDB by now, but unknown to GDScript
1393 if (!target_elem) {
1394 return false;
1395 }
1396 int idx = target_elem->get();
1397 r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx];
1398 }
1399 return true;
1400 }
1401 }
1402
1403 // Check autoload singletons
1404 if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(p_identifier)) {
1405 r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[p_identifier]);
1406 return true;
1407 }
1408
1409 return false;
1410 }
1411
_guess_identifier_type_from_base(GDScriptCompletionContext & p_context,const GDScriptCompletionIdentifier & p_base,const StringName & p_identifier,GDScriptCompletionIdentifier & r_type)1412 static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) {
1413 GDScriptParser::DataType base_type = p_base.type;
1414 bool _static = base_type.is_meta_type;
1415 while (base_type.has_type) {
1416 switch (base_type.kind) {
1417 case GDScriptParser::DataType::CLASS: {
1418 if (base_type.class_type->constant_expressions.has(p_identifier)) {
1419 GDScriptParser::ClassNode::Constant c = base_type.class_type->constant_expressions[p_identifier];
1420 r_type.type = c.type;
1421 if (c.expression->type == GDScriptParser::Node::TYPE_CONSTANT) {
1422 r_type.value = static_cast<const GDScriptParser::ConstantNode *>(c.expression)->value;
1423 }
1424 return true;
1425 }
1426
1427 if (!_static) {
1428 for (int i = 0; i < base_type.class_type->variables.size(); i++) {
1429 GDScriptParser::ClassNode::Member m = base_type.class_type->variables[i];
1430 if (m.identifier == p_identifier) {
1431 if (m.expression) {
1432 if (p_context.line == m.expression->line) {
1433 // Variable used in the same expression
1434 return false;
1435 }
1436 if (_guess_expression_type(p_context, m.expression, r_type)) {
1437 return true;
1438 }
1439 if (m.expression->get_datatype().has_type) {
1440 r_type.type = m.expression->get_datatype();
1441 return true;
1442 }
1443 }
1444 if (m.data_type.has_type) {
1445 r_type.type = m.data_type;
1446 return true;
1447 }
1448 return false;
1449 }
1450 }
1451 }
1452 base_type = base_type.class_type->base_type;
1453 } break;
1454 case GDScriptParser::DataType::GDSCRIPT: {
1455 Ref<GDScript> gds = base_type.script_type;
1456 if (gds.is_valid()) {
1457 if (gds->get_constants().has(p_identifier)) {
1458 r_type = _type_from_variant(gds->get_constants()[p_identifier]);
1459 return true;
1460 }
1461 if (!_static) {
1462 const Set<StringName>::Element *m = gds->get_members().find(p_identifier);
1463 if (m) {
1464 r_type = _type_from_gdtype(gds->get_member_type(p_identifier));
1465 return true;
1466 }
1467 }
1468 Ref<GDScript> parent = gds->get_base_script();
1469 if (parent.is_valid()) {
1470 base_type.script_type = parent;
1471 } else {
1472 base_type.kind = GDScriptParser::DataType::NATIVE;
1473 base_type.native_type = gds->get_instance_base_type();
1474 }
1475 } else {
1476 return false;
1477 }
1478 } break;
1479 case GDScriptParser::DataType::SCRIPT: {
1480 Ref<Script> scr = base_type.script_type;
1481 if (scr.is_valid()) {
1482 Map<StringName, Variant> constants;
1483 scr->get_constants(&constants);
1484 if (constants.has(p_identifier)) {
1485 r_type = _type_from_variant(constants[p_identifier]);
1486 return true;
1487 }
1488
1489 if (!_static) {
1490 List<PropertyInfo> members;
1491 scr->get_script_property_list(&members);
1492 for (const List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
1493 const PropertyInfo &prop = E->get();
1494 if (prop.name == p_identifier) {
1495 r_type = _type_from_property(prop);
1496 return true;
1497 }
1498 }
1499 }
1500 Ref<Script> parent = scr->get_base_script();
1501 if (parent.is_valid()) {
1502 base_type.script_type = parent;
1503 } else {
1504 base_type.kind = GDScriptParser::DataType::NATIVE;
1505 base_type.native_type = scr->get_instance_base_type();
1506 }
1507 } else {
1508 return false;
1509 }
1510 } break;
1511 case GDScriptParser::DataType::NATIVE: {
1512 StringName class_name = base_type.native_type;
1513 if (!ClassDB::class_exists(class_name)) {
1514 class_name = String("_") + class_name;
1515 if (!ClassDB::class_exists(class_name)) {
1516 return false;
1517 }
1518 }
1519
1520 // Skip constants since they're all integers. Type does not matter because int has no members
1521
1522 List<PropertyInfo> props;
1523 ClassDB::get_property_list(class_name, &props);
1524 for (const List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
1525 const PropertyInfo &prop = E->get();
1526 if (prop.name == p_identifier) {
1527 StringName getter = ClassDB::get_property_getter(class_name, p_identifier);
1528 if (getter != StringName()) {
1529 MethodBind *g = ClassDB::get_method(class_name, getter);
1530 if (g) {
1531 r_type = _type_from_property(g->get_return_info());
1532 return true;
1533 }
1534 } else {
1535 r_type = _type_from_property(prop);
1536 return true;
1537 }
1538 break;
1539 }
1540 }
1541 return false;
1542 } break;
1543 case GDScriptParser::DataType::BUILTIN: {
1544 Variant::CallError err;
1545 Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
1546
1547 if (err.error != Variant::CallError::CALL_OK) {
1548 return false;
1549 }
1550 bool valid = false;
1551 Variant res = tmp.get(p_identifier, &valid);
1552 if (valid) {
1553 r_type = _type_from_variant(res);
1554 r_type.value = Variant();
1555 r_type.type.is_constant = false;
1556 return true;
1557 }
1558 return false;
1559 } break;
1560 default: {
1561 return false;
1562 } break;
1563 }
1564 }
1565
1566 return false;
1567 }
1568
_find_last_return_in_block(const GDScriptCompletionContext & p_context,int & r_last_return_line,const GDScriptParser::Node ** r_last_returned_value)1569 static bool _find_last_return_in_block(const GDScriptCompletionContext &p_context, int &r_last_return_line, const GDScriptParser::Node **r_last_returned_value) {
1570 if (!p_context.block) {
1571 return false;
1572 }
1573
1574 for (int i = 0; i < p_context.block->statements.size(); i++) {
1575 if (p_context.block->statements[i]->line < r_last_return_line) {
1576 continue;
1577 }
1578 if (p_context.block->statements[i]->type != GDScriptParser::Node::TYPE_CONTROL_FLOW) {
1579 continue;
1580 }
1581
1582 const GDScriptParser::ControlFlowNode *cf = static_cast<const GDScriptParser::ControlFlowNode *>(p_context.block->statements[i]);
1583 if (cf->cf_type == GDScriptParser::ControlFlowNode::CF_RETURN && cf->arguments.size() > 0) {
1584 if (cf->line > r_last_return_line) {
1585 r_last_return_line = cf->line;
1586 *r_last_returned_value = cf->arguments[0];
1587 }
1588 }
1589 }
1590
1591 // Recurse into subblocks
1592 for (int i = 0; i < p_context.block->sub_blocks.size(); i++) {
1593 GDScriptCompletionContext c = p_context;
1594 c.block = p_context.block->sub_blocks[i];
1595 _find_last_return_in_block(c, r_last_return_line, r_last_returned_value);
1596 }
1597
1598 return false;
1599 }
1600
_guess_method_return_type_from_base(GDScriptCompletionContext & p_context,const GDScriptCompletionIdentifier & p_base,const StringName & p_method,GDScriptCompletionIdentifier & r_type)1601 static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) {
1602 GDScriptParser::DataType base_type = p_base.type;
1603 bool _static = base_type.is_meta_type;
1604
1605 if (_static && p_method == "new") {
1606 r_type.type = base_type;
1607 r_type.type.is_meta_type = false;
1608 r_type.type.is_constant = false;
1609 return true;
1610 }
1611
1612 while (base_type.has_type) {
1613 switch (base_type.kind) {
1614 case GDScriptParser::DataType::CLASS: {
1615 if (!base_type.class_type) {
1616 base_type.has_type = false;
1617 break;
1618 }
1619
1620 for (int i = 0; i < base_type.class_type->static_functions.size(); i++) {
1621 if (base_type.class_type->static_functions[i]->name == p_method) {
1622 int last_return_line = -1;
1623 const GDScriptParser::Node *last_returned_value = NULL;
1624 GDScriptCompletionContext c = p_context;
1625 c._class = base_type.class_type;
1626 c.function = base_type.class_type->static_functions[i];
1627 c.block = c.function->body;
1628
1629 _find_last_return_in_block(c, last_return_line, &last_returned_value);
1630 if (last_returned_value) {
1631 c.line = c.block->end_line;
1632 return _guess_expression_type(c, last_returned_value, r_type);
1633 }
1634 }
1635 }
1636 if (!_static) {
1637 for (int i = 0; i < base_type.class_type->functions.size(); i++) {
1638 if (base_type.class_type->functions[i]->name == p_method) {
1639 int last_return_line = -1;
1640 const GDScriptParser::Node *last_returned_value = NULL;
1641 GDScriptCompletionContext c = p_context;
1642 c._class = base_type.class_type;
1643 c.function = base_type.class_type->functions[i];
1644 c.block = c.function->body;
1645
1646 _find_last_return_in_block(c, last_return_line, &last_returned_value);
1647 if (last_returned_value) {
1648 c.line = c.block->end_line;
1649 return _guess_expression_type(c, last_returned_value, r_type);
1650 }
1651 }
1652 }
1653 }
1654
1655 base_type = base_type.class_type->base_type;
1656 } break;
1657 case GDScriptParser::DataType::GDSCRIPT: {
1658 Ref<GDScript> gds = base_type.script_type;
1659 if (gds.is_valid()) {
1660 if (gds->get_member_functions().has(p_method)) {
1661 r_type = _type_from_gdtype(gds->get_member_functions()[p_method]->get_return_type());
1662 return true;
1663 }
1664 Ref<GDScript> base_script = gds->get_base_script();
1665 if (base_script.is_valid()) {
1666 base_type.script_type = base_script;
1667 } else {
1668 base_type.kind = GDScriptParser::DataType::NATIVE;
1669 base_type.native_type = gds->get_instance_base_type();
1670 }
1671 } else {
1672 return false;
1673 }
1674 } break;
1675 case GDScriptParser::DataType::SCRIPT: {
1676 Ref<Script> scr = base_type.script_type;
1677 if (scr.is_valid()) {
1678 List<MethodInfo> methods;
1679 scr->get_script_method_list(&methods);
1680 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
1681 MethodInfo &mi = E->get();
1682 if (mi.name == p_method) {
1683 r_type = _type_from_property(mi.return_val);
1684 return true;
1685 }
1686 }
1687 Ref<Script> base_script = scr->get_base_script();
1688 if (base_script.is_valid()) {
1689 base_type.script_type = base_script;
1690 } else {
1691 base_type.kind = GDScriptParser::DataType::NATIVE;
1692 base_type.native_type = scr->get_instance_base_type();
1693 }
1694 } else {
1695 return false;
1696 }
1697 } break;
1698 case GDScriptParser::DataType::NATIVE: {
1699 StringName native = base_type.native_type;
1700 if (!ClassDB::class_exists(native)) {
1701 native = String("_") + native;
1702 if (!ClassDB::class_exists(native)) {
1703 return false;
1704 }
1705 }
1706 MethodBind *mb = ClassDB::get_method(native, p_method);
1707 if (mb) {
1708 r_type = _type_from_property(mb->get_return_info());
1709 return true;
1710 }
1711 return false;
1712 } break;
1713 case GDScriptParser::DataType::BUILTIN: {
1714 Variant::CallError err;
1715 Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
1716 if (err.error != Variant::CallError::CALL_OK) {
1717 return false;
1718 }
1719
1720 List<MethodInfo> methods;
1721 tmp.get_method_list(&methods);
1722
1723 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
1724 MethodInfo &mi = E->get();
1725 if (mi.name == p_method) {
1726 r_type = _type_from_property(mi.return_val);
1727 return true;
1728 }
1729 }
1730 return false;
1731 } break;
1732 default: {
1733 return false;
1734 }
1735 }
1736 }
1737 return false;
1738 }
1739
_make_arguments_hint(const MethodInfo & p_info,int p_arg_idx)1740 static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) {
1741
1742 String arghint = _get_visual_datatype(p_info.return_val, false) + " " + p_info.name + "(";
1743
1744 int def_args = p_info.arguments.size() - p_info.default_arguments.size();
1745 int i = 0;
1746 for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E; E = E->next()) {
1747 if (i > 0) {
1748 arghint += ", ";
1749 }
1750
1751 if (i == p_arg_idx) {
1752 arghint += String::chr(0xFFFF);
1753 }
1754 arghint += E->get().name + ": " + _get_visual_datatype(E->get(), true);
1755
1756 if (i - def_args >= 0) {
1757 arghint += String(" = ") + p_info.default_arguments[i - def_args].get_construct_string();
1758 }
1759
1760 if (i == p_arg_idx) {
1761 arghint += String::chr(0xFFFF);
1762 }
1763
1764 i++;
1765 }
1766
1767 if (p_info.flags & METHOD_FLAG_VARARG) {
1768 if (p_info.arguments.size() > 0) {
1769 arghint += ", ";
1770 }
1771 if (p_arg_idx >= p_info.arguments.size()) {
1772 arghint += String::chr(0xFFFF);
1773 }
1774 arghint += "...";
1775 if (p_arg_idx >= p_info.arguments.size()) {
1776 arghint += String::chr(0xFFFF);
1777 }
1778 }
1779
1780 arghint += ")";
1781
1782 return arghint;
1783 }
1784
_make_arguments_hint(const GDScriptParser::FunctionNode * p_function,int p_arg_idx)1785 static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx) {
1786
1787 String arghint = p_function->return_type.to_string() + " " + p_function->name.operator String() + "(";
1788
1789 int def_args = p_function->arguments.size() - p_function->default_values.size();
1790 for (int i = 0; i < p_function->arguments.size(); i++) {
1791 if (i > 0) {
1792 arghint += ", ";
1793 }
1794
1795 if (i == p_arg_idx) {
1796 arghint += String::chr(0xFFFF);
1797 }
1798 arghint += p_function->arguments[i].operator String() + ": " + p_function->argument_types[i].to_string();
1799
1800 if (i - def_args >= 0) {
1801 String def_val = "<unknown>";
1802 if (p_function->default_values[i - def_args] && p_function->default_values[i - def_args]->type == GDScriptParser::Node::TYPE_OPERATOR) {
1803 const GDScriptParser::OperatorNode *assign = static_cast<const GDScriptParser::OperatorNode *>(p_function->default_values[i - def_args]);
1804
1805 if (assign->arguments.size() >= 2) {
1806 if (assign->arguments[1]->type == GDScriptParser::Node::TYPE_CONSTANT) {
1807 const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(assign->arguments[1]);
1808 def_val = cn->value.get_construct_string();
1809 } else if (assign->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) {
1810 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(assign->arguments[1]);
1811 def_val = id->name.operator String();
1812 }
1813 }
1814 }
1815 arghint += " = " + def_val;
1816 }
1817 if (i == p_arg_idx) {
1818 arghint += String::chr(0xFFFF);
1819 }
1820 }
1821
1822 arghint += ")";
1823
1824 return arghint;
1825 }
1826
_find_enumeration_candidates(const String p_enum_hint,Map<String,ScriptCodeCompletionOption> & r_result)1827 static void _find_enumeration_candidates(const String p_enum_hint, Map<String, ScriptCodeCompletionOption> &r_result) {
1828
1829 if (p_enum_hint.find(".") == -1) {
1830 // Global constant
1831 StringName current_enum = p_enum_hint;
1832 for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
1833 if (GlobalConstants::get_global_constant_enum(i) == current_enum) {
1834 ScriptCodeCompletionOption option(GlobalConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM);
1835 r_result.insert(option.display, option);
1836 }
1837 }
1838 } else {
1839 String class_name = p_enum_hint.get_slice(".", 0);
1840 String enum_name = p_enum_hint.get_slice(".", 1);
1841
1842 if (!ClassDB::class_exists(class_name)) {
1843 return;
1844 }
1845
1846 List<StringName> enum_constants;
1847 ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
1848 for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) {
1849 String candidate = class_name + "." + E->get();
1850 ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM);
1851 r_result.insert(option.display, option);
1852 }
1853 }
1854 }
1855
_find_identifiers_in_block(const GDScriptCompletionContext & p_context,Map<String,ScriptCodeCompletionOption> & r_result)1856 static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) {
1857 for (Map<StringName, GDScriptParser::LocalVarNode *>::Element *E = p_context.block->variables.front(); E; E = E->next()) {
1858 if (E->get()->line < p_context.line) {
1859 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_VARIABLE);
1860 r_result.insert(option.display, option);
1861 }
1862 }
1863 if (p_context.block->parent_block) {
1864 GDScriptCompletionContext c = p_context;
1865 c.block = p_context.block->parent_block;
1866 _find_identifiers_in_block(c, r_result);
1867 }
1868 }
1869
1870 static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result);
1871
_find_identifiers_in_class(const GDScriptCompletionContext & p_context,bool p_static,bool p_only_functions,bool p_parent_only,Map<String,ScriptCodeCompletionOption> & r_result)1872 static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) {
1873 if (!p_parent_only) {
1874 if (!p_static && !p_only_functions) {
1875 for (int i = 0; i < p_context._class->variables.size(); i++) {
1876 ScriptCodeCompletionOption option(p_context._class->variables[i].identifier, ScriptCodeCompletionOption::KIND_MEMBER);
1877 r_result.insert(option.display, option);
1878 }
1879 }
1880
1881 if (!p_only_functions) {
1882 for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_context._class->constant_expressions.front(); E; E = E->next()) {
1883 ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT);
1884 r_result.insert(option.display, option);
1885 }
1886 for (int i = 0; i < p_context._class->subclasses.size(); i++) {
1887 ScriptCodeCompletionOption option(p_context._class->subclasses[i]->name, ScriptCodeCompletionOption::KIND_CLASS);
1888 r_result.insert(option.display, option);
1889 }
1890 }
1891
1892 for (int i = 0; i < p_context._class->static_functions.size(); i++) {
1893 ScriptCodeCompletionOption option(p_context._class->static_functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
1894 if (p_context._class->static_functions[i]->arguments.size()) {
1895 option.insert_text += "(";
1896 } else {
1897 option.insert_text += "()";
1898 }
1899 r_result.insert(option.display, option);
1900 }
1901
1902 if (!p_static) {
1903 for (int i = 0; i < p_context._class->functions.size(); i++) {
1904 ScriptCodeCompletionOption option(p_context._class->functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
1905 if (p_context._class->functions[i]->arguments.size()) {
1906 option.insert_text += "(";
1907 } else {
1908 option.insert_text += "()";
1909 }
1910 r_result.insert(option.display, option);
1911 }
1912 }
1913 }
1914
1915 // Parents
1916 GDScriptCompletionIdentifier base_type;
1917 base_type.type = p_context._class->base_type;
1918 base_type.type.is_meta_type = p_static;
1919 base_type.value = p_context.base;
1920
1921 GDScriptCompletionContext c = p_context;
1922 c.block = NULL;
1923 c.function = NULL;
1924
1925 _find_identifiers_in_base(c, base_type, p_only_functions, r_result);
1926 }
1927
_find_identifiers_in_base(const GDScriptCompletionContext & p_context,const GDScriptCompletionIdentifier & p_base,bool p_only_functions,Map<String,ScriptCodeCompletionOption> & r_result)1928 static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
1929 GDScriptParser::DataType base_type = p_base.type;
1930 bool _static = base_type.is_meta_type;
1931
1932 if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) {
1933 ScriptCodeCompletionOption option("new", ScriptCodeCompletionOption::KIND_FUNCTION);
1934 option.insert_text += "(";
1935 r_result.insert(option.display, option);
1936 }
1937
1938 while (base_type.has_type) {
1939 switch (base_type.kind) {
1940 case GDScriptParser::DataType::CLASS: {
1941 GDScriptCompletionContext c = p_context;
1942 c._class = base_type.class_type;
1943 c.block = NULL;
1944 c.function = NULL;
1945 _find_identifiers_in_class(c, _static, p_only_functions, false, r_result);
1946 base_type = base_type.class_type->base_type;
1947 } break;
1948 case GDScriptParser::DataType::GDSCRIPT: {
1949 Ref<GDScript> script = base_type.script_type;
1950 if (script.is_valid()) {
1951 if (!_static && !p_only_functions) {
1952 if (p_context.base && p_context.base->get_script_instance()) {
1953 List<PropertyInfo> members;
1954 p_context.base->get_script_instance()->get_property_list(&members);
1955 for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
1956 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
1957 r_result.insert(option.display, option);
1958 }
1959 }
1960 for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) {
1961 ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER);
1962 r_result.insert(option.display, option);
1963 }
1964 }
1965 if (!p_only_functions) {
1966 for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) {
1967 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
1968 r_result.insert(option.display, option);
1969 }
1970 }
1971 for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) {
1972 if (!_static || E->get()->is_static()) {
1973 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_FUNCTION);
1974 if (E->get()->get_argument_count()) {
1975 option.insert_text += "(";
1976 } else {
1977 option.insert_text += "()";
1978 }
1979 r_result.insert(option.display, option);
1980 }
1981 }
1982 if (!p_only_functions) {
1983 for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) {
1984 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
1985 r_result.insert(option.display, option);
1986 }
1987 }
1988 base_type = GDScriptParser::DataType();
1989 if (script->get_base().is_valid()) {
1990 base_type.has_type = true;
1991 base_type.kind = GDScriptParser::DataType::GDSCRIPT;
1992 base_type.script_type = script->get_base();
1993 } else {
1994 base_type.has_type = script->get_instance_base_type() != StringName();
1995 base_type.kind = GDScriptParser::DataType::NATIVE;
1996 base_type.native_type = script->get_instance_base_type();
1997 }
1998 } else {
1999 return;
2000 }
2001 } break;
2002 case GDScriptParser::DataType::SCRIPT: {
2003 Ref<Script> scr = base_type.script_type;
2004 if (scr.is_valid()) {
2005 if (!_static && !p_only_functions) {
2006 List<PropertyInfo> members;
2007 scr->get_script_property_list(&members);
2008 for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
2009 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
2010 r_result.insert(option.display, option);
2011 }
2012 }
2013 if (!p_only_functions) {
2014 Map<StringName, Variant> constants;
2015 scr->get_constants(&constants);
2016 for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
2017 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
2018 r_result.insert(option.display, option);
2019 }
2020 }
2021
2022 List<MethodInfo> methods;
2023 scr->get_script_method_list(&methods);
2024 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
2025 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
2026 if (E->get().arguments.size()) {
2027 option.insert_text += "(";
2028 } else {
2029 option.insert_text += "()";
2030 }
2031 r_result.insert(option.display, option);
2032 }
2033
2034 Ref<Script> base_script = scr->get_base_script();
2035 if (base_script.is_valid()) {
2036 base_type.script_type = base_script;
2037 } else {
2038 base_type.kind = GDScriptParser::DataType::NATIVE;
2039 base_type.native_type = scr->get_instance_base_type();
2040 }
2041 } else {
2042 return;
2043 }
2044 } break;
2045 case GDScriptParser::DataType::NATIVE: {
2046 StringName type = base_type.native_type;
2047 if (!ClassDB::class_exists(type)) {
2048 type = String("_") + type;
2049 if (!ClassDB::class_exists(type)) {
2050 return;
2051 }
2052 }
2053
2054 if (!p_only_functions) {
2055 List<String> constants;
2056 ClassDB::get_integer_constant_list(type, &constants);
2057 for (List<String>::Element *E = constants.front(); E; E = E->next()) {
2058 ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT);
2059 r_result.insert(option.display, option);
2060 }
2061
2062 if (!_static) {
2063 List<PropertyInfo> pinfo;
2064 ClassDB::get_property_list(type, &pinfo);
2065 for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
2066 if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) {
2067 continue;
2068 }
2069 if (E->get().name.find("/") != -1) {
2070 continue;
2071 }
2072 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
2073 r_result.insert(option.display, option);
2074 }
2075 }
2076 }
2077
2078 if (!_static) {
2079 List<MethodInfo> methods;
2080 bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize();
2081 ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters);
2082 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
2083 if (E->get().name.begins_with("_")) {
2084 continue;
2085 }
2086 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
2087 if (E->get().arguments.size()) {
2088 option.insert_text += "(";
2089 } else {
2090 option.insert_text += "()";
2091 }
2092 r_result.insert(option.display, option);
2093 }
2094 }
2095
2096 return;
2097 } break;
2098 case GDScriptParser::DataType::BUILTIN: {
2099 Variant::CallError err;
2100 Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
2101 if (err.error != Variant::CallError::CALL_OK) {
2102 return;
2103 }
2104
2105 if (!p_only_functions) {
2106 List<PropertyInfo> members;
2107 if (p_base.value.get_type() != Variant::NIL) {
2108 p_base.value.get_property_list(&members);
2109 } else {
2110 tmp.get_property_list(&members);
2111 }
2112
2113 for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
2114 if (String(E->get().name).find("/") == -1) {
2115 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
2116 r_result.insert(option.display, option);
2117 }
2118 }
2119 }
2120
2121 List<MethodInfo> methods;
2122 tmp.get_method_list(&methods);
2123 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
2124 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION);
2125 if (E->get().arguments.size()) {
2126 option.insert_text += "(";
2127 } else {
2128 option.insert_text += "()";
2129 }
2130 r_result.insert(option.display, option);
2131 }
2132
2133 return;
2134 } break;
2135 default: {
2136 return;
2137 } break;
2138 }
2139 }
2140 }
2141
_find_identifiers(const GDScriptCompletionContext & p_context,bool p_only_functions,Map<String,ScriptCodeCompletionOption> & r_result)2142 static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
2143
2144 const GDScriptParser::BlockNode *block = p_context.block;
2145
2146 if (p_context.function) {
2147
2148 const GDScriptParser::FunctionNode *f = p_context.function;
2149
2150 for (int i = 0; i < f->arguments.size(); i++) {
2151 ScriptCodeCompletionOption option(f->arguments[i].operator String(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
2152 r_result.insert(option.display, option);
2153 }
2154 }
2155
2156 if (!p_only_functions && block) {
2157 GDScriptCompletionContext c = p_context;
2158 c.block = block;
2159 _find_identifiers_in_block(c, r_result);
2160 }
2161
2162 const GDScriptParser::ClassNode *clss = p_context._class;
2163 bool _static = p_context.function && p_context.function->_static;
2164
2165 while (clss) {
2166 GDScriptCompletionContext c = p_context;
2167 c._class = clss;
2168 c.block = NULL;
2169 c.function = NULL;
2170 _find_identifiers_in_class(c, _static, p_only_functions, false, r_result);
2171 _static = true;
2172 clss = clss->owner;
2173 }
2174
2175 for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
2176 MethodInfo mi = GDScriptFunctions::get_info(GDScriptFunctions::Function(i));
2177 ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION);
2178 if (mi.arguments.size() || (mi.flags & METHOD_FLAG_VARARG)) {
2179 option.insert_text += "(";
2180 } else {
2181 option.insert_text += "()";
2182 }
2183 r_result.insert(option.display, option);
2184 }
2185
2186 static const char *_type_names[Variant::VARIANT_MAX] = {
2187 "null", "bool", "int", "float", "String", "Vector2", "Rect2", "Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform",
2188 "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray",
2189 "PoolVector2Array", "PoolVector3Array", "PoolColorArray"
2190 };
2191
2192 for (int i = 0; i < Variant::VARIANT_MAX; i++) {
2193 ScriptCodeCompletionOption option(_type_names[i], ScriptCodeCompletionOption::KIND_CLASS);
2194 r_result.insert(option.display, option);
2195 }
2196
2197 static const char *_keywords[] = {
2198 "and", "in", "not", "or", "false", "PI", "TAU", "INF", "NAN", "self", "true", "as", "assert",
2199 "breakpoint", "class", "extends", "is", "func", "preload", "setget", "signal", "tool", "yield",
2200 "const", "enum", "export", "onready", "static", "var", "break", "continue", "if", "elif",
2201 "else", "for", "pass", "return", "match", "while", "remote", "sync", "master", "puppet", "slave",
2202 "remotesync", "mastersync", "puppetsync",
2203 0
2204 };
2205
2206 const char **kw = _keywords;
2207 while (*kw) {
2208 ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
2209 r_result.insert(option.display, option);
2210 kw++;
2211 }
2212
2213 // Autoload singletons
2214 List<PropertyInfo> props;
2215 ProjectSettings::get_singleton()->get_property_list(&props);
2216 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
2217 String s = E->get().name;
2218 if (!s.begins_with("autoload/")) {
2219 continue;
2220 }
2221 String path = ProjectSettings::get_singleton()->get(s);
2222 if (path.begins_with("*")) {
2223 ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CONSTANT);
2224 r_result.insert(option.display, option);
2225 }
2226 }
2227
2228 // Named scripts
2229 List<StringName> named_scripts;
2230 ScriptServer::get_global_class_list(&named_scripts);
2231 for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) {
2232 ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2233 r_result.insert(option.display, option);
2234 }
2235
2236 // Native classes
2237 for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) {
2238 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2239 r_result.insert(option.display, option);
2240 }
2241 }
2242
_find_call_arguments(const GDScriptCompletionContext & p_context,const GDScriptCompletionIdentifier & p_base,const StringName & p_method,int p_argidx,bool p_static,Map<String,ScriptCodeCompletionOption> & r_result,String & r_arghint)2243 static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptCodeCompletionOption> &r_result, String &r_arghint) {
2244 Variant base = p_base.value;
2245 GDScriptParser::DataType base_type = p_base.type;
2246
2247 const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
2248
2249 #define IS_METHOD_SIGNAL(m_method) (m_method == "connect" || m_method == "disconnect" || m_method == "is_connected" || m_method == "emit_signal")
2250
2251 while (base_type.has_type) {
2252 switch (base_type.kind) {
2253 case GDScriptParser::DataType::CLASS: {
2254 for (int i = 0; i < base_type.class_type->static_functions.size(); i++) {
2255 if (base_type.class_type->static_functions[i]->name == p_method) {
2256 r_arghint = _make_arguments_hint(base_type.class_type->static_functions[i], p_argidx);
2257 return;
2258 }
2259 }
2260 for (int i = 0; i < base_type.class_type->functions.size(); i++) {
2261 if (base_type.class_type->functions[i]->name == p_method) {
2262 r_arghint = _make_arguments_hint(base_type.class_type->functions[i], p_argidx);
2263 return;
2264 }
2265 }
2266
2267 if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) {
2268 for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
2269 ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL);
2270 option.insert_text = quote_style + option.display + quote_style;
2271 r_result.insert(option.display, option);
2272 }
2273 }
2274
2275 base_type = base_type.class_type->base_type;
2276 } break;
2277 case GDScriptParser::DataType::GDSCRIPT: {
2278 Ref<GDScript> gds = base_type.script_type;
2279 if (gds.is_valid()) {
2280 if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) {
2281 List<MethodInfo> signals;
2282 gds->get_script_signal_list(&signals);
2283 for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
2284 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL);
2285 option.insert_text = quote_style + option.display + quote_style;
2286 r_result.insert(option.display, option);
2287 }
2288 }
2289 Ref<GDScript> base_script = gds->get_base_script();
2290 if (base_script.is_valid()) {
2291 base_type.script_type = base_script;
2292 } else {
2293 base_type.kind = GDScriptParser::DataType::NATIVE;
2294 base_type.native_type = gds->get_instance_base_type();
2295 }
2296 } else {
2297 return;
2298 }
2299 } break;
2300 case GDScriptParser::DataType::NATIVE: {
2301 StringName class_name = base_type.native_type;
2302 if (!ClassDB::class_exists(class_name)) {
2303 class_name = String("_") + class_name;
2304 if (!ClassDB::class_exists(class_name)) {
2305 base_type.has_type = false;
2306 break;
2307 }
2308 }
2309
2310 List<MethodInfo> methods;
2311 ClassDB::get_method_list(class_name, &methods);
2312 ClassDB::get_virtual_methods(class_name, &methods);
2313 int method_args = 0;
2314
2315 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
2316 if (E->get().name == p_method) {
2317 method_args = E->get().arguments.size();
2318 if (base.get_type() == Variant::OBJECT) {
2319 Object *obj = base.operator Object *();
2320 if (obj) {
2321 List<String> options;
2322 obj->get_argument_options(p_method, p_argidx, &options);
2323 for (List<String>::Element *F = options.front(); F; F = F->next()) {
2324 ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION);
2325 r_result.insert(option.display, option);
2326 }
2327 }
2328 }
2329
2330 if (p_argidx < method_args) {
2331 PropertyInfo arg_info = E->get().arguments[p_argidx];
2332 if (arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
2333 _find_enumeration_candidates(arg_info.class_name, r_result);
2334 }
2335 }
2336
2337 r_arghint = _make_arguments_hint(E->get(), p_argidx);
2338 break;
2339 }
2340 }
2341
2342 if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) {
2343 List<MethodInfo> signals;
2344 ClassDB::get_signal_list(class_name, &signals);
2345 for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
2346 ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL);
2347 option.insert_text = quote_style + option.display + quote_style;
2348 r_result.insert(option.display, option);
2349 }
2350 }
2351 #undef IS_METHOD_SIGNAL
2352
2353 if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) {
2354 // Get autoloads
2355 List<PropertyInfo> props;
2356 ProjectSettings::get_singleton()->get_property_list(&props);
2357
2358 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
2359 String s = E->get().name;
2360 if (!s.begins_with("autoload/")) {
2361 continue;
2362 }
2363 String name = s.get_slice("/", 1);
2364 ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH);
2365 option.insert_text = quote_style + option.display + quote_style;
2366 r_result.insert(option.display, option);
2367 }
2368 }
2369
2370 if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, "InputEvent") && p_method.operator String().find("action") != -1) {
2371 // Get input actions
2372 List<PropertyInfo> props;
2373 ProjectSettings::get_singleton()->get_property_list(&props);
2374 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
2375 String s = E->get().name;
2376 if (!s.begins_with("input/")) {
2377 continue;
2378 }
2379 String name = s.get_slice("/", 1);
2380 ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT);
2381 option.insert_text = quote_style + option.display + quote_style;
2382 r_result.insert(option.display, option);
2383 }
2384 }
2385
2386 base_type.has_type = false;
2387 } break;
2388 case GDScriptParser::DataType::BUILTIN: {
2389 if (base.get_type() == Variant::NIL) {
2390 Variant::CallError err;
2391 base = Variant::construct(base_type.builtin_type, NULL, 0, err);
2392 if (err.error != Variant::CallError::CALL_OK) {
2393 return;
2394 }
2395 }
2396
2397 List<MethodInfo> methods;
2398 base.get_method_list(&methods);
2399 for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
2400 if (E->get().name == p_method) {
2401 r_arghint = _make_arguments_hint(E->get(), p_argidx);
2402 return;
2403 }
2404 }
2405
2406 base_type.has_type = false;
2407 } break;
2408 default: {
2409 base_type.has_type = false;
2410 } break;
2411 }
2412 }
2413 }
2414
_find_call_arguments(GDScriptCompletionContext & p_context,const GDScriptParser::Node * p_node,int p_argidx,Map<String,ScriptCodeCompletionOption> & r_result,bool & r_forced,String & r_arghint)2415 static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
2416
2417 const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
2418
2419 if (!p_node || p_node->type != GDScriptParser::Node::TYPE_OPERATOR) {
2420 return;
2421 }
2422
2423 Variant base;
2424 GDScriptParser::DataType base_type;
2425 StringName function;
2426 bool _static = false;
2427 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_node);
2428
2429 GDScriptCompletionIdentifier connect_base;
2430
2431 if (op->op != GDScriptParser::OperatorNode::OP_CALL && op->op != GDScriptParser::OperatorNode::OP_PARENT_CALL) {
2432 return;
2433 }
2434
2435 if (!op->arguments.size()) {
2436 return;
2437 }
2438
2439 if (op->op == GDScriptParser::OperatorNode::OP_CALL) {
2440 if (op->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) {
2441 // Complete built-in function
2442 const GDScriptParser::BuiltInFunctionNode *fn = static_cast<const GDScriptParser::BuiltInFunctionNode *>(op->arguments[0]);
2443 MethodInfo mi = GDScriptFunctions::get_info(fn->function);
2444
2445 if ((mi.name == "load" || mi.name == "preload") && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
2446 _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
2447 }
2448
2449 r_arghint = _make_arguments_hint(mi, p_argidx);
2450 return;
2451
2452 } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) {
2453 // Complete constructor
2454 const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(op->arguments[0]);
2455
2456 List<MethodInfo> constructors;
2457 Variant::get_constructor_list(tn->vtype, &constructors);
2458
2459 int i = 0;
2460 for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) {
2461 if (p_argidx >= E->get().arguments.size()) {
2462 continue;
2463 }
2464 if (i > 0) {
2465 r_arghint += "\n";
2466 }
2467 r_arghint += _make_arguments_hint(E->get(), p_argidx);
2468 i++;
2469 }
2470 return;
2471 } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_SELF) {
2472
2473 if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) {
2474 return;
2475 }
2476
2477 base = p_context.base;
2478
2479 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]);
2480 function = id->name;
2481 base_type.has_type = true;
2482 base_type.kind = GDScriptParser::DataType::CLASS;
2483 base_type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class);
2484 _static = p_context.function && p_context.function->_static;
2485
2486 if (function == "connect" && op->arguments.size() >= 4) {
2487 _guess_expression_type(p_context, op->arguments[3], connect_base);
2488 }
2489
2490 } else {
2491 if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) {
2492 return;
2493 }
2494 const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]);
2495 function = id->name;
2496
2497 GDScriptCompletionIdentifier ci;
2498 if (_guess_expression_type(p_context, op->arguments[0], ci)) {
2499 base_type = ci.type;
2500 base = ci.value;
2501 } else {
2502 return;
2503 }
2504 _static = ci.type.is_meta_type;
2505
2506 if (function == "connect" && op->arguments.size() >= 4) {
2507 _guess_expression_type(p_context, op->arguments[3], connect_base);
2508 }
2509 }
2510 } else {
2511 if (!p_context._class || op->arguments.size() < 1 || op->arguments[0]->type != GDScriptParser::Node::TYPE_IDENTIFIER) {
2512 return;
2513 }
2514 base_type.has_type = true;
2515 base_type.kind = GDScriptParser::DataType::CLASS;
2516 base_type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class);
2517 base_type.is_meta_type = p_context.function && p_context.function->_static;
2518 base = p_context.base;
2519
2520 function = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name;
2521
2522 if (function == "connect" && op->arguments.size() >= 4) {
2523 _guess_expression_type(p_context, op->arguments[3], connect_base);
2524 }
2525 }
2526
2527 GDScriptCompletionIdentifier ci;
2528 ci.type = base_type;
2529 ci.value = base;
2530 _find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint);
2531
2532 if (function == "connect" && p_argidx == 2) {
2533 Map<String, ScriptCodeCompletionOption> methods;
2534 _find_identifiers_in_base(p_context, connect_base, true, methods);
2535 for (Map<String, ScriptCodeCompletionOption>::Element *E = methods.front(); E; E = E->next()) {
2536 ScriptCodeCompletionOption &option = E->value();
2537 option.insert_text = quote_style + option.display + quote_style;
2538 r_result.insert(option.display, option);
2539 }
2540 }
2541
2542 r_forced = r_result.size() > 0;
2543 }
2544
complete_code(const String & p_code,const String & p_path,Object * p_owner,List<ScriptCodeCompletionOption> * r_options,bool & r_forced,String & r_call_hint)2545 Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
2546
2547 const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
2548
2549 GDScriptParser parser;
2550
2551 parser.parse(p_code, p_path.get_base_dir(), false, p_path, true);
2552 r_forced = false;
2553 Map<String, ScriptCodeCompletionOption> options;
2554 GDScriptCompletionContext context;
2555 context._class = parser.get_completion_class();
2556 context.block = parser.get_completion_block();
2557 context.function = parser.get_completion_function();
2558 context.line = parser.get_completion_line();
2559
2560 if (!context._class || context._class->owner == NULL) {
2561 context.base = p_owner;
2562 context.base_path = p_path.get_base_dir();
2563 }
2564
2565 bool is_function = false;
2566
2567 switch (parser.get_completion_type()) {
2568 case GDScriptParser::COMPLETION_NONE: {
2569 } break;
2570 case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
2571 List<StringName> constants;
2572 Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants);
2573 for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
2574 ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
2575 options.insert(option.display, option);
2576 }
2577 } break;
2578 case GDScriptParser::COMPLETION_PARENT_FUNCTION: {
2579 _find_identifiers_in_class(context, !context.function || context.function->_static, true, true, options);
2580 } break;
2581 case GDScriptParser::COMPLETION_FUNCTION: {
2582 is_function = true;
2583 FALLTHROUGH;
2584 }
2585 case GDScriptParser::COMPLETION_IDENTIFIER: {
2586 _find_identifiers(context, is_function, options);
2587 } break;
2588 case GDScriptParser::COMPLETION_EXTENDS: {
2589
2590 // Native classes.
2591 List<StringName> class_list;
2592 ClassDB::get_class_list(&class_list);
2593 for (int i = 0; i < class_list.size(); i++) {
2594 ScriptCodeCompletionOption option(class_list[i], ScriptCodeCompletionOption::KIND_CLASS);
2595 options.insert(option.display, option);
2596 }
2597
2598 // GDScript classes.
2599 if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) {
2600 for (int i = 0; i < ScriptServer::get_language_count(); i++) {
2601 if (ScriptServer::get_language(i)->get_name() == "GDScript") {
2602 List<String> extensions;
2603 ScriptServer::get_language(i)->get_recognized_extensions(&extensions);
2604 for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
2605 _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options, String("." + E->get()));
2606 }
2607 }
2608 }
2609 r_forced = true;
2610 }
2611
2612 // Named Scripts.
2613 List<StringName> named_scripts;
2614 ScriptServer::get_global_class_list(&named_scripts);
2615 for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) {
2616 ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2617 options.insert(option.display, option);
2618 }
2619 } break;
2620 case GDScriptParser::COMPLETION_GET_NODE: {
2621 if (p_owner) {
2622 List<String> opts;
2623 p_owner->get_argument_options("get_node", 0, &opts);
2624
2625 for (List<String>::Element *E = opts.front(); E; E = E->next()) {
2626
2627 String opt = E->get().strip_edges();
2628 if (opt.is_quoted()) {
2629 r_forced = true;
2630 String idopt = opt.unquote();
2631 if (idopt.replace("/", "_").is_valid_identifier()) {
2632 ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH);
2633 options.insert(option.display, option);
2634 } else {
2635 ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
2636 options.insert(option.display, option);
2637 }
2638 }
2639 }
2640
2641 // Get autoloads
2642 List<PropertyInfo> props;
2643 ProjectSettings::get_singleton()->get_property_list(&props);
2644
2645 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
2646 String s = E->get().name;
2647 if (!s.begins_with("autoload/")) {
2648 continue;
2649 }
2650 String name = s.get_slice("/", 1);
2651 ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH);
2652 options.insert(option.display, option);
2653 }
2654 }
2655 } break;
2656 case GDScriptParser::COMPLETION_METHOD: {
2657 is_function = true;
2658 FALLTHROUGH;
2659 }
2660 case GDScriptParser::COMPLETION_INDEX: {
2661 const GDScriptParser::Node *node = parser.get_completion_node();
2662 if (node->type != GDScriptParser::Node::TYPE_OPERATOR) {
2663 break;
2664 }
2665 const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(node);
2666 if (op->arguments.size() < 1) {
2667 break;
2668 }
2669
2670 GDScriptCompletionIdentifier base;
2671 if (!_guess_expression_type(context, op->arguments[0], base)) {
2672 break;
2673 }
2674
2675 GDScriptCompletionContext c = context;
2676 c.function = NULL;
2677 c.block = NULL;
2678 c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : NULL;
2679 if (base.type.kind == GDScriptParser::DataType::CLASS) {
2680 c._class = base.type.class_type;
2681 } else {
2682 c._class = NULL;
2683 }
2684
2685 _find_identifiers_in_base(c, base, is_function, options);
2686 } break;
2687 case GDScriptParser::COMPLETION_CALL_ARGUMENTS: {
2688 _find_call_arguments(context, parser.get_completion_node(), parser.get_completion_argument_index(), options, r_forced, r_call_hint);
2689 } break;
2690 case GDScriptParser::COMPLETION_VIRTUAL_FUNC: {
2691 GDScriptParser::DataType native_type = context._class->base_type;
2692 while (native_type.has_type && native_type.kind != GDScriptParser::DataType::NATIVE) {
2693 switch (native_type.kind) {
2694 case GDScriptParser::DataType::CLASS: {
2695 native_type = native_type.class_type->base_type;
2696 } break;
2697 case GDScriptParser::DataType::GDSCRIPT: {
2698 Ref<GDScript> gds = native_type.script_type;
2699 if (gds.is_valid()) {
2700 Ref<GDScript> base = gds->get_base_script();
2701 if (base.is_valid()) {
2702 native_type.script_type = base;
2703 } else {
2704 native_type.native_type = gds->get_instance_base_type();
2705 native_type.kind = GDScriptParser::DataType::NATIVE;
2706 }
2707 } else {
2708 native_type.has_type = false;
2709 }
2710 } break;
2711 default: {
2712 native_type.has_type = false;
2713 } break;
2714 }
2715 }
2716
2717 if (!native_type.has_type) {
2718 break;
2719 }
2720
2721 StringName class_name = native_type.native_type;
2722 if (!ClassDB::class_exists(class_name)) {
2723 class_name = String("_") + class_name;
2724 if (!ClassDB::class_exists(class_name)) {
2725 break;
2726 }
2727 }
2728
2729 bool use_type_hint = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints").operator bool();
2730
2731 List<MethodInfo> virtual_methods;
2732 ClassDB::get_virtual_methods(class_name, &virtual_methods);
2733 for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) {
2734
2735 MethodInfo &mi = E->get();
2736 String method_hint = mi.name;
2737 if (method_hint.find(":") != -1) {
2738 method_hint = method_hint.get_slice(":", 0);
2739 }
2740 method_hint += "(";
2741
2742 if (mi.arguments.size()) {
2743 for (int i = 0; i < mi.arguments.size(); i++) {
2744 if (i > 0) {
2745 method_hint += ", ";
2746 }
2747 String arg = mi.arguments[i].name;
2748 if (arg.find(":") != -1) {
2749 arg = arg.substr(0, arg.find(":"));
2750 }
2751 method_hint += arg;
2752 if (use_type_hint && mi.arguments[i].type != Variant::NIL) {
2753 method_hint += ": ";
2754 if (mi.arguments[i].type == Variant::OBJECT && mi.arguments[i].class_name != StringName()) {
2755 method_hint += mi.arguments[i].class_name.operator String();
2756 } else {
2757 method_hint += Variant::get_type_name(mi.arguments[i].type);
2758 }
2759 }
2760 }
2761 }
2762 method_hint += ")";
2763 if (use_type_hint && (mi.return_val.type != Variant::NIL || !(mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT))) {
2764 method_hint += " -> ";
2765 if (mi.return_val.type == Variant::NIL) {
2766 method_hint += "void";
2767 } else if (mi.return_val.type == Variant::OBJECT && mi.return_val.class_name != StringName()) {
2768 method_hint += mi.return_val.class_name.operator String();
2769 } else {
2770 method_hint += Variant::get_type_name(mi.return_val.type);
2771 }
2772 }
2773 method_hint += ":";
2774
2775 ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION);
2776 options.insert(option.display, option);
2777 }
2778 } break;
2779 case GDScriptParser::COMPLETION_YIELD: {
2780 const GDScriptParser::Node *node = parser.get_completion_node();
2781
2782 GDScriptCompletionContext c = context;
2783 c.line = node->line;
2784 GDScriptCompletionIdentifier type;
2785 if (!_guess_expression_type(c, node, type)) {
2786 break;
2787 }
2788
2789 GDScriptParser::DataType base_type = type.type;
2790 while (base_type.has_type) {
2791 switch (base_type.kind) {
2792 case GDScriptParser::DataType::CLASS: {
2793 for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
2794 ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL);
2795 option.insert_text = quote_style + option.display + quote_style;
2796 options.insert(option.display, option);
2797 }
2798 base_type = base_type.class_type->base_type;
2799 } break;
2800 case GDScriptParser::DataType::SCRIPT:
2801 case GDScriptParser::DataType::GDSCRIPT: {
2802 Ref<Script> scr = base_type.script_type;
2803 if (scr.is_valid()) {
2804 List<MethodInfo> signals;
2805 scr->get_script_signal_list(&signals);
2806 for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
2807 ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
2808 options.insert(option.display, option);
2809 }
2810 Ref<Script> base_script = scr->get_base_script();
2811 if (base_script.is_valid()) {
2812 base_type.script_type = base_script;
2813 } else {
2814 base_type.kind = GDScriptParser::DataType::NATIVE;
2815 base_type.native_type = scr->get_instance_base_type();
2816 }
2817 } else {
2818 base_type.has_type = false;
2819 }
2820 } break;
2821 case GDScriptParser::DataType::NATIVE: {
2822 base_type.has_type = false;
2823
2824 StringName class_name = base_type.native_type;
2825 if (!ClassDB::class_exists(class_name)) {
2826 class_name = String("_") + class_name;
2827 if (!ClassDB::class_exists(class_name)) {
2828 break;
2829 }
2830 }
2831
2832 List<MethodInfo> signals;
2833 ClassDB::get_signal_list(class_name, &signals);
2834 for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
2835 ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL);
2836 options.insert(option.display, option);
2837 }
2838 } break;
2839 default: {
2840 base_type.has_type = false;
2841 }
2842 }
2843 }
2844 } break;
2845 case GDScriptParser::COMPLETION_RESOURCE_PATH: {
2846 if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) {
2847 _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options);
2848 r_forced = true;
2849 }
2850 } break;
2851 case GDScriptParser::COMPLETION_ASSIGN: {
2852 GDScriptCompletionIdentifier type;
2853 if (!_guess_expression_type(context, parser.get_completion_node(), type)) {
2854 break;
2855 }
2856
2857 if (!type.enumeration.empty()) {
2858 _find_enumeration_candidates(type.enumeration, options);
2859 r_forced = options.size() > 0;
2860 }
2861 } break;
2862 case GDScriptParser::COMPLETION_TYPE_HINT: {
2863 const GDScriptParser::ClassNode *clss = context._class;
2864 while (clss) {
2865 for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = clss->constant_expressions.front(); E; E = E->next()) {
2866 GDScriptCompletionIdentifier constant;
2867 GDScriptCompletionContext c = context;
2868 c.function = NULL;
2869 c.block = NULL;
2870 c.line = E->value().expression->line;
2871 if (_guess_expression_type(c, E->value().expression, constant)) {
2872 if (constant.type.has_type && constant.type.is_meta_type) {
2873 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2874 options.insert(option.display, option);
2875 }
2876 }
2877 }
2878 for (int i = 0; i < clss->subclasses.size(); i++) {
2879 if (clss->subclasses[i]->name != StringName()) {
2880 ScriptCodeCompletionOption option(clss->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2881 options.insert(option.display, option);
2882 }
2883 }
2884 clss = clss->owner;
2885 for (int i = 0; i < Variant::VARIANT_MAX; i++) {
2886 ScriptCodeCompletionOption option(Variant::get_type_name((Variant::Type)i), ScriptCodeCompletionOption::KIND_CLASS);
2887 options.insert(option.display, option);
2888 }
2889 List<PropertyInfo> props;
2890 ProjectSettings::get_singleton()->get_property_list(&props);
2891 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
2892 String s = E->get().name;
2893 if (!s.begins_with("autoload/")) {
2894 continue;
2895 }
2896 ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CLASS);
2897 options.insert(option.display, option);
2898 }
2899 }
2900
2901 List<StringName> native_classes;
2902 ClassDB::get_class_list(&native_classes);
2903 for (List<StringName>::Element *E = native_classes.front(); E; E = E->next()) {
2904 String class_name = E->get().operator String();
2905 if (class_name.begins_with("_")) {
2906 class_name = class_name.right(1);
2907 }
2908 if (Engine::get_singleton()->has_singleton(class_name)) {
2909 continue;
2910 }
2911 ScriptCodeCompletionOption option(class_name, ScriptCodeCompletionOption::KIND_CLASS);
2912 options.insert(option.display, option);
2913 }
2914
2915 // Named scripts
2916 List<StringName> named_scripts;
2917 ScriptServer::get_global_class_list(&named_scripts);
2918 for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) {
2919 ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2920 options.insert(option.display, option);
2921 }
2922
2923 if (parser.get_completion_identifier_is_function()) {
2924 ScriptCodeCompletionOption option("void", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
2925 options.insert(option.display, option);
2926 }
2927 r_forced = true;
2928 } break;
2929 case GDScriptParser::COMPLETION_TYPE_HINT_INDEX: {
2930 GDScriptCompletionIdentifier base;
2931 String index = parser.get_completion_cursor().operator String();
2932 if (!_guess_identifier_type(context, index.get_slice(".", 0), base)) {
2933 break;
2934 }
2935
2936 GDScriptCompletionContext c = context;
2937 c._class = NULL;
2938 c.function = NULL;
2939 c.block = NULL;
2940 bool finding = true;
2941 index = index.right(index.find(".") + 1);
2942 while (index.find(".") != -1) {
2943 String id = index.get_slice(".", 0);
2944
2945 GDScriptCompletionIdentifier sub_base;
2946 if (!_guess_identifier_type_from_base(c, base, id, sub_base)) {
2947 finding = false;
2948 break;
2949 }
2950 index = index.right(index.find(".") + 1);
2951 base = sub_base;
2952 }
2953
2954 if (!finding) {
2955 break;
2956 }
2957
2958 GDScriptParser::DataType base_type = base.type;
2959 while (base_type.has_type) {
2960 switch (base_type.kind) {
2961 case GDScriptParser::DataType::CLASS: {
2962 if (base_type.class_type) {
2963 for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = base_type.class_type->constant_expressions.front(); E; E = E->next()) {
2964 GDScriptCompletionIdentifier constant;
2965 GDScriptCompletionContext c2 = context;
2966 c2._class = base_type.class_type;
2967 c2.function = NULL;
2968 c2.block = NULL;
2969 c2.line = E->value().expression->line;
2970 if (_guess_expression_type(c2, E->value().expression, constant)) {
2971 if (constant.type.has_type && constant.type.is_meta_type) {
2972 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2973 options.insert(option.display, option);
2974 }
2975 }
2976 }
2977 for (int i = 0; i < base_type.class_type->subclasses.size(); i++) {
2978 if (base_type.class_type->subclasses[i]->name != StringName()) {
2979 ScriptCodeCompletionOption option(base_type.class_type->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2980 options.insert(option.display, option);
2981 }
2982 }
2983
2984 base_type = base_type.class_type->base_type;
2985 } else {
2986 base_type.has_type = false;
2987 }
2988 } break;
2989 case GDScriptParser::DataType::SCRIPT:
2990 case GDScriptParser::DataType::GDSCRIPT: {
2991 Ref<Script> scr = base_type.script_type;
2992 if (scr.is_valid()) {
2993 Map<StringName, Variant> constants;
2994 scr->get_constants(&constants);
2995 for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
2996 Ref<Script> const_scr = E->value();
2997 if (const_scr.is_valid()) {
2998 ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
2999 options.insert(option.display, option);
3000 }
3001 }
3002 Ref<Script> base_script = scr->get_base_script();
3003 if (base_script.is_valid()) {
3004 base_type.script_type = base_script;
3005 } else {
3006 base_type.has_type = false;
3007 }
3008 } else {
3009 base_type.has_type = false;
3010 }
3011 } break;
3012 default: {
3013 base_type.has_type = false;
3014 } break;
3015 }
3016 }
3017 r_forced = options.size() > 0;
3018 } break;
3019 }
3020
3021 for (Map<String, ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) {
3022 r_options->push_back(E->get());
3023 }
3024
3025 return OK;
3026 }
3027
3028 #else
3029
complete_code(const String & p_code,const String & p_path,Object * p_owner,List<ScriptCodeCompletionOption> * r_options,bool & r_forced,String & r_call_hint)3030 Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) {
3031 return OK;
3032 }
3033
3034 #endif
3035
3036 //////// END COMPLETION //////////
3037
_get_indentation() const3038 String GDScriptLanguage::_get_indentation() const {
3039 #ifdef TOOLS_ENABLED
3040 if (Engine::get_singleton()->is_editor_hint()) {
3041 bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", false);
3042
3043 if (use_space_indentation) {
3044 int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
3045
3046 String space_indent = "";
3047 for (int i = 0; i < indent_size; i++) {
3048 space_indent += " ";
3049 }
3050 return space_indent;
3051 }
3052 }
3053 #endif
3054 return "\t";
3055 }
3056
auto_indent_code(String & p_code,int p_from_line,int p_to_line) const3057 void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {
3058
3059 String indent = _get_indentation();
3060
3061 Vector<String> lines = p_code.split("\n");
3062 List<int> indent_stack;
3063
3064 for (int i = 0; i < lines.size(); i++) {
3065
3066 String l = lines[i];
3067 int tc = 0;
3068 for (int j = 0; j < l.length(); j++) {
3069 if (l[j] == ' ' || l[j] == '\t') {
3070
3071 tc++;
3072 } else {
3073 break;
3074 }
3075 }
3076
3077 String st = l.substr(tc, l.length()).strip_edges();
3078 if (st == "" || st.begins_with("#"))
3079 continue; //ignore!
3080
3081 int ilevel = 0;
3082 if (indent_stack.size()) {
3083 ilevel = indent_stack.back()->get();
3084 }
3085
3086 if (tc > ilevel) {
3087 indent_stack.push_back(tc);
3088 } else if (tc < ilevel) {
3089 while (indent_stack.size() && indent_stack.back()->get() > tc) {
3090 indent_stack.pop_back();
3091 }
3092
3093 if (indent_stack.size() && indent_stack.back()->get() != tc)
3094 indent_stack.push_back(tc); //this is not right but gets the job done
3095 }
3096
3097 if (i >= p_from_line) {
3098
3099 l = "";
3100 for (int j = 0; j < indent_stack.size(); j++) {
3101 l += indent;
3102 }
3103 l += st;
3104
3105 } else if (i > p_to_line) {
3106 break;
3107 }
3108
3109 lines.write[i] = l;
3110 }
3111
3112 p_code = "";
3113 for (int i = 0; i < lines.size(); i++) {
3114 if (i > 0)
3115 p_code += "\n";
3116 p_code += lines[i];
3117 }
3118 }
3119
3120 #ifdef TOOLS_ENABLED
3121
_lookup_symbol_from_base(const GDScriptParser::DataType & p_base,const String & p_symbol,bool p_is_function,GDScriptLanguage::LookupResult & r_result)3122 static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, const String &p_symbol, bool p_is_function, GDScriptLanguage::LookupResult &r_result) {
3123 GDScriptParser::DataType base_type = p_base;
3124
3125 while (base_type.has_type) {
3126 switch (base_type.kind) {
3127 case GDScriptParser::DataType::CLASS: {
3128 if (base_type.class_type) {
3129 if (p_is_function) {
3130 for (int i = 0; i < base_type.class_type->functions.size(); i++) {
3131 if (base_type.class_type->functions[i]->name == p_symbol) {
3132 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3133 r_result.location = base_type.class_type->functions[i]->line;
3134 return OK;
3135 }
3136 }
3137 for (int i = 0; i < base_type.class_type->static_functions.size(); i++) {
3138 if (base_type.class_type->static_functions[i]->name == p_symbol) {
3139 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3140 r_result.location = base_type.class_type->static_functions[i]->line;
3141 return OK;
3142 }
3143 }
3144 } else {
3145 if (base_type.class_type->constant_expressions.has(p_symbol)) {
3146 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3147 r_result.location = base_type.class_type->constant_expressions[p_symbol].expression->line;
3148 return OK;
3149 }
3150
3151 for (int i = 0; i < base_type.class_type->variables.size(); i++) {
3152 if (base_type.class_type->variables[i].identifier == p_symbol) {
3153 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3154 r_result.location = base_type.class_type->variables[i].line;
3155 return OK;
3156 }
3157 }
3158
3159 for (int i = 0; i < base_type.class_type->subclasses.size(); i++) {
3160 if (base_type.class_type->subclasses[i]->name == p_symbol) {
3161 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3162 r_result.location = base_type.class_type->subclasses[i]->line;
3163 return OK;
3164 }
3165 }
3166 }
3167 base_type = base_type.class_type->base_type;
3168 }
3169 } break;
3170 case GDScriptParser::DataType::SCRIPT:
3171 case GDScriptParser::DataType::GDSCRIPT: {
3172 Ref<Script> scr = base_type.script_type;
3173 if (scr.is_valid()) {
3174 int line = scr->get_member_line(p_symbol);
3175 if (line >= 0) {
3176 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3177 r_result.location = line;
3178 r_result.script = scr;
3179 return OK;
3180 }
3181 Ref<Script> base_script = scr->get_base_script();
3182 if (base_script.is_valid()) {
3183 base_type.script_type = base_script;
3184 } else {
3185 base_type.kind = GDScriptParser::DataType::NATIVE;
3186 base_type.native_type = scr->get_instance_base_type();
3187 }
3188 } else {
3189 base_type.has_type = false;
3190 }
3191 } break;
3192 case GDScriptParser::DataType::NATIVE: {
3193 StringName class_name = base_type.native_type;
3194 if (!ClassDB::class_exists(class_name)) {
3195 class_name = String("_") + class_name;
3196 if (!ClassDB::class_exists(class_name)) {
3197 base_type.has_type = false;
3198 break;
3199 }
3200 }
3201
3202 if (ClassDB::has_method(class_name, p_symbol, true)) {
3203 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
3204 r_result.class_name = base_type.native_type;
3205 r_result.class_member = p_symbol;
3206 return OK;
3207 }
3208
3209 List<MethodInfo> virtual_methods;
3210 ClassDB::get_virtual_methods(class_name, &virtual_methods, true);
3211 for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) {
3212 if (E->get().name == p_symbol) {
3213 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
3214 r_result.class_name = base_type.native_type;
3215 r_result.class_member = p_symbol;
3216 return OK;
3217 }
3218 }
3219
3220 StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true);
3221 if (enum_name != StringName()) {
3222 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM;
3223 r_result.class_name = base_type.native_type;
3224 r_result.class_member = enum_name;
3225 return OK;
3226 }
3227
3228 List<String> constants;
3229 ClassDB::get_integer_constant_list(class_name, &constants, true);
3230 for (List<String>::Element *E = constants.front(); E; E = E->next()) {
3231 if (E->get() == p_symbol) {
3232 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
3233 r_result.class_name = base_type.native_type;
3234 r_result.class_member = p_symbol;
3235 return OK;
3236 }
3237 }
3238
3239 List<PropertyInfo> properties;
3240 ClassDB::get_property_list(class_name, &properties, true);
3241 for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
3242 if (E->get().name == p_symbol) {
3243 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
3244 r_result.class_name = base_type.native_type;
3245 r_result.class_member = p_symbol;
3246 return OK;
3247 }
3248 }
3249
3250 StringName parent = ClassDB::get_parent_class(class_name);
3251 if (parent != StringName()) {
3252 if (String(parent).begins_with("_")) {
3253 base_type.native_type = String(parent).right(1);
3254 } else {
3255 base_type.native_type = parent;
3256 }
3257 } else {
3258 base_type.has_type = false;
3259 }
3260 } break;
3261 case GDScriptParser::DataType::BUILTIN: {
3262 base_type.has_type = false;
3263
3264 if (Variant::has_constant(base_type.builtin_type, p_symbol)) {
3265 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
3266 r_result.class_name = Variant::get_type_name(base_type.builtin_type);
3267 r_result.class_member = p_symbol;
3268 return OK;
3269 }
3270
3271 Variant v;
3272 REF v_ref;
3273 if (base_type.builtin_type == Variant::OBJECT) {
3274 v_ref.instance();
3275 v = v_ref;
3276 } else {
3277 Variant::CallError err;
3278 v = Variant::construct(base_type.builtin_type, NULL, 0, err);
3279 if (err.error != Variant::CallError::CALL_OK) {
3280 break;
3281 }
3282 }
3283
3284 if (v.has_method(p_symbol)) {
3285 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
3286 r_result.class_name = Variant::get_type_name(base_type.builtin_type);
3287 r_result.class_member = p_symbol;
3288 return OK;
3289 }
3290
3291 bool valid = false;
3292 v.get(p_symbol, &valid);
3293 if (valid) {
3294 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
3295 r_result.class_name = Variant::get_type_name(base_type.builtin_type);
3296 r_result.class_member = p_symbol;
3297 return OK;
3298 }
3299 } break;
3300 default: {
3301 base_type.has_type = false;
3302 } break;
3303 }
3304 }
3305
3306 return ERR_CANT_RESOLVE;
3307 }
3308
lookup_code(const String & p_code,const String & p_symbol,const String & p_path,Object * p_owner,LookupResult & r_result)3309 Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) {
3310
3311 //before parsing, try the usual stuff
3312 if (ClassDB::class_exists(p_symbol)) {
3313 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
3314 r_result.class_name = p_symbol;
3315 return OK;
3316 } else {
3317 String under_prefix = "_" + p_symbol;
3318 if (ClassDB::class_exists(under_prefix)) {
3319 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
3320 r_result.class_name = p_symbol;
3321 return OK;
3322 }
3323 }
3324
3325 for (int i = 0; i < Variant::VARIANT_MAX; i++) {
3326 Variant::Type t = Variant::Type(i);
3327 if (Variant::get_type_name(t) == p_symbol) {
3328 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
3329 r_result.class_name = Variant::get_type_name(t);
3330 return OK;
3331 }
3332 }
3333
3334 for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
3335 if (GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)) == p_symbol) {
3336 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
3337 r_result.class_name = "@GDScript";
3338 r_result.class_member = p_symbol;
3339 return OK;
3340 }
3341 }
3342
3343 if ("PI" == p_symbol || "TAU" == p_symbol || "INF" == p_symbol || "NAN" == p_symbol) {
3344 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
3345 r_result.class_name = "@GDScript";
3346 r_result.class_member = p_symbol;
3347 return OK;
3348 }
3349
3350 GDScriptParser parser;
3351 parser.parse(p_code, p_path.get_base_dir(), false, p_path, true);
3352
3353 if (parser.get_completion_type() == GDScriptParser::COMPLETION_NONE) {
3354 return ERR_CANT_RESOLVE;
3355 }
3356
3357 GDScriptCompletionContext context;
3358 context._class = parser.get_completion_class();
3359 context.function = parser.get_completion_function();
3360 context.block = parser.get_completion_block();
3361 context.line = parser.get_completion_line();
3362 context.base = p_owner;
3363 context.base_path = p_path.get_base_dir();
3364
3365 if (context._class && context._class->extends_class.size() > 0) {
3366 bool success = false;
3367 ClassDB::get_integer_constant(context._class->extends_class[0], p_symbol, &success);
3368 if (success) {
3369 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
3370 r_result.class_name = context._class->extends_class[0];
3371 r_result.class_member = p_symbol;
3372 return OK;
3373 }
3374 }
3375
3376 bool is_function = false;
3377
3378 switch (parser.get_completion_type()) {
3379 case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
3380 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
3381 r_result.class_name = Variant::get_type_name(parser.get_completion_built_in_constant());
3382 r_result.class_member = p_symbol;
3383 return OK;
3384 } break;
3385 case GDScriptParser::COMPLETION_PARENT_FUNCTION:
3386 case GDScriptParser::COMPLETION_FUNCTION: {
3387 is_function = true;
3388 FALLTHROUGH;
3389 }
3390 case GDScriptParser::COMPLETION_IDENTIFIER: {
3391
3392 if (!is_function) {
3393 is_function = parser.get_completion_identifier_is_function();
3394 }
3395
3396 GDScriptParser::DataType base_type;
3397 if (context._class) {
3398 if (parser.get_completion_type() != GDScriptParser::COMPLETION_PARENT_FUNCTION) {
3399 base_type.has_type = true;
3400 base_type.kind = GDScriptParser::DataType::CLASS;
3401 base_type.class_type = const_cast<GDScriptParser::ClassNode *>(context._class);
3402 } else {
3403 base_type = context._class->base_type;
3404 }
3405 } else {
3406 break;
3407 }
3408
3409 if (!is_function && context.block) {
3410 // Lookup local variables
3411 const GDScriptParser::BlockNode *block = context.block;
3412 while (block) {
3413 if (block->variables.has(p_symbol)) {
3414 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3415 r_result.location = block->variables[p_symbol]->line;
3416 return OK;
3417 }
3418 block = block->parent_block;
3419 }
3420 }
3421
3422 if (context.function && context.function->name != StringName()) {
3423 // Lookup function arguments
3424 for (int i = 0; i < context.function->arguments.size(); i++) {
3425 if (context.function->arguments[i] == p_symbol) {
3426 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3427 r_result.location = context.function->line;
3428 return OK;
3429 }
3430 }
3431 }
3432
3433 if (_lookup_symbol_from_base(base_type, p_symbol, is_function, r_result) == OK) {
3434 return OK;
3435 }
3436
3437 if (!is_function) {
3438 // Guess in autoloads as singletons
3439 List<PropertyInfo> props;
3440 ProjectSettings::get_singleton()->get_property_list(&props);
3441
3442 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
3443
3444 String s = E->get().name;
3445 if (!s.begins_with("autoload/"))
3446 continue;
3447 String name = s.get_slice("/", 1);
3448 if (name == String(p_symbol)) {
3449
3450 String path = ProjectSettings::get_singleton()->get(s);
3451 if (path.begins_with("*")) {
3452 String script = path.substr(1, path.length());
3453
3454 if (!script.ends_with(".gd")) {
3455 // Not a script, try find the script anyway,
3456 // may have some success
3457 script = script.get_basename() + ".gd";
3458 }
3459
3460 if (FileAccess::exists(script)) {
3461
3462 r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
3463 r_result.location = 0;
3464 r_result.script = ResourceLoader::load(script);
3465 return OK;
3466 }
3467 }
3468 }
3469 }
3470
3471 // Global
3472 Map<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map();
3473 if (classes.has(p_symbol)) {
3474 Variant value = GDScriptLanguage::get_singleton()->get_global_array()[classes[p_symbol]];
3475 if (value.get_type() == Variant::OBJECT) {
3476 Object *obj = value;
3477 if (obj) {
3478 if (Object::cast_to<GDScriptNativeClass>(obj)) {
3479 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
3480 r_result.class_name = Object::cast_to<GDScriptNativeClass>(obj)->get_name();
3481 } else {
3482 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
3483 r_result.class_name = obj->get_class();
3484 }
3485
3486 // proxy class remove the underscore.
3487 if (r_result.class_name.begins_with("_")) {
3488 r_result.class_name = r_result.class_name.right(1);
3489 }
3490 return OK;
3491 }
3492 } else {
3493 /*
3494 // Because get_integer_constant_enum and get_integer_constant don't work on @GlobalScope
3495 // We cannot determine the exact nature of the identifier here
3496 // Otherwise these codes would work
3497 StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true);
3498 if (enumName != NULL) {
3499 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM;
3500 r_result.class_name = "@GlobalScope";
3501 r_result.class_member = enumName;
3502 return OK;
3503 }
3504 else {
3505 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
3506 r_result.class_name = "@GlobalScope";
3507 r_result.class_member = p_symbol;
3508 return OK;
3509 }*/
3510 r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE;
3511 r_result.class_name = "@GlobalScope";
3512 r_result.class_member = p_symbol;
3513 return OK;
3514 }
3515 }
3516 }
3517 } break;
3518 case GDScriptParser::COMPLETION_METHOD: {
3519 is_function = true;
3520 FALLTHROUGH;
3521 }
3522 case GDScriptParser::COMPLETION_INDEX: {
3523 const GDScriptParser::Node *node = parser.get_completion_node();
3524 if (node->type != GDScriptParser::Node::TYPE_OPERATOR) {
3525 break;
3526 }
3527 GDScriptCompletionIdentifier base;
3528 if (!_guess_expression_type(context, static_cast<const GDScriptParser::OperatorNode *>(node)->arguments[0], base)) {
3529 break;
3530 }
3531
3532 if (_lookup_symbol_from_base(base.type, p_symbol, is_function, r_result) == OK) {
3533 return OK;
3534 }
3535 } break;
3536 case GDScriptParser::COMPLETION_VIRTUAL_FUNC: {
3537 GDScriptParser::DataType base_type = context._class->base_type;
3538
3539 if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) {
3540 return OK;
3541 }
3542 } break;
3543 case GDScriptParser::COMPLETION_TYPE_HINT: {
3544
3545 GDScriptParser::DataType base_type = context._class->base_type;
3546 base_type.has_type = true;
3547 base_type.kind = GDScriptParser::DataType::CLASS;
3548 base_type.class_type = const_cast<GDScriptParser::ClassNode *>(context._class);
3549
3550 if (_lookup_symbol_from_base(base_type, p_symbol, false, r_result) == OK) {
3551 return OK;
3552 }
3553 } break;
3554 default: {
3555 }
3556 }
3557
3558 return ERR_CANT_RESOLVE;
3559 }
3560
3561 #endif
3562