Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDScript: Fix UNSAFE_CAST warning #84043

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using an expression whose type may not be compatible with the function parameter expected.
</member>
<member name="debug/gdscript/warnings/unsafe_cast" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when performing an unsafe cast.
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a [Variant] value is cast to a non-Variant.
</member>
<member name="debug/gdscript/warnings/unsafe_method_access" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a method whose presence is not guaranteed at compile-time in the class.
Expand Down
4 changes: 1 addition & 3 deletions modules/gdscript/gdscript_analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3453,9 +3453,7 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {
if (op_type.is_variant() || !op_type.is_hard_type()) {
mark_node_unsafe(p_cast);
#ifdef DEBUG_ENABLED
if (op_type.is_variant() && !op_type.is_hard_type()) {
parser->push_warning(p_cast, GDScriptWarning::UNSAFE_CAST, cast_type.to_string());
}
parser->push_warning(p_cast, GDScriptWarning::UNSAFE_CAST, cast_type.to_string());
#endif
} else {
bool valid = false;
Expand Down
2 changes: 1 addition & 1 deletion modules/gdscript/gdscript_warning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ String GDScriptWarning::get_message() const {
return vformat(R"*(The method "%s()" is not present on the inferred type "%s" (but may be present on a subtype).)*", symbols[0], symbols[1]);
case UNSAFE_CAST:
CHECK_SYMBOLS(1);
return vformat(R"(The value is cast to "%s" but has an unknown type.)", symbols[0]);
return vformat(R"(Casting "Variant" to "%s" is unsafe.)", symbols[0]);
case UNSAFE_CALL_ARGUMENT:
CHECK_SYMBOLS(5);
return vformat(R"*(The argument %s of the %s "%s()" requires the subtype "%s" but the supertype "%s" was provided.)*", symbols[0], symbols[1], symbols[2], symbols[3], symbols[4]);
Expand Down
2 changes: 1 addition & 1 deletion modules/gdscript/gdscript_warning.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class GDScriptWarning {
INFERRED_DECLARATION, // Variable/constant/parameter has an implicitly inferred static type.
UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes).
UNSAFE_METHOD_ACCESS, // Function not found in the detected type (but can be in subtypes).
UNSAFE_CAST, // Cast used in an unknown type.
UNSAFE_CAST, // Casting a `Variant` value to non-`Variant`.
UNSAFE_CALL_ARGUMENT, // Function call argument is of a supertype of the required type.
UNSAFE_VOID_RETURN, // Function returns void but returned a call to a function that can't be type checked.
RETURN_VALUE_DISCARDED, // Function call returns something but the value isn't used.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func test():
var integer := 1
print(integer as Array)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GDTEST_ANALYZER_ERROR
Invalid cast. Cannot convert from "int" to "Array".
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func test():
var integer := 1
print(integer as Node)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GDTEST_ANALYZER_ERROR
Invalid cast. Cannot convert from "int" to "Node".
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func test():
var object := RefCounted.new()
print(object as int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GDTEST_ANALYZER_ERROR
Invalid cast. Cannot convert from "RefCounted" to "int".
24 changes: 24 additions & 0 deletions modules/gdscript/tests/scripts/analyzer/warnings/unsafe_cast.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# We don't want to execute it because of errors, just analyze.
func no_exec_test():
var weak_int = 1
print(weak_int as Variant) # No warning.
print(weak_int as int)
print(weak_int as Node)

var weak_node = Node.new()
print(weak_node as Variant) # No warning.
print(weak_node as int)
print(weak_node as Node)

var weak_variant = null
print(weak_variant as Variant) # No warning.
print(weak_variant as int)
print(weak_variant as Node)

var hard_variant: Variant = null
print(hard_variant as Variant) # No warning.
print(hard_variant as int)
print(hard_variant as Node)

func test():
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
GDTEST_OK
>> WARNING
>> Line: 5
>> UNSAFE_CAST
>> Casting "Variant" to "int" is unsafe.
>> WARNING
>> Line: 6
>> UNSAFE_CAST
>> Casting "Variant" to "Node" is unsafe.
>> WARNING
>> Line: 10
>> UNSAFE_CAST
>> Casting "Variant" to "int" is unsafe.
>> WARNING
>> Line: 11
>> UNSAFE_CAST
>> Casting "Variant" to "Node" is unsafe.
>> WARNING
>> Line: 15
>> UNSAFE_CAST
>> Casting "Variant" to "int" is unsafe.
>> WARNING
>> Line: 16
>> UNSAFE_CAST
>> Casting "Variant" to "Node" is unsafe.
>> WARNING
>> Line: 20
>> UNSAFE_CAST
>> Casting "Variant" to "int" is unsafe.
>> WARNING
>> Line: 21
>> UNSAFE_CAST
>> Casting "Variant" to "Node" is unsafe.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
func test():
var node := Node.new()
node.free()
print(node as Node2D)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GDTEST_RUNTIME_ERROR
>> SCRIPT ERROR
>> on function: test()
>> runtime/errors/cast_freed_object.gd
>> 4
>> Trying to cast a freed object.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
func test():
var integer: Variant = 1
@warning_ignore("unsafe_cast")
print(integer as Array)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GDTEST_RUNTIME_ERROR
>> SCRIPT ERROR
>> on function: test()
>> runtime/errors/cast_int_to_array.gd
>> 4
>> Invalid cast: could not convert value to 'Array'.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
func test():
var integer: Variant = 1
@warning_ignore("unsafe_cast")
print(integer as Node)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GDTEST_RUNTIME_ERROR
>> SCRIPT ERROR
>> on function: test()
>> runtime/errors/cast_int_to_object.gd
>> 4
>> Invalid cast: can't convert a non-object value to an object type.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
func test():
var object: Variant = RefCounted.new()
@warning_ignore("unsafe_cast")
print(object as int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GDTEST_RUNTIME_ERROR
>> SCRIPT ERROR
>> on function: test()
>> runtime/errors/cast_object_to_int.gd
>> 4
>> Invalid cast: could not convert value to 'int'.
24 changes: 24 additions & 0 deletions modules/gdscript/tests/scripts/runtime/features/type_casting.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
func print_value(value: Variant) -> void:
if value is Object:
@warning_ignore("unsafe_method_access")
print("<%s>" % value.get_class())
else:
print(var_to_str(value))

func test():
var int_value := 1
print_value(int_value as Variant)
print_value(int_value as int)
print_value(int_value as float)

var node_value := Node.new()
print_value(node_value as Variant)
print_value(node_value as Object)
print_value(node_value as Node)
print_value(node_value as Node2D)
node_value.free()

var null_value = null
print_value(null_value as Variant)
@warning_ignore("unsafe_cast")
print_value(null_value as Node)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
GDTEST_OK
1
1
1.0
<Node>
<Node>
<Node>
null
null
null