2
0
Эх сурвалжийг харах

GDScript: Make using return of void function an error

Remove the `VOID_ASSIGNMENT` warning since those cases will be errors
now.
George Marques 2 жил өмнө
parent
commit
bc739a4687

+ 0 - 3
doc/classes/ProjectSettings.xml

@@ -464,9 +464,6 @@
 		<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1">
 		<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1">
 			When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused.
 			When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused.
 		</member>
 		</member>
-		<member name="debug/gdscript/warnings/void_assignment" type="int" setter="" getter="" default="1">
-			When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when assigning the result of a function that returns [code]void[/code] to a variable.
-		</member>
 		<member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug to the project developer.&quot;">
 		<member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug to the project developer.&quot;">
 			Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting.
 			Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting.
 		</member>
 		</member>

+ 13 - 15
modules/gdscript/gdscript_analyzer.cpp

@@ -1748,12 +1748,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
 
 
 		type = p_variable->initializer->get_datatype();
 		type = p_variable->initializer->get_datatype();
 
 
-#ifdef DEBUG_ENABLED
-		if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
-			parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name);
-		}
-#endif
-
 		if (p_variable->infer_datatype) {
 		if (p_variable->infer_datatype) {
 			type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
 			type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
 
 
@@ -1843,12 +1837,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
 		}
 		}
 
 
 		type = p_constant->initializer->get_datatype();
 		type = p_constant->initializer->get_datatype();
-
-#ifdef DEBUG_ENABLED
-		if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) {
-			parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name);
-		}
-#endif
 	}
 	}
 
 
 	if (p_constant->datatype_specifier != nullptr) {
 	if (p_constant->datatype_specifier != nullptr) {
@@ -2333,9 +2321,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
 	}
 	}
 
 
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
-	if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.is_hard_type() && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) {
-		parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name);
-	} else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
+	if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
 		parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION);
 		parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION);
 	}
 	}
 #endif
 #endif
@@ -2650,6 +2636,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 		} else if (GDScriptUtilityFunctions::function_exists(function_name)) {
 		} else if (GDScriptUtilityFunctions::function_exists(function_name)) {
 			MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
 			MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name);
 
 
+			if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) {
+				push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call);
+			}
+
 			if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
 			if (all_is_constant && GDScriptUtilityFunctions::is_function_constant(function_name)) {
 				// Can call on compilation.
 				// Can call on compilation.
 				Vector<const Variant *> args;
 				Vector<const Variant *> args;
@@ -2693,6 +2683,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 		} else if (Variant::has_utility_function(function_name)) {
 		} else if (Variant::has_utility_function(function_name)) {
 			MethodInfo function_info = info_from_utility_func(function_name);
 			MethodInfo function_info = info_from_utility_func(function_name);
 
 
+			if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) {
+				push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call);
+			}
+
 			if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
 			if (all_is_constant && Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH) {
 				// Can call on compilation.
 				// Can call on compilation.
 				Vector<const Variant *> args;
 				Vector<const Variant *> args;
@@ -2835,6 +2829,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 			mark_lambda_use_self();
 			mark_lambda_use_self();
 		}
 		}
 
 
+		if (!p_is_root && return_type.is_hard_type() && return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) {
+			push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", p_call->function_name), p_call);
+		}
+
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 		if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
 		if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
 			parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
 			parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);

+ 0 - 5
modules/gdscript/gdscript_warning.cpp

@@ -80,10 +80,6 @@ String GDScriptWarning::get_message() const {
 		case STANDALONE_EXPRESSION: {
 		case STANDALONE_EXPRESSION: {
 			return "Standalone expression (the line has no effect).";
 			return "Standalone expression (the line has no effect).";
 		} break;
 		} break;
-		case VOID_ASSIGNMENT: {
-			CHECK_SYMBOLS(1);
-			return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
-		} break;
 		case NARROWING_CONVERSION: {
 		case NARROWING_CONVERSION: {
 			return "Narrowing conversion (float is converted to int and loses precision).";
 			return "Narrowing conversion (float is converted to int and loses precision).";
 		} break;
 		} break;
@@ -202,7 +198,6 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
 		"UNREACHABLE_CODE",
 		"UNREACHABLE_CODE",
 		"UNREACHABLE_PATTERN",
 		"UNREACHABLE_PATTERN",
 		"STANDALONE_EXPRESSION",
 		"STANDALONE_EXPRESSION",
-		"VOID_ASSIGNMENT",
 		"NARROWING_CONVERSION",
 		"NARROWING_CONVERSION",
 		"INCOMPATIBLE_TERNARY",
 		"INCOMPATIBLE_TERNARY",
 		"UNUSED_SIGNAL",
 		"UNUSED_SIGNAL",

+ 0 - 1
modules/gdscript/gdscript_warning.h

@@ -57,7 +57,6 @@ public:
 		UNREACHABLE_CODE, // Code after a return statement.
 		UNREACHABLE_CODE, // Code after a return statement.
 		UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
 		UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
 		STANDALONE_EXPRESSION, // Expression not assigned to a variable.
 		STANDALONE_EXPRESSION, // Expression not assigned to a variable.
-		VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable.
 		NARROWING_CONVERSION, // Float value into an integer slot, precision is lost.
 		NARROWING_CONVERSION, // Float value into an integer slot, precision is lost.
 		INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible.
 		INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible.
 		UNUSED_SIGNAL, // Signal is defined but never emitted.
 		UNUSED_SIGNAL, // Signal is defined but never emitted.

+ 3 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.gd

@@ -0,0 +1,3 @@
+func test():
+	var builtin := []
+	print(builtin.reverse()) # Built-in type method.

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_builtin_method.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "reverse()" because it returns "void".

+ 5 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.gd

@@ -0,0 +1,5 @@
+func foo() -> void:
+	pass
+
+func test():
+	print(foo()) # Custom method.

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_custom_method.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "foo()" because it returns "void".

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.gd

@@ -0,0 +1,2 @@
+func test():
+	print(print_debug()) # GDScript utility function.

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_gd_utility.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "print_debug()" because it returns "void".

+ 3 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.gd

@@ -0,0 +1,3 @@
+func test():
+	var obj := Node.new()
+	print(obj.free()) # Native type method.

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_native_method.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "free()" because it returns "void".

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.gd

@@ -0,0 +1,2 @@
+func test():
+	print(print()) # Built-in utility function.

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/use_value_of_void_function_utility.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get return value of call to "print()" because it returns "void".

+ 0 - 6
modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd

@@ -1,6 +0,0 @@
-func i_return_void() -> void:
-	return
-
-
-func test():
-	var __ = i_return_void()

+ 0 - 5
modules/gdscript/tests/scripts/parser/warnings/void_assignment.out

@@ -1,5 +0,0 @@
-GDTEST_OK
->> WARNING
->> Line: 6
->> VOID_ASSIGNMENT
->> Assignment operation, but the function 'i_return_void()' returns void.