Skip to content

Commit cef1635

Browse files
unit tests
1 parent 1ac7fd8 commit cef1635

18 files changed

+78
-32
lines changed

doc/classes/ProjectSettings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,9 @@
545545
<member name="debug/gdscript/warnings/onready_with_export" type="int" setter="" getter="" default="2">
546546
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [code]@onready[/code] annotation is used together with the [code]@export[/code] annotation, since it may not behave as expected.
547547
</member>
548+
<member name="debug/gdscript/warnings/override_non_virtual_method" type="int" setter="" getter="" default="1">
549+
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a method tries to override the one that is not annotated by [code]@virtual[/code] in the super class, since such behavior will lead to unexpected and unsafe behaviors, unless you know what you are doing.
550+
</member>
548551
<member name="debug/gdscript/warnings/property_used_as_function" type="int" setter="" getter="" default="1" deprecated="This warning is never produced. Instead, an error is generated if the expression type is known at compile time.">
549552
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using a property as if it is a function.
550553
</member>

modules/gdscript/doc_classes/@GDScript.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,9 +797,24 @@
797797
print("A")
798798

799799
class B extends A:
800-
@func test():
800+
func test():
801801
print("B")
802802
[/codeblock]
803+
If a method is trying to override a non-virtual method, a warning (or an error) will be thrown.
804+
[codeblock]
805+
func _init():
806+
B.new().test() # Prints B, with a warning (or an error) about overriding a non-virtual method.
807+
808+
809+
class A:
810+
func test():
811+
print("A")
812+
813+
class B extends A:
814+
func test():
815+
print("B")
816+
[/codeblock]
817+
You can ignore the warning as long as you know what you are doing.
803818
</description>
804819
</annotation>
805820
<annotation name="@warning_ignore" qualifiers="vararg">

modules/gdscript/gdscript_analyzer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
18741874
if (base_type.class_type != nullptr && base_type.class_type->has_function(p_function->identifier->name)) {
18751875
GDScriptParser::FunctionNode *parent_func = base_type.class_type->get_member(p_function->identifier->name).function;
18761876
if (!parent_func->is_annotated_virtual) {
1877-
push_error(vformat(R"*(The function "%s()" is non-virtual and cannot be overridden.)*", p_function->identifier->name), p_function);
1877+
parser->push_warning(p_function, GDScriptWarning::OVERRIDE_NON_VIRTUAL_METHOD, function_name);
18781878
}
18791879
}
18801880

