Merge pull request #75988 from dalexeev/gds-unsafe-call-argument

GDScript: Improve call analysis
This commit is contained in:
Yuri Sizov
2023-09-27 19:07:46 +02:00
25 changed files with 184 additions and 46 deletions

View File

@@ -0,0 +1,7 @@
# GH-73283
class MyClass:
pass
func test():
MyClass.not_existing_method()

View File

@@ -0,0 +1,2 @@
GDTEST_ANALYZER_ERROR
Static function "not_existing_method()" not found in base "MyClass".

View File

@@ -0,0 +1,4 @@
# GH-73213
func test():
print(Object())

View File

@@ -0,0 +1,2 @@
GDTEST_ANALYZER_ERROR
Invalid constructor "Object()", use "Object.new()" instead.

View File

@@ -23,6 +23,7 @@ func test() -> void:
typed = variant()
inferred = variant()
@warning_ignore("unsafe_call_argument") # TODO: Hard vs Weak vs Unknown.
param_weak(typed)
param_typed(typed)
param_inferred(typed)

View File

@@ -6,10 +6,12 @@ var prop = null
func check_arg(arg = null) -> void:
if arg != null:
@warning_ignore("unsafe_call_argument")
print(check(arg))
func check_recur() -> void:
if recur != null:
@warning_ignore("unsafe_call_argument")
print(check(recur))
else:
recur = 1
@@ -22,11 +24,13 @@ func test() -> void:
if prop == null:
set('prop', 1)
@warning_ignore("unsafe_call_argument")
print(check(prop))
set('prop', null)
var loop = null
while loop != 2:
if loop != null:
@warning_ignore("unsafe_call_argument")
print(check(loop))
loop = 1 if loop == null else 2

View File

@@ -14,4 +14,5 @@ func test():
func do_add_node():
var node = Node.new()
node.name = "Node"
@warning_ignore("unsafe_call_argument")
add_child(node)

View File

@@ -0,0 +1,37 @@
func variant_func(x: Variant) -> void:
print(x)
func int_func(x: int) -> void:
print(x)
func float_func(x: float) -> void:
print(x)
# We don't want to execute it because of errors, just analyze.
func no_exec_test():
var untyped_int = 42
var untyped_string = "abc"
var variant_int: Variant = 42
var variant_string: Variant = "abc"
var typed_int: int = 42
variant_func(untyped_int) # No warning.
variant_func(untyped_string) # No warning.
variant_func(variant_int) # No warning.
variant_func(variant_string) # No warning.
variant_func(typed_int) # No warning.
int_func(untyped_int)
int_func(untyped_string)
int_func(variant_int)
int_func(variant_string)
int_func(typed_int) # No warning.
float_func(untyped_int)
float_func(untyped_string)
float_func(variant_int)
float_func(variant_string)
float_func(typed_int) # No warning.
func test():
pass

View File

@@ -0,0 +1,33 @@
GDTEST_OK
>> WARNING
>> Line: 24
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
>> WARNING
>> Line: 25
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
>> WARNING
>> Line: 26
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
>> WARNING
>> Line: 27
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
>> WARNING
>> Line: 30
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
>> WARNING
>> Line: 31
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
>> WARNING
>> Line: 32
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
>> WARNING
>> Line: 33
>> UNSAFE_CALL_ARGUMENT
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.

View File

@@ -3,27 +3,32 @@ extends Node
func test():
var child = Node.new()
child.name = "Child"
@warning_ignore("unsafe_call_argument")
add_child(child)
child.owner = self
var hey = Node.new()
hey.name = "Hey"
@warning_ignore("unsafe_call_argument")
child.add_child(hey)
hey.owner = self
hey.unique_name_in_owner = true
var fake_hey = Node.new()
fake_hey.name = "Hey"
@warning_ignore("unsafe_call_argument")
add_child(fake_hey)
fake_hey.owner = self
var sub_child = Node.new()
sub_child.name = "SubChild"
@warning_ignore("unsafe_call_argument")
hey.add_child(sub_child)
sub_child.owner = self
var howdy = Node.new()
howdy.name = "Howdy"
@warning_ignore("unsafe_call_argument")
sub_child.add_child(howdy)
howdy.owner = self
howdy.unique_name_in_owner = true

View File

@@ -5,9 +5,11 @@ func test():
# Create the required node structure.
var hello = Node.new()
hello.name = "Hello"
@warning_ignore("unsafe_call_argument")
add_child(hello)
var world = Node.new()
world.name = "World"
@warning_ignore("unsafe_call_argument")
hello.add_child(world)
# All the ways of writing node paths below with the `$` operator are valid.

View File

@@ -26,6 +26,7 @@ func test():
if true: (v as Callable).call()
print()
@warning_ignore("unsafe_call_argument")
other(v)
print()

View File

@@ -2,4 +2,5 @@ func foo(x):
return x + 1
func test():
@warning_ignore("unsafe_call_argument")
print(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(0)))))))))))))))))))))))))

View File

@@ -36,6 +36,7 @@ class SayNothing extends Say:
print("howdy, see above")
func say(name):
@warning_ignore("unsafe_call_argument")
super(name + " super'd")
print(prefix, " say nothing... or not? ", name)

View File

@@ -29,6 +29,7 @@ func test():
const d = 1.1
_process(d)
@warning_ignore("unsafe_call_argument")
print(is_equal_approx(, PI + (d * PI)))
func _process(Δ: float) -> void:

View File

@@ -0,0 +1,6 @@
# GH-73213
func test():
var object := Object.new() # Not `Object()`.
print(object.get_class())
object.free()

View File

@@ -0,0 +1,2 @@
GDTEST_OK
Object

View File

@@ -12,6 +12,7 @@ func test():
print("end")
func test_construct(v, f):
@warning_ignore("unsafe_call_argument")
Vector2(v, v) # Built-in type construct.
assert(not f) # Test unary operator reading from `nil`.

View File

@@ -44,6 +44,7 @@ func test():
@warning_ignore("unsafe_method_access")
var path = get_script().get_path().get_base_dir()
@warning_ignore("unsafe_call_argument")
var other = load(path + "/static_variables_load.gd")
prints("load.perm:", other.perm)

View File

@@ -24,7 +24,8 @@ func test():
print(StringName("hello"))
print(NodePath("hello/world"))
var node := Node.new()
print(RID(node))
@warning_ignore("unsafe_call_argument")
print(RID(node)) # TODO: Why is the constructor (or implicit cast) not documented?
print(node.get_name)
print(node.property_list_changed)
node.free()