GDScript: Fix built-in script and other find_class
bugs
This commit is contained in:
parent
47ef0549ee
commit
e1c63fee86
4 changed files with 34 additions and 39 deletions
|
@ -1111,21 +1111,27 @@ bool GDScript::inherits_script(const Ref<Script> &p_script) const {
|
||||||
GDScript *GDScript::find_class(const String &p_qualified_name) {
|
GDScript *GDScript::find_class(const String &p_qualified_name) {
|
||||||
String first = p_qualified_name.get_slice("::", 0);
|
String first = p_qualified_name.get_slice("::", 0);
|
||||||
|
|
||||||
|
Vector<String> class_names;
|
||||||
GDScript *result = nullptr;
|
GDScript *result = nullptr;
|
||||||
|
// Empty initial name means start here.
|
||||||
if (first.is_empty() || first == name) {
|
if (first.is_empty() || first == name) {
|
||||||
|
class_names = p_qualified_name.split("::");
|
||||||
result = this;
|
result = this;
|
||||||
} else if (first == get_root_script()->path) {
|
} else if (p_qualified_name.begins_with(get_root_script()->path)) {
|
||||||
|
// Script path could have a class path separator("::") in it.
|
||||||
|
class_names = p_qualified_name.trim_prefix(get_root_script()->path).split("::");
|
||||||
result = get_root_script();
|
result = get_root_script();
|
||||||
} else if (HashMap<StringName, Ref<GDScript>>::Iterator E = subclasses.find(first)) {
|
} else if (HashMap<StringName, Ref<GDScript>>::Iterator E = subclasses.find(first)) {
|
||||||
|
class_names = p_qualified_name.split("::");
|
||||||
result = E->value.ptr();
|
result = E->value.ptr();
|
||||||
} else if (_owner != nullptr) {
|
} else if (_owner != nullptr) {
|
||||||
// Check parent scope.
|
// Check parent scope.
|
||||||
return _owner->find_class(p_qualified_name);
|
return _owner->find_class(p_qualified_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int name_count = p_qualified_name.get_slice_count("::");
|
// Starts at index 1 because index 0 was handled above.
|
||||||
for (int i = 1; result != nullptr && i < name_count; i++) {
|
for (int i = 1; result != nullptr && i < class_names.size(); i++) {
|
||||||
String current_name = p_qualified_name.get_slice("::", i);
|
String current_name = class_names[i];
|
||||||
if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(current_name)) {
|
if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(current_name)) {
|
||||||
result = E->value.ptr();
|
result = E->value.ptr();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1137,11 +1143,12 @@ GDScript *GDScript::find_class(const String &p_qualified_name) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GDScript::is_subclass(const GDScript *p_script) {
|
bool GDScript::has_class(const GDScript *p_script) {
|
||||||
String fqn = p_script->fully_qualified_name;
|
String fqn = p_script->fully_qualified_name;
|
||||||
if (!fqn.is_empty() && fqn != fully_qualified_name && fqn.begins_with(fully_qualified_name)) {
|
if (fully_qualified_name.is_empty() && fqn.get_slice("::", 0).is_empty()) {
|
||||||
String fqn_rest = fqn.substr(fully_qualified_name.length());
|
return p_script == this;
|
||||||
return find_class(fqn_rest) == p_script;
|
} else if (fqn.begins_with(fully_qualified_name)) {
|
||||||
|
return p_script == find_class(fqn.trim_prefix(fully_qualified_name));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2597,8 +2604,7 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String
|
||||||
SelfList<GDScript> *elem = script_list.first();
|
SelfList<GDScript> *elem = script_list.first();
|
||||||
while (elem) {
|
while (elem) {
|
||||||
GDScript *scr = elem->self();
|
GDScript *scr = elem->self();
|
||||||
scr = scr->find_class(p_name);
|
if (scr->fully_qualified_name == p_name) {
|
||||||
if (scr != nullptr) {
|
|
||||||
return scr;
|
return scr;
|
||||||
}
|
}
|
||||||
elem = elem->next();
|
elem = elem->next();
|
||||||
|
|
|
@ -187,7 +187,7 @@ public:
|
||||||
bool inherits_script(const Ref<Script> &p_script) const override;
|
bool inherits_script(const Ref<Script> &p_script) const override;
|
||||||
|
|
||||||
GDScript *find_class(const String &p_qualified_name);
|
GDScript *find_class(const String &p_qualified_name);
|
||||||
bool is_subclass(const GDScript *p_script);
|
bool has_class(const GDScript *p_script);
|
||||||
GDScript *get_root_script();
|
GDScript *get_root_script();
|
||||||
bool is_root_script() const { return _owner == nullptr; }
|
bool is_root_script() const { return _owner == nullptr; }
|
||||||
String get_fully_qualified_name() const { return fully_qualified_name; }
|
String get_fully_qualified_name() const { return fully_qualified_name; }
|
||||||
|
|
|
@ -3993,37 +3993,27 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
|
||||||
result.kind = GDScriptParser::DataType::CLASS;
|
result.kind = GDScriptParser::DataType::CLASS;
|
||||||
// This might be an inner class, so we want to get the parser for the root.
|
// This might be an inner class, so we want to get the parser for the root.
|
||||||
// But still get the inner class from that tree.
|
// But still get the inner class from that tree.
|
||||||
GDScript *current = gds.ptr();
|
String script_path = gds->get_script_path();
|
||||||
List<StringName> class_chain;
|
Ref<GDScriptParserRef> ref = get_parser_for(script_path);
|
||||||
while (current->_owner) {
|
|
||||||
// Push to front so it's in reverse.
|
|
||||||
class_chain.push_front(current->name);
|
|
||||||
current = current->_owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<GDScriptParserRef> ref = get_parser_for(current->get_path());
|
|
||||||
if (ref.is_null()) {
|
if (ref.is_null()) {
|
||||||
push_error("Could not find script in path.", p_source);
|
push_error(vformat(R"(Could not find script "%s".)", script_path), p_source);
|
||||||
GDScriptParser::DataType error_type;
|
GDScriptParser::DataType error_type;
|
||||||
error_type.kind = GDScriptParser::DataType::VARIANT;
|
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||||
return error_type;
|
return error_type;
|
||||||
}
|
}
|
||||||
ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
|
Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
|
||||||
|
GDScriptParser::ClassNode *found = nullptr;
|
||||||
GDScriptParser::ClassNode *found = ref->get_parser()->head;
|
if (err == OK) {
|
||||||
|
found = ref->get_parser()->find_class(gds->fully_qualified_name);
|
||||||
for (const StringName &E : class_chain) {
|
if (found != nullptr) {
|
||||||
if (!found->has_member(E)) {
|
err = resolve_class_inheritance(found, p_source);
|
||||||
return GDScriptParser::DataType();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (found->get_member(E).type != GDScriptParser::ClassNode::Member::CLASS) {
|
if (err || found == nullptr) {
|
||||||
return GDScriptParser::DataType();
|
push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source);
|
||||||
}
|
GDScriptParser::DataType error_type;
|
||||||
|
error_type.kind = GDScriptParser::DataType::VARIANT;
|
||||||
resolve_class_member(found, E, p_source);
|
return error_type;
|
||||||
|
|
||||||
found = found->get_member(E).m_class;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = found->get_datatype();
|
result = found->get_datatype();
|
||||||
|
|
|
@ -117,8 +117,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
||||||
result.builtin_type = p_datatype.builtin_type;
|
result.builtin_type = p_datatype.builtin_type;
|
||||||
result.native_type = p_datatype.native_type;
|
result.native_type = p_datatype.native_type;
|
||||||
|
|
||||||
String root_name = p_datatype.class_type->fqcn.get_slice("::", 0);
|
bool is_local_class = parser->has_class(p_datatype.class_type);
|
||||||
bool is_local_class = !root_name.is_empty() && root_name == main_script->fully_qualified_name;
|
|
||||||
|
|
||||||
Ref<GDScript> script;
|
Ref<GDScript> script;
|
||||||
if (is_local_class) {
|
if (is_local_class) {
|
||||||
|
@ -2300,7 +2299,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
|
||||||
return ERR_COMPILATION_FAILED;
|
return ERR_COMPILATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base.ptr() == main_script || main_script->is_subclass(base.ptr())) {
|
if (main_script->has_class(base.ptr())) {
|
||||||
Error err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state);
|
Error err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Reference in a new issue