diff options
Diffstat (limited to 'modules/gdscript/gdscript_editor.cpp')
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 239015060e..aec05b6771 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -483,6 +483,8 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na #ifdef TOOLS_ENABLED +#define COMPLETION_RECURSION_LIMIT 200 + struct GDScriptCompletionIdentifier { GDScriptParser::DataType type; String enumeration; @@ -766,9 +768,11 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, } } -static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result); +static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth); + +static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) { + ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT); -static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) { if (!p_parent_only) { bool outer = false; const GDScriptParser::ClassNode *clss = p_class; @@ -788,6 +792,9 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, continue; } option = ScriptCodeCompletionOption(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT); + if (member.constant->initializer) { + option.default_value = member.constant->initializer->reduced_value; + } break; case GDScriptParser::ClassNode::Member::CLASS: if (p_only_functions) { @@ -820,7 +827,6 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, break; case GDScriptParser::ClassNode::Member::SIGNAL: if (p_only_functions || outer) { - clss = clss->outer; continue; } option = ScriptCodeCompletionOption(member.signal->identifier->name, ScriptCodeCompletionOption::KIND_SIGNAL); @@ -840,10 +846,12 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, base_type.type = p_class->base_type; base_type.type.is_meta_type = p_static; - _find_identifiers_in_base(base_type, p_only_functions, r_result); + _find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1); } -static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { +static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) { + ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT); + GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; @@ -856,7 +864,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base while (!base_type.has_no_type()) { switch (base_type.kind) { case GDScriptParser::DataType::CLASS: { - _find_identifiers_in_class(base_type.class_type, p_only_functions, _static, false, r_result); + _find_identifiers_in_class(base_type.class_type, p_only_functions, _static, false, r_result, p_recursion_depth + 1); // This already finds all parent identifiers, so we are done. base_type = GDScriptParser::DataType(); } break; @@ -1007,14 +1015,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } } -static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { +static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) { if (!p_only_functions && p_context.current_suite) { // This includes function parameters, since they are also locals. _find_identifiers_in_suite(p_context.current_suite, r_result); } if (p_context.current_class) { - _find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result); + _find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth + 1); } for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { @@ -1259,8 +1267,10 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, GDScriptParser::CompletionContext c = p_context; c.current_line = call->start_line; + GDScriptParser::Node::Type callee_type = call->get_callee_type(); + GDScriptCompletionIdentifier base; - if (call->callee->type == GDScriptParser::Node::IDENTIFIER || call->is_super) { + if (callee_type == GDScriptParser::Node::IDENTIFIER || call->is_super) { // Simple call, so base is 'self'. if (p_context.current_class) { base.type.kind = GDScriptParser::DataType::CLASS; @@ -1271,7 +1281,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } else { break; } - } else if (call->callee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->is_attribute) { + } else if (callee_type == GDScriptParser::Node::SUBSCRIPT && static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->is_attribute) { if (!_guess_expression_type(c, static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->base, base)) { found = false; break; @@ -2290,6 +2300,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c GDScriptParser::DataType base_type; bool _static = false; const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call); + GDScriptParser::Node::Type callee_type = GDScriptParser::Node::NONE; GDScriptCompletionIdentifier connect_base; @@ -2319,14 +2330,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c i++; } return; - } else if (call->is_super || call->callee->type == GDScriptParser::Node::IDENTIFIER) { + } else if (call->is_super || callee_type == GDScriptParser::Node::IDENTIFIER) { base = p_context.base; if (p_context.current_class) { base_type = p_context.current_class->get_datatype(); _static = !p_context.current_function || p_context.current_function->is_static; } - } else if (call->callee->type == GDScriptParser::Node::SUBSCRIPT) { + } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) { const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee); if (subscript->is_attribute) { @@ -2396,6 +2407,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path Variant::get_constants_for_type(completion_context.builtin_type, &constants); for (const List<StringName>::Element *E = constants.front(); E != nullptr; E = E->next()) { ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + bool valid = false; + Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E->get(), &valid); + if (valid) { + option.default_value = default_value; + } options.insert(option.display, option); } } break; @@ -2450,7 +2466,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path break; } if (!_guess_expression_type(completion_context, static_cast<const GDScriptParser::AssignmentNode *>(completion_context.node)->assignee, type)) { - _find_identifiers(completion_context, false, options); + _find_identifiers(completion_context, false, options, 0); r_forced = true; break; } @@ -2459,7 +2475,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path _find_enumeration_candidates(completion_context, type.enumeration, options); r_forced = options.size() > 0; } else { - _find_identifiers(completion_context, false, options); + _find_identifiers(completion_context, false, options, 0); r_forced = true; } } break; @@ -2467,7 +2483,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path is_function = true; [[fallthrough]]; case GDScriptParser::COMPLETION_IDENTIFIER: { - _find_identifiers(completion_context, is_function, options); + _find_identifiers(completion_context, is_function, options, 0); } break; case GDScriptParser::COMPLETION_ATTRIBUTE_METHOD: is_function = true; @@ -2481,7 +2497,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path break; } - _find_identifiers_in_base(base, is_function, options); + _find_identifiers_in_base(base, is_function, options, 0); } } break; case GDScriptParser::COMPLETION_SUBSCRIPT: { @@ -2501,7 +2517,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path c.current_class = nullptr; } - _find_identifiers_in_base(base, false, options); + _find_identifiers_in_base(base, false, options, 0); } break; case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: { if (!completion_context.current_class) { @@ -2527,7 +2543,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path // TODO: Improve this to only list types. if (found) { - _find_identifiers_in_base(base, false, options); + _find_identifiers_in_base(base, false, options, 0); } r_forced = true; } break; @@ -2648,7 +2664,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path if (!completion_context.current_class) { break; } - _find_identifiers_in_class(completion_context.current_class, true, false, true, options); + _find_identifiers_in_class(completion_context.current_class, true, false, true, options, 0); } break; } @@ -2762,6 +2778,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co if (base_type.class_type->has_member(p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; r_result.location = base_type.class_type->get_member(p_symbol).get_line(); + return OK; } base_type = base_type.class_type->base_type; } |