GDScript: Fix extending abstract classes, forbid their construction
This commit is contained in:
parent
e80cf3259e
commit
274d49790d
8 changed files with 54 additions and 12 deletions
|
@ -148,6 +148,11 @@ bool CreateDialog::_should_hide_type(const String &p_type) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringName native_type = ScriptServer::get_global_class_native_base(p_type);
|
||||||
|
if (ClassDB::class_exists(native_type) && !ClassDB::can_instantiate(native_type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
String script_path = ScriptServer::get_global_class_path(p_type);
|
String script_path = ScriptServer::get_global_class_path(p_type);
|
||||||
if (script_path.begins_with("res://addons/")) {
|
if (script_path.begins_with("res://addons/")) {
|
||||||
if (!EditorNode::get_singleton()->is_addon_plugin_enabled(script_path.get_slicec('/', 3))) {
|
if (!EditorNode::get_singleton()->is_addon_plugin_enabled(script_path.get_slicec('/', 3))) {
|
||||||
|
|
|
@ -431,7 +431,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
base = info_parser->get_parser()->head->get_datatype();
|
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.kind = GDScriptParser::DataType::NATIVE;
|
||||||
base.native_type = name;
|
base.native_type = name;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4010,6 +4010,25 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
|
||||||
return false;
|
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) {
|
if (p_is_constructor) {
|
||||||
function_name = "_init";
|
function_name = "_init";
|
||||||
r_static = true;
|
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) {
|
if (p_is_constructor) {
|
||||||
// Native types always have a default constructor.
|
// Native types always have a default constructor.
|
||||||
r_return_type = p_base_type;
|
r_return_type = p_base_type;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
func test():
|
||||||
|
CanvasItem.new()
|
|
@ -0,0 +1,2 @@
|
||||||
|
GDTEST_ANALYZER_ERROR
|
||||||
|
Native class "CanvasItem" cannot be constructed as it is abstract.
|
|
@ -0,0 +1,9 @@
|
||||||
|
class A extends CanvasItem:
|
||||||
|
func _init():
|
||||||
|
print('no')
|
||||||
|
|
||||||
|
class B extends A:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func test():
|
||||||
|
B.new()
|
|
@ -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".
|
|
@ -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')
|
|
@ -0,0 +1,2 @@
|
||||||
|
GDTEST_OK
|
||||||
|
ok
|
Loading…
Reference in a new issue