GDScript: Add abstract methods

Co-authored-by: ryanabx <ryanbrue@hotmail.com>
This commit is contained in:
Danil Alexeev
2025-05-14 22:52:19 +03:00
parent 8f87e60307
commit a7cf2069d5
27 changed files with 399 additions and 94 deletions

View File

@@ -0,0 +1,28 @@
abstract class AbstractClass:
abstract func some_func()
class ImplementedClass extends AbstractClass:
func some_func():
pass
abstract class AbstractClassAgain extends ImplementedClass:
abstract func some_func()
class Test1:
abstract func some_func()
class Test2 extends AbstractClass:
pass
class Test3 extends AbstractClassAgain:
pass
class Test4 extends AbstractClass:
func some_func():
super()
func other_func():
super.some_func()
func test():
pass

View File

@@ -0,0 +1,6 @@
GDTEST_ANALYZER_ERROR
>> ERROR at line 11: Class "Test1" is not abstract but contains abstract methods. Mark the class as abstract or remove "abstract" from all methods in this class.
>> ERROR at line 14: Class "Test2" must implement "AbstractClass.some_func()" and other inherited abstract methods or be marked as abstract.
>> ERROR at line 17: Class "Test3" must implement "AbstractClassAgain.some_func()" and other inherited abstract methods or be marked as abstract.
>> ERROR at line 22: Cannot call the parent class' abstract function "some_func()" because it hasn't been defined.
>> ERROR at line 25: Cannot call the parent class' abstract function "some_func()" because it hasn't been defined.

View File

@@ -0,0 +1,4 @@
[output]
include=[
{"display": "test(x: int) -> void:", "insert_text": "test(x: int) -> void:"},
]

View File

@@ -0,0 +1,5 @@
abstract class A:
abstract func test(x: int) -> void
class B extends A:
func

View File

@@ -0,0 +1,8 @@
extends RefCounted
abstract class A:
abstract func f():
pass
func test():
pass

View File

@@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Expected end of statement after abstract function declaration, found ":" instead.

View File

@@ -0,0 +1,8 @@
extends RefCounted
abstract class A:
# Currently, an abstract function cannot be static.
abstract static func f()
func test():
pass

View File

@@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Expected "class" or "func" after "abstract".

View File

@@ -1,2 +0,0 @@
GDTEST_PARSER_ERROR
Expected "class_name", "extends", or "class" after "abstract".

View File

@@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Expected "class_name", "extends", "class", or "func" after "abstract".

View File

@@ -0,0 +1,7 @@
extends RefCounted
abstract class A:
abstract abstract func f()
func test():
pass

View File

@@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Expected "class" or "func" after "abstract".

View File

@@ -0,0 +1,8 @@
extends RefCounted
abstract class A:
# Currently, an abstract function cannot be static.
static abstract func f()
func test():
pass

View File

@@ -0,0 +1,2 @@
GDTEST_PARSER_ERROR
Expected "func" or "var" after "static".

View File

@@ -0,0 +1,48 @@
abstract class A:
abstract func get_text_1() -> String
abstract func get_text_2() -> String
# No `UNUSED_PARAMETER` warning.
abstract func func_with_param(param: int) -> int
abstract func func_with_semicolon() -> int;
abstract func func_1() -> int; abstract func func_2() -> int
abstract func func_without_return_type()
func print_text_1() -> void:
print(get_text_1())
abstract class B extends A:
func get_text_1() -> String:
return "text_1b"
func print_text_2() -> void:
print(get_text_2())
class C extends B:
func get_text_2() -> String:
return "text_2c"
func func_with_param(param: int) -> int: return param
func func_with_semicolon() -> int: return 0
func func_1() -> int: return 0
func func_2() -> int: return 0
func func_without_return_type(): pass
abstract class D extends C:
abstract func get_text_1() -> String
func get_text_2() -> String:
return super() + " text_2d"
class E extends D:
func get_text_1() -> String:
return "text_1e"
func test():
var c := C.new()
c.print_text_1()
c.print_text_2()
var e := E.new()
e.print_text_1()
e.print_text_2()

View File

@@ -0,0 +1,5 @@
GDTEST_OK
text_1b
text_2c
text_1e
text_2c text_2d

View File

