summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
authorDmitrii Maganov <vonagam@gmail.com>2022-12-29 09:34:13 +0200
committerDmitrii Maganov <vonagam@gmail.com>2023-01-12 17:47:10 +0200
commit274d49790dd2d68828a312e2c0802c1dbf09ac8f (patch)
treee99c43d07ff64187c2da1f429544f44d46b848a0 /modules/gdscript
parente80cf3259ee23fe75da0ea41dcf67680e607f063 (diff)
GDScript: Fix extending abstract classes, forbid their construction
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp32
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out2
7 files changed, 49 insertions, 12 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index ddfdc937c4..8afcb431ec 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -431,7 +431,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
return err;
}
base = info_parser->get_parser()->head->get_datatype();
- } else if (class_exists(name) && ClassDB::can_instantiate(name)) {
+ } else if (class_exists(name)) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
@@ -4010,6 +4010,25 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
return false;
}
+ StringName base_native = p_base_type.native_type;
+ if (base_native != StringName()) {
+ // Empty native class might happen in some Script implementations.
+ // Just ignore it.
+ if (!class_exists(base_native)) {
+ push_error(vformat("Native class %s used in script doesn't exist or isn't exposed.", base_native), p_source);
+ return false;
+ } else if (p_is_constructor && !ClassDB::can_instantiate(base_native)) {
+ if (p_base_type.kind == GDScriptParser::DataType::CLASS) {
+ push_error(vformat(R"(Class "%s" cannot be constructed as it is based on abstract native class "%s".)", p_base_type.class_type->fqcn.get_file(), base_native), p_source);
+ } else if (p_base_type.kind == GDScriptParser::DataType::SCRIPT) {
+ push_error(vformat(R"(Script "%s" cannot be constructed as it is based on abstract native class "%s".)", p_base_type.script_path.get_file(), base_native), p_source);
+ } else {
+ push_error(vformat(R"(Native class "%s" cannot be constructed as it is abstract.)", base_native), p_source);
+ }
+ return false;
+ }
+ }
+
if (p_is_constructor) {
function_name = "_init";
r_static = true;
@@ -4070,17 +4089,6 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
}
}
- StringName base_native = p_base_type.native_type;
-#ifdef DEBUG_ENABLED
- if (base_native != StringName()) {
- // Empty native class might happen in some Script implementations.
- // Just ignore it.
- if (!class_exists(base_native)) {
- ERR_FAIL_V_MSG(false, vformat("Native class %s used in script doesn't exist or isn't exposed.", base_native));
- }
- }
-#endif
-
if (p_is_constructor) {
// Native types always have a default constructor.
r_return_type = p_base_type;
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
new file mode 100644
index 0000000000..38c2faa859
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.gd
@@ -0,0 +1,2 @@
+func test():
+ CanvasItem.new()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
new file mode 100644
index 0000000000..9eff912b59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_class_instantiate.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Native class "CanvasItem" cannot be constructed as it is abstract.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
new file mode 100644
index 0000000000..118e7e8a45
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.gd
@@ -0,0 +1,9 @@
+class A extends CanvasItem:
+ func _init():
+ print('no')
+
+class B extends A:
+ pass
+
+func test():
+ B.new()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
new file mode 100644
index 0000000000..8b956f5974
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/abstract_script_instantiate.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Class "abstract_script_instantiate.gd::B" cannot be constructed as it is based on abstract native class "CanvasItem".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd
new file mode 100644
index 0000000000..95c3268130
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.gd
@@ -0,0 +1,12 @@
+class A extends CanvasItem:
+ func _init():
+ pass
+
+class B extends A:
+ pass
+
+class C extends CanvasItem:
+ pass
+
+func test():
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out
new file mode 100644
index 0000000000..1b47ed10dc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/extend_abstract_class.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+ok