Sfoglia il codice sorgente

GDScript: Make using return of void function an error

Remove the `VOID_ASSIGNMENT` warning since those cases will be errors
now.
George Marques 2 anni fa
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">
 			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 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;">
 			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>

+ 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();
 
-#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) {
 			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();
-
-#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) {
@@ -2333,9 +2321,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
 	}
 
 #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);
 	}
 #endif
@@ -2650,6 +2636,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 		} else if (GDScriptUtilityFunctions::function_exists(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)) {
 				// Can call on compilation.
 				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)) {
 			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) {
 				// Can call on compilation.
 				Vector<const Variant *> args;
@@ -2835,6 +2829,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 			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
 		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);

+ 0 - 5
modules/gdscript/gdscript_warning.cpp

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

+ 0 - 1
modules/gdscript/gdscript_warning.h

@@ -57,7 +57,6 @@ public:
 		UNREACHABLE_CODE, // Code after a return statement.
 		UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
 		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.
 		INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible.
 		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.