modules/gdscript/gdscript_warning.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ String GDScriptWarning::get_message() const {
162162
return vformat(R"*(The default value is using "%s" which won't return nodes in the scene tree before "_ready()" is called. Use the "@onready" annotation to solve this.)*", symbols[0]);
163163
case ONREADY_WITH_EXPORT:
164164
return R"("@onready" will set the default value after "@export" takes effect and will override it.)";
165+
case OVERRIDE_NON_VIRTUAL_METHOD:
166+
CHECK_SYMBOLS(1);
167+
return vformat(R"*(The method "%s()" overrides a non-virtual method from the base class. This may cause unexpected and unsafe behaviors.)*", symbols[0]);
165168
#ifndef DISABLE_DEPRECATED
166169
// Never produced. These warnings migrated from 3.x by mistake.
167170
case PROPERTY_USED_AS_FUNCTION: // There is already an error.
@@ -238,6 +241,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
238241
"NATIVE_METHOD_OVERRIDE",
239242
"GET_NODE_DEFAULT_WITHOUT_ONREADY",
240243
"ONREADY_WITH_EXPORT",
244+
"OVERRIDE_NON_VIRTUAL_METHOD",
241245
#ifndef DISABLE_DEPRECATED
242246
"PROPERTY_USED_AS_FUNCTION",
243247
"CONSTANT_USED_AS_FUNCTION",

modules/gdscript/gdscript_warning.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class GDScriptWarning {
8989
NATIVE_METHOD_OVERRIDE, // The script method overrides a native one, this may not work as intended.
9090
GET_NODE_DEFAULT_WITHOUT_ONREADY, // A class variable uses `get_node()` (or the `$` notation) as its default value, but does not use the @onready annotation.
9191
ONREADY_WITH_EXPORT, // The `@onready` annotation will set the value after `@export` which is likely not intended.
92+
OVERRIDE_NON_VIRTUAL_METHOD, // The class method overrides a non-virtual one, which would cause potential problems.
9293
#ifndef DISABLE_DEPRECATED
9394
PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name.
9495
CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name.
@@ -146,6 +147,7 @@ class GDScriptWarning {
146147
ERROR, // NATIVE_METHOD_OVERRIDE // May not work as expected.
147148
ERROR, // GET_NODE_DEFAULT_WITHOUT_ONREADY // May not work as expected.
148149
ERROR, // ONREADY_WITH_EXPORT // May not work as expected.
150+
WARN, // OVERRIDE_NON_VIRTUAL_METHOD
149151
#ifndef DISABLE_DEPRECATED
150152
WARN, // PROPERTY_USED_AS_FUNCTION
151153
WARN, // CONSTANT_USED_AS_FUNCTION

modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ func test():
66
print("No failure")
77

88
class Parent:
9-
func my_function(_par1: Dictionary = {}) -> void:
9+
@virtual func my_function(_par1: Dictionary = {}) -> void:
1010
pass
1111

1212
class Child extends Parent:

modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_extra_parameters.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ func test():
99
Utils.check(result == 0)
1010

1111
class Parent:
12-
func my_function(par1: int) -> int:
12+
@virtual func my_function(par1: int) -> int:
1313
return par1
1414

1515
class Child extends Parent:

modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.gd

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
class A:
2-
func int_to_variant(_p: int): pass
3-
func node_to_variant(_p: Node): pass
4-
func node_2d_to_node(_p: Node2D): pass
2+
@virtual func int_to_variant(_p: int): pass
3+
@virtual func node_to_variant(_p: Node): pass
4+
@virtual func node_2d_to_node(_p: Node2D): pass
55

6-
func variant_to_untyped(_p: Variant): pass
7-
func int_to_untyped(_p: int): pass
8-
func node_to_untyped(_p: Node): pass
6+
@virtual func variant_to_untyped(_p: Variant): pass
7+
@virtual func int_to_untyped(_p: int): pass
8+
@virtual func node_to_untyped(_p: Node): pass
99

1010
class B extends A:
1111
func int_to_variant(_p: Variant): pass

modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.gd

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
class A:
2-
func variant_to_int() -> Variant: return 0
3-
func variant_to_node() -> Variant: return null
4-
func node_to_node_2d() -> Node: return null
2+
@virtual func variant_to_int() -> Variant: return 0
3+
@virtual func variant_to_node() -> Variant: return null
4+
@virtual func node_to_node_2d() -> Node: return null
55

6-
func untyped_to_void(): pass
7-
func untyped_to_variant(): pass
8-
func untyped_to_int(): pass
9-
func untyped_to_node(): pass
6+
@virtual func untyped_to_void(): pass
7+
@virtual func untyped_to_variant(): pass
8+
@virtual func untyped_to_int(): pass
9+
@virtual func untyped_to_node(): pass
1010

11-
func void_to_untyped() -> void: pass
12-
func variant_to_untyped() -> Variant: return null
13-
func int_to_untyped() -> int: return 0
14-
func node_to_untyped() -> Node: return null
11+
@virtual func void_to_untyped() -> void: pass
12+
@virtual func variant_to_untyped() -> Variant: return null
13+
@virtual func int_to_untyped() -> int: return 0
14+
@virtual func node_to_untyped() -> Node: return null
1515

1616
class B extends A:
1717
func variant_to_int() -> int: return 0

modules/gdscript/tests/scripts/analyzer/features/global_enums.gd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ func test():
1818
duper.set_direction(COUNTERCLOCKWISE)
1919

2020
class Super:
21-
func set_type(type: Variant.Type) -> void:
21+
@virtual func set_type(type: Variant.Type) -> void:
2222
print(type)
23-
func set_direction(dir: ClockDirection) -> void:
23+
@virtual func set_direction(dir: ClockDirection) -> void:
2424
print(dir)
2525

2626
class Duper extends Super:

0 commit comments

Comments
 (0)