From 8a13be50abe929b1905b5e5ef72b199b60de13c3 Mon Sep 17 00:00:00 2001 From: Stephen Nichols Date: Wed, 5 Aug 2020 14:41:46 -0500 Subject: [PATCH] Fixing null callee crash. --- modules/gdscript/gdscript_analyzer.cpp | 22 ++++++++++++---------- modules/gdscript/gdscript_editor.cpp | 11 +++++++---- modules/gdscript/gdscript_parser.cpp | 4 +++- modules/gdscript/gdscript_parser.h | 8 ++++++++ 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 531666bec54..5b9a7e8a481 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -872,7 +872,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { // Use int, Vector2, Vector3 instead, which also can be used as range iterators. if (p_for->list && p_for->list->type == GDScriptParser::Node::CALL) { GDScriptParser::CallNode *call = static_cast(p_for->list); - if (call->callee->type == GDScriptParser::Node::IDENTIFIER) { + GDScriptParser::Node::Type callee_type = call->get_callee_type(); + if (callee_type == GDScriptParser::Node::IDENTIFIER) { GDScriptParser::IdentifierNode *callee = static_cast(call->callee); if (callee->name == "range") { list_resolved = true; @@ -1608,9 +1609,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa all_is_constant = all_is_constant && p_call->arguments[i]->is_constant; } + GDScriptParser::Node::Type callee_type = p_call->get_callee_type(); GDScriptParser::DataType call_type; - if (!p_call->is_super && p_call->callee->type == GDScriptParser::Node::IDENTIFIER) { + if (!p_call->is_super && callee_type == GDScriptParser::Node::IDENTIFIER) { // Call to name directly. StringName function_name = p_call->function_name; Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name); @@ -1785,10 +1787,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa if (p_call->is_super) { base_type = parser->current_class->base_type; is_self = true; - } else if (p_call->callee->type == GDScriptParser::Node::IDENTIFIER) { + } else if (callee_type == GDScriptParser::Node::IDENTIFIER) { base_type = parser->current_class->get_datatype(); is_self = true; - } else if (p_call->callee->type == GDScriptParser::Node::SUBSCRIPT) { + } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) { GDScriptParser::SubscriptNode *subscript = static_cast(p_call->callee); if (!subscript->is_attribute) { // Invalid call. Error already sent in parser. @@ -1825,9 +1827,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa } else { // Check if the name exists as something else. bool found = false; - if (!p_call->is_super) { + if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) { GDScriptParser::IdentifierNode *callee_id; - if (p_call->callee->type == GDScriptParser::Node::IDENTIFIER) { + if (callee_type == GDScriptParser::Node::IDENTIFIER) { callee_id = static_cast(p_call->callee); } else { // Can only be attribute. @@ -1835,13 +1837,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa } if (callee_id) { reduce_identifier_from_base(callee_id, &base_type); - GDScriptParser::DataType callee_type = callee_id->get_datatype(); - if (callee_type.is_set() && !callee_type.is_variant()) { + GDScriptParser::DataType callee_datatype = callee_id->get_datatype(); + if (callee_datatype.is_set() && !callee_datatype.is_variant()) { found = true; - if (callee_type.builtin_type == Variant::CALLABLE) { + if (callee_datatype.builtin_type == Variant::CALLABLE) { push_error(vformat(R"*(Name "%s" is a Callable. You can call it with "%s.call()" instead.)*", p_call->function_name, p_call->function_name), p_call->callee); } else { - push_error(vformat(R"*(Name "%s" called as a function but is a "%s".)*", p_call->function_name, callee_type.to_string()), p_call->callee); + push_error(vformat(R"*(Name "%s" called as a function but is a "%s".)*", p_call->function_name, callee_datatype.to_string()), p_call->callee); } #ifdef DEBUG_ENABLED } else if (!is_self) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 239015060e0..1fdce6eeeb6 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1259,8 +1259,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 +1273,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } else { break; } - } else if (call->callee->type == GDScriptParser::Node::SUBSCRIPT && static_cast(call->callee)->is_attribute) { + } else if (callee_type == GDScriptParser::Node::SUBSCRIPT && static_cast(call->callee)->is_attribute) { if (!_guess_expression_type(c, static_cast(call->callee)->base, base)) { found = false; break; @@ -2290,6 +2292,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c GDScriptParser::DataType base_type; bool _static = false; const GDScriptParser::CallNode *call = static_cast(p_call); + GDScriptParser::Node::Type callee_type = GDScriptParser::Node::NONE; GDScriptCompletionIdentifier connect_base; @@ -2319,14 +2322,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(call->callee); if (subscript->is_attribute) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index af074577505..79dc0313f1b 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2419,7 +2419,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre } else { call->callee = p_previous_operand; - if (call->callee->type == Node::IDENTIFIER) { + if (call->callee == nullptr) { + push_error(R"*(Cannot call on an expression. Use ".call()" if it's a Callable.)*"); + } else if (call->callee->type == Node::IDENTIFIER) { call->function_name = static_cast(call->callee)->name; make_completion_context(COMPLETION_METHOD, call->callee); } else if (call->callee->type == Node::SUBSCRIPT) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index a741ae0cc7a..346895324a9 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -383,6 +383,14 @@ public: CallNode() { type = CALL; } + + Type get_callee_type() const { + if (callee == nullptr) { + return Type::NONE; + } else { + return callee->type; + } + } }; struct CastNode : public ExpressionNode {