소스 검색

Merge pull request #41055 from snichols/null-callee-fix

Fix crash with null callee
Rémi Verschelde 5 년 전
부모
커밋
cf05486d8e
4개의 변경된 파일35개의 추가작업 그리고 16개의 파일을 삭제
  1. 12 10
      modules/gdscript/gdscript_analyzer.cpp
  2. 7 4
      modules/gdscript/gdscript_editor.cpp
  3. 8 2
      modules/gdscript/gdscript_parser.cpp
  4. 8 0
      modules/gdscript/gdscript_parser.h

+ 12 - 10
modules/gdscript/gdscript_analyzer.cpp

@@ -876,7 +876,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
 	// Use int, Vector2, Vector3 instead, which also can be used as range iterators.
 	// Use int, Vector2, Vector3 instead, which also can be used as range iterators.
 	if (p_for->list && p_for->list->type == GDScriptParser::Node::CALL) {
 	if (p_for->list && p_for->list->type == GDScriptParser::Node::CALL) {
 		GDScriptParser::CallNode *call = static_cast<GDScriptParser::CallNode *>(p_for->list);
 		GDScriptParser::CallNode *call = static_cast<GDScriptParser::CallNode *>(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<GDScriptParser::IdentifierNode *>(call->callee);
 			GDScriptParser::IdentifierNode *callee = static_cast<GDScriptParser::IdentifierNode *>(call->callee);
 			if (callee->name == "range") {
 			if (callee->name == "range") {
 				list_resolved = true;
 				list_resolved = true;
@@ -1626,9 +1627,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
 		all_is_constant = all_is_constant && p_call->arguments[i]->is_constant;
 		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;
 	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.
 		// Call to name directly.
 		StringName function_name = p_call->function_name;
 		StringName function_name = p_call->function_name;
 		Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
 		Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
@@ -1803,10 +1805,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
 	if (p_call->is_super) {
 	if (p_call->is_super) {
 		base_type = parser->current_class->base_type;
 		base_type = parser->current_class->base_type;
 		is_self = true;
 		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();
 		base_type = parser->current_class->get_datatype();
 		is_self = true;
 		is_self = true;
-	} else if (p_call->callee->type == GDScriptParser::Node::SUBSCRIPT) {
+	} else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
 		GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(p_call->callee);
 		GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(p_call->callee);
 		if (!subscript->is_attribute) {
 		if (!subscript->is_attribute) {
 			// Invalid call. Error already sent in parser.
 			// Invalid call. Error already sent in parser.
@@ -1843,9 +1845,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
 	} else {
 	} else {
 		// Check if the name exists as something else.
 		// Check if the name exists as something else.
 		bool found = false;
 		bool found = false;
-		if (!p_call->is_super) {
+		if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) {
 			GDScriptParser::IdentifierNode *callee_id;
 			GDScriptParser::IdentifierNode *callee_id;
-			if (p_call->callee->type == GDScriptParser::Node::IDENTIFIER) {
+			if (callee_type == GDScriptParser::Node::IDENTIFIER) {
 				callee_id = static_cast<GDScriptParser::IdentifierNode *>(p_call->callee);
 				callee_id = static_cast<GDScriptParser::IdentifierNode *>(p_call->callee);
 			} else {
 			} else {
 				// Can only be attribute.
 				// Can only be attribute.
@@ -1853,13 +1855,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
 			}
 			}
 			if (callee_id) {
 			if (callee_id) {
 				reduce_identifier_from_base(callee_id, &base_type);
 				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;
 					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);
 						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 {
 					} 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
 #ifdef DEBUG_ENABLED
 				} else if (!is_self) {
 				} else if (!is_self) {

+ 7 - 4
modules/gdscript/gdscript_editor.cpp

@@ -1259,8 +1259,10 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
 					GDScriptParser::CompletionContext c = p_context;
 					GDScriptParser::CompletionContext c = p_context;
 					c.current_line = call->start_line;
 					c.current_line = call->start_line;
 
 
+					GDScriptParser::Node::Type callee_type = call->get_callee_type();
+
 					GDScriptCompletionIdentifier base;
 					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'.
 						// Simple call, so base is 'self'.
 						if (p_context.current_class) {
 						if (p_context.current_class) {
 							base.type.kind = GDScriptParser::DataType::CLASS;
 							base.type.kind = GDScriptParser::DataType::CLASS;
@@ -1271,7 +1273,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
 						} else {
 						} else {
 							break;
 							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)) {
 						if (!_guess_expression_type(c, static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->base, base)) {
 							found = false;
 							found = false;
 							break;
 							break;
@@ -2290,6 +2292,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
 	GDScriptParser::DataType base_type;
 	GDScriptParser::DataType base_type;
 	bool _static = false;
 	bool _static = false;
 	const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call);
 	const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call);
+	GDScriptParser::Node::Type callee_type = GDScriptParser::Node::NONE;
 
 
 	GDScriptCompletionIdentifier connect_base;
 	GDScriptCompletionIdentifier connect_base;
 
 
@@ -2319,14 +2322,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
 			i++;
 			i++;
 		}
 		}
 		return;
 		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;
 		base = p_context.base;
 
 
 		if (p_context.current_class) {
 		if (p_context.current_class) {
 			base_type = p_context.current_class->get_datatype();
 			base_type = p_context.current_class->get_datatype();
 			_static = !p_context.current_function || p_context.current_function->is_static;
 			_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);
 		const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
 
 
 		if (subscript->is_attribute) {
 		if (subscript->is_attribute) {

+ 8 - 2
modules/gdscript/gdscript_parser.cpp

@@ -2332,7 +2332,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
 GDScriptParser::ExpressionNode *GDScriptParser::parse_grouping(ExpressionNode *p_previous_operand, bool p_can_assign) {
 GDScriptParser::ExpressionNode *GDScriptParser::parse_grouping(ExpressionNode *p_previous_operand, bool p_can_assign) {
 	ExpressionNode *grouped = parse_expression(false);
 	ExpressionNode *grouped = parse_expression(false);
 	pop_multiline();
 	pop_multiline();
-	consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after grouping expression.)*");
+	if (grouped == nullptr) {
+		push_error(R"(Expected grouping expression.)");
+	} else {
+		consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after grouping expression.)*");
+	}
 	return grouped;
 	return grouped;
 }
 }
 
 
@@ -2423,7 +2427,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
 	} else {
 	} else {
 		call->callee = p_previous_operand;
 		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<IdentifierNode *>(call->callee)->name;
 			call->function_name = static_cast<IdentifierNode *>(call->callee)->name;
 			make_completion_context(COMPLETION_METHOD, call->callee);
 			make_completion_context(COMPLETION_METHOD, call->callee);
 		} else if (call->callee->type == Node::SUBSCRIPT) {
 		} else if (call->callee->type == Node::SUBSCRIPT) {

+ 8 - 0
modules/gdscript/gdscript_parser.h

@@ -383,6 +383,14 @@ public:
 		CallNode() {
 		CallNode() {
 			type = CALL;
 			type = CALL;
 		}
 		}
+
+		Type get_callee_type() const {
+			if (callee == nullptr) {
+				return Type::NONE;
+			} else {
+				return callee->type;
+			}
+		}
 	};
 	};
 
 
 	struct CastNode : public ExpressionNode {
 	struct CastNode : public ExpressionNode {