@@ -1,18 +1,12 @@
# GH-82169
class A:
static var test_static_var_a1
static var test_static_var_a2
var test_var_a1
var test_var_a2
static func test_static_func_a1(): pass
static func test_static_func_a2(): pass
func test_func_a1(): pass
func test_func_a2(): pass
@warning_ignore("unused_signal")
signal test_signal_a1()
@warning_ignore("unused_signal")
signal test_signal_a2()
@warning_ignore_start("unused_signal")
abstract class A:
abstract func test_abstract_func_1()
abstract func test_abstract_func_2()
func test_override_func_1(): pass
func test_override_func_2(): pass
class B extends A:
static var test_static_var_b1
@@ -21,27 +15,67 @@ class B extends A:
var test_var_b2
static func test_static_func_b1(): pass
static func test_static_func_b2(): pass
func test_abstract_func_1(): pass
func test_abstract_func_2(): pass
func test_override_func_1(): pass
func test_override_func_2(): pass
func test_func_b1(): pass
func test_func_b2(): pass
@warning_ignore("unused_signal")
signal test_signal_b1()
@warning_ignore("unused_signal")
signal test_signal_b2()
class C extends B:
static var test_static_var_c1
static var test_static_var_c2
var test_var_c1
var test_var_c2
static func test_static_func_c1(): pass
static func test_static_func_c2(): pass
func test_abstract_func_1(): pass
func test_abstract_func_2(): pass
func test_override_func_1(): pass
func test_override_func_2(): pass
func test_func_c1(): pass
func test_func_c2(): pass
signal test_signal_c1()
signal test_signal_c2()
func test_property_signature(name: String, base: Object, is_static: bool = false) -> void:
prints("---", name, "---")
for property in base.get_property_list():
if str(property.name).begins_with("test_"):
print(Utils.get_property_signature(property, null, is_static))
func test_method_signature(name: String, base: Object) -> void:
prints("---", name, "---")
for method in base.get_method_list():
if str(method.name).begins_with("test_"):
print(Utils.get_method_signature(method))
func test_signal_signature(name: String, base: Object) -> void:
prints("---", name, "---")
for method in base.get_signal_list():
if str(method.name).begins_with("test_"):
print(Utils.get_method_signature(method, true))
func test():
var b := B.new()
for property in (B as GDScript).get_property_list():
if str(property.name).begins_with("test_"):
print(Utils.get_property_signature(property, null, true))
print("---")
for property in b.get_property_list():
if str(property.name).begins_with("test_"):
print(Utils.get_property_signature(property))
print("---")
for method in b.get_method_list():
if str(method.name).begins_with("test_"):
print(Utils.get_method_signature(method))
print("---")
for method in b.get_signal_list():
if str(method.name).begins_with("test_"):
print(Utils.get_method_signature(method, true))
var c := C.new()
print("=== Class Properties ===")
test_property_signature("A", A as GDScript, true)
test_property_signature("B", B as GDScript, true)
test_property_signature("C", C as GDScript, true)
print("=== Member Properties ===")
test_property_signature("B", b)
test_property_signature("C", c)
print("=== Class Methods ===")
test_method_signature("A", A as GDScript)
test_method_signature("B", B as GDScript)
test_method_signature("C", C as GDScript)
print("=== Member Methods ===")
test_method_signature("B", b)
test_method_signature("C", c)
print("=== Signals ===")
test_signal_signature("B", b)
test_signal_signature("C", c)

View File

@@ -1,24 +1,68 @@
GDTEST_OK
static var test_static_var_a1: Variant
static var test_static_var_a2: Variant
=== Class Properties ===
--- A ---
--- B ---
static var test_static_var_b1: Variant
static var test_static_var_b2: Variant
---
--- C ---
static var test_static_var_b1: Variant
static var test_static_var_b2: Variant
static var test_static_var_c1: Variant
static var test_static_var_c2: Variant
=== Member Properties ===
--- B ---
var test_var_b1: Variant
var test_var_b2: Variant
var test_var_a1: Variant
var test_var_a2: Variant
---
--- C ---
var test_var_c1: Variant
var test_var_c2: Variant
var test_var_b1: Variant
var test_var_b2: Variant
=== Class Methods ===
--- A ---
--- B ---
--- C ---
=== Member Methods ===
--- B ---
static func test_static_func_b1() -> void
static func test_static_func_b2() -> void
func test_abstract_func_1() -> void
func test_abstract_func_2() -> void
func test_override_func_1() -> void
func test_override_func_2() -> void
func test_func_b1() -> void
func test_func_b2() -> void
static func test_static_func_a1() -> void
static func test_static_func_a2() -> void
func test_func_a1() -> void
func test_func_a2() -> void
---
abstract func test_abstract_func_1() -> void
abstract func test_abstract_func_2() -> void
func test_override_func_1() -> void
func test_override_func_2() -> void
--- C ---
static func test_static_func_c1() -> void
static func test_static_func_c2() -> void
func test_abstract_func_1() -> void
func test_abstract_func_2() -> void
func test_override_func_1() -> void
func test_override_func_2() -> void
func test_func_c1() -> void
func test_func_c2() -> void
static func test_static_func_b1() -> void
static func test_static_func_b2() -> void
func test_abstract_func_1() -> void
func test_abstract_func_2() -> void
func test_override_func_1() -> void
func test_override_func_2() -> void
func test_func_b1() -> void
func test_func_b2() -> void
abstract func test_abstract_func_1() -> void
abstract func test_abstract_func_2() -> void
func test_override_func_1() -> void
func test_override_func_2() -> void
=== Signals ===
--- B ---
signal test_signal_b1()
signal test_signal_b2()
--- C ---
signal test_signal_c1()
signal test_signal_c2()
signal test_signal_b1()
signal test_signal_b2()
signal test_signal_a1()
signal test_signal_a2()

View File

@@ -100,6 +100,8 @@ static func print_property_extended_info(property: Dictionary, base: Object = nu
static func get_method_signature(method: Dictionary, is_signal: bool = false) -> String:
var result: String = ""
if method.flags & METHOD_FLAG_VIRTUAL_REQUIRED:
result += "abstract "
if method.flags & METHOD_FLAG_STATIC:
result += "static "
result += ("signal " if is_signal else "func ") + method.name + "("