diff options
Diffstat (limited to 'modules/gdscript/gdscript_editor.cpp')
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 8cfd48b52b..63dfd4d27c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1353,6 +1353,21 @@ static GDScriptCompletionIdentifier _type_from_property(const PropertyInfo &p_pr return ci; } +#define MAX_COMPLETION_RECURSION 100 +struct RecursionCheck { + int *counter; + _FORCE_INLINE_ bool check() { + return (*counter) > MAX_COMPLETION_RECURSION; + } + RecursionCheck(int *p_counter) : + counter(p_counter) { + (*counter)++; + } + ~RecursionCheck() { + (*counter)--; + } +}; + static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); @@ -1385,6 +1400,12 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, return false; } + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + if (p_expression->is_constant) { // Already has a value, so just use that. r_type = _type_from_variant(p_expression->reduced_value); @@ -1855,6 +1876,12 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + // Look in blocks first. int last_assign_line = -1; const GDScriptParser::ExpressionNode *last_assigned_expression = nullptr; @@ -1918,21 +1945,19 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } } - if (suite->parent_if && suite->parent_if->condition && suite->parent_if->condition->type == GDScriptParser::Node::BINARY_OPERATOR && static_cast<const GDScriptParser::BinaryOpNode *>(suite->parent_if->condition)->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { + if (suite->parent_if && suite->parent_if->condition && suite->parent_if->condition->type == GDScriptParser::Node::TYPE_TEST) { // Operator `is` used, check if identifier is in there! this helps resolve in blocks that are (if (identifier is value)): which are very common.. // Super dirty hack, but very useful. // Credit: Zylann. // TODO: this could be hacked to detect ANDed conditions too... - const GDScriptParser::BinaryOpNode *op = static_cast<const GDScriptParser::BinaryOpNode *>(suite->parent_if->condition); - if (op->left_operand && op->right_operand && op->left_operand->type == GDScriptParser::Node::IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(op->left_operand)->name == p_identifier) { + const GDScriptParser::TypeTestNode *type_test = static_cast<const GDScriptParser::TypeTestNode *>(suite->parent_if->condition); + if (type_test->operand && type_test->test_type && type_test->operand->type == GDScriptParser::Node::IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(type_test->operand)->name == p_identifier) { // Bingo. GDScriptParser::CompletionContext c = p_context; - c.current_line = op->left_operand->start_line; + c.current_line = type_test->operand->start_line; c.current_suite = suite; - GDScriptCompletionIdentifier is_type; - if (_guess_expression_type(c, op->right_operand, is_type)) { - id_type = is_type.type; - id_type.is_meta_type = false; + if ((!id_type.is_set() || id_type.is_variant()) && type_test->test_datatype.is_hard_type()) { + id_type = type_test->test_datatype; if (last_assign_line < c.current_line) { // Override last assignment. last_assign_line = c.current_line; @@ -2074,6 +2099,12 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + GDScriptParser::DataType base_type = p_base.type; bool is_static = base_type.is_meta_type; while (base_type.is_set()) { @@ -2287,6 +2318,12 @@ static void _find_last_return_in_block(GDScriptParser::CompletionContext &p_cont } static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { + static int recursion_depth = 0; + RecursionCheck recursion(&recursion_depth); + if (unlikely(recursion.check())) { + ERR_FAIL_V_MSG(false, "Reached recursion limit while trying to guess type."); + } + GDScriptParser::DataType base_type = p_base.type; bool is_static = base_type.is_meta_type; |