Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDScript compiler inner class bugfixes #68374

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 66 additions & 74 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,10 +629,6 @@ void GDScript::_update_doc() {
}
}

for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
E.value->_update_doc();
}

_add_doc(doc);
}
#endif
Expand Down Expand Up @@ -674,36 +670,14 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
base_cache = Ref<GDScript>();
}

if (c->extends_used) {
String ext_path = "";
if (String(c->extends_path) != "" && String(c->extends_path) != get_path()) {
ext_path = c->extends_path;
if (ext_path.is_relative_path()) {
String base_path = get_path();
if (base_path.is_empty() || base_path.is_relative_path()) {
ERR_PRINT(("Could not resolve relative path for parent class: " + ext_path).utf8().get_data());
} else {
ext_path = base_path.get_base_dir().path_join(ext_path);
}
}
} else if (c->extends.size() != 0) {
const StringName &base_class = c->extends[0];

if (ScriptServer::is_global_class(base_class)) {
ext_path = ScriptServer::get_global_class_path(base_class);
}
}

if (!ext_path.is_empty()) {
if (ext_path != get_path()) {
Ref<GDScript> bf = ResourceLoader::load(ext_path);

if (bf.is_valid()) {
base_cache = bf;
bf->inheriters_cache.insert(get_instance_id());
}
} else {
ERR_PRINT(("Path extending itself in " + ext_path).utf8().get_data());
GDScriptParser::DataType base_type = parser.get_tree()->base_type;
if (base_type.kind == GDScriptParser::DataType::CLASS) {
Ref<GDScript> bf = GDScriptCache::get_full_script(base_type.script_path, err, path);
if (err == OK) {
bf = Ref<GDScript>(bf->find_class(base_type.class_type->fqcn));
if (bf.is_valid()) {
base_cache = bf;
bf->inheriters_cache.insert(get_instance_id());
}
}
}
Expand Down Expand Up @@ -825,13 +799,6 @@ void GDScript::update_exports() {
#endif
}

void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
p_sc->path = p_path;
for (KeyValue<StringName, Ref<GDScript>> &E : p_sc->subclasses) {
_set_subclass_path(E.value, p_path);
}
}

String GDScript::_get_debug_path() const {
if (is_built_in() && !get_name().is_empty()) {
return get_name() + " (" + get_path() + ")";
Expand Down Expand Up @@ -860,7 +827,7 @@ Error GDScript::reload(bool p_keep_state) {
basedir = basedir.get_base_dir();
}

// Loading a template, don't parse.
// Loading a template, don't parse.
#ifdef TOOLS_ENABLED
if (EditorPaths::get_singleton() && basedir.begins_with(EditorPaths::get_singleton()->get_project_script_templates_dir())) {
return OK;
Expand Down Expand Up @@ -913,10 +880,6 @@ Error GDScript::reload(bool p_keep_state) {
GDScriptCompiler compiler;
err = compiler.compile(&parser, this, p_keep_state);

#ifdef TOOLS_ENABLED
_update_doc();
#endif

if (err) {
if (can_run) {
if (EngineDebugger::is_active()) {
Expand All @@ -937,14 +900,6 @@ Error GDScript::reload(bool p_keep_state) {
}
#endif

valid = true;

for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
_set_subclass_path(E.value, path);
}

_init_rpc_methods_properties();

return OK;
}

Expand Down Expand Up @@ -1051,8 +1006,13 @@ Error GDScript::load_byte_code(const String &p_path) {
}

void GDScript::set_path(const String &p_path, bool p_take_over) {
Script::set_path(p_path, p_take_over);
if (is_root_script()) {
Script::set_path(p_path, p_take_over);
}
this->path = p_path;
for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) {
kv.value->set_path(p_path, p_take_over);
}
}

Error GDScript::load_source_code(const String &p_path) {
Expand Down Expand Up @@ -1127,6 +1087,52 @@ bool GDScript::inherits_script(const Ref<Script> &p_script) const {
return false;
}

GDScript *GDScript::find_class(const String &p_qualified_name) {
String first = p_qualified_name.get_slice("::", 0);

GDScript *result = nullptr;
if (first.is_empty() || first == name) {
result = this;
} else if (first == get_root_script()->path) {
result = get_root_script();
} else if (HashMap<StringName, Ref<GDScript>>::Iterator E = subclasses.find(first)) {
result = E->value.ptr();
} else if (_owner != nullptr) {
// Check parent scope.
return _owner->find_class(p_qualified_name);
}

int name_count = p_qualified_name.get_slice_count("::");
for (int i = 1; result != nullptr && i < name_count; i++) {
String current_name = p_qualified_name.get_slice("::", i);
if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(current_name)) {
result = E->value.ptr();
} else {
// Couldn't find inner class.
return nullptr;
}
}

return result;
}

bool GDScript::is_subclass(const GDScript *p_script) {
String fqn = p_script->fully_qualified_name;
if (!fqn.is_empty() && fqn != fully_qualified_name && fqn.begins_with(fully_qualified_name)) {
String fqn_rest = fqn.substr(fully_qualified_name.length());
return find_class(fqn_rest) == p_script;
}
return false;
}

GDScript *GDScript::get_root_script() {
GDScript *result = this;
while (result->_owner) {
result = result->_owner;
}
return result;
}

bool GDScript::has_script_signal(const StringName &p_signal) const {
if (_signals.has(p_signal)) {
return true;
Expand Down Expand Up @@ -1238,25 +1244,11 @@ void GDScript::_init_rpc_methods_properties() {
rpc_config = base->rpc_config.duplicate();
}

GDScript *cscript = this;
HashMap<StringName, Ref<GDScript>>::Iterator sub_E = subclasses.begin();
while (cscript) {
// RPC Methods
for (KeyValue<StringName, GDScriptFunction *> &E : cscript->member_functions) {
Variant config = E.value->get_rpc_config();
if (config.get_type() != Variant::NIL) {
rpc_config[E.value->get_name()] = config;
}
}

if (cscript != this) {
++sub_E;
}

if (sub_E) {
cscript = sub_E->value.ptr();
} else {
cscript = nullptr;
// RPC Methods
for (KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
Variant config = E.value->get_rpc_config();
if (config.get_type() != Variant::NIL) {
rpc_config[E.value->get_name()] = config;
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ class GDScript : public Script {
void _super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error);
GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);

void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path);
String _get_debug_path() const;

#ifdef TOOLS_ENABLED
Expand Down Expand Up @@ -178,6 +177,11 @@ class GDScript : public Script {

bool inherits_script(const Ref<Script> &p_script) const override;

GDScript *find_class(const String &p_qualified_name);
bool is_subclass(const GDScript *p_script);
GDScript *get_root_script();
bool is_root_script() const { return _owner == nullptr; }
String get_fully_qualified_name() const { return fully_qualified_name; }
const HashMap<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; }
const HashMap<StringName, Variant> &get_constants() const { return constants; }
const HashSet<StringName> &get_members() const { return members; }
Expand Down Expand Up @@ -223,7 +227,6 @@ class GDScript : public Script {
virtual Error reload(bool p_keep_state = false) override;

virtual void set_path(const String &p_path, bool p_take_over = false) override;
void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too...
Error load_source_code(const String &p_path);
Error load_byte_code(const String &p_path);

Expand Down
10 changes: 0 additions & 10 deletions modules/gdscript/gdscript_analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,6 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return OK;
}

if (p_class == parser->head) {
if (p_class->identifier) {
p_class->fqcn = p_class->identifier->name;
} else {
p_class->fqcn = parser->script_path;
}
} else {
p_class->fqcn = p_class->outer->fqcn + "::" + String(p_class->identifier->name);
}

if (p_class->identifier) {
StringName class_name = p_class->identifier->name;
if (class_exists(class_name)) {
Expand Down
40 changes: 33 additions & 7 deletions modules/gdscript/gdscript_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "core/templates/vector.h"
#include "gdscript.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"

bool GDScriptParserRef::is_valid() const {
Expand Down Expand Up @@ -161,7 +162,7 @@ String GDScriptCache::get_source_code(const String &p_path) {
return source;
}

Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const String &p_owner) {
Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_error, const String &p_owner) {
MutexLock lock(singleton->lock);
if (!p_owner.is_empty()) {
singleton->dependencies[p_owner].insert(p_path);
Expand All @@ -173,11 +174,16 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri
return singleton->shallow_gdscript_cache[p_path];
}

Ref<GDScriptParserRef> parser_ref = get_parser(p_path, GDScriptParserRef::PARSED, r_error);
if (r_error != OK) {
return Ref<GDScript>();
}
Comment on lines +178 to +180

This comment was marked as spam.


Ref<GDScript> script;
script.instantiate();
script->set_path(p_path, true);
script->set_script_path(p_path);
script->load_source_code(p_path);
GDScriptCompiler::make_scripts(script.ptr(), parser_ref->get_parser()->get_tree(), true);

singleton->shallow_gdscript_cache[p_path] = script.ptr();
return script;
Expand All @@ -200,17 +206,21 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
}

if (script.is_null()) {
script = get_shallow_script(p_path);
ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
script = get_shallow_script(p_path, r_error);
if (r_error) {
return script;
}
rune-scape marked this conversation as resolved.
Show resolved Hide resolved
}

r_error = script->load_source_code(p_path);
if (p_update_from_disk) {
r_error = script->load_source_code(p_path);
}

if (r_error) {
return script;
}

r_error = script->reload();
r_error = script->reload(true);
if (r_error) {
return script;
}
Expand All @@ -221,9 +231,25 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
return script;
}

Ref<GDScript> GDScriptCache::get_cached_script(const String &p_path) {
MutexLock lock(singleton->lock);

if (singleton->full_gdscript_cache.has(p_path)) {
return singleton->full_gdscript_cache[p_path];
}

if (singleton->shallow_gdscript_cache.has(p_path)) {
return singleton->shallow_gdscript_cache[p_path];
}

return Ref<GDScript>();
}

Error GDScriptCache::finish_compiling(const String &p_owner) {
MutexLock lock(singleton->lock);

// Mark this as compiled.
Ref<GDScript> script = get_shallow_script(p_owner);
Ref<GDScript> script = get_cached_script(p_owner);
singleton->full_gdscript_cache[p_owner] = script.ptr();
singleton->shallow_gdscript_cache.erase(p_owner);

Expand Down
3 changes: 2 additions & 1 deletion modules/gdscript/gdscript_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ class GDScriptCache {
public:
static Ref<GDScriptParserRef> get_parser(const String &p_path, GDScriptParserRef::Status status, Error &r_error, const String &p_owner = String());
static String get_source_code(const String &p_path);
static Ref<GDScript> get_shallow_script(const String &p_path, const String &p_owner = String());
static Ref<GDScript> get_shallow_script(const String &p_path, Error &r_error, const String &p_owner = String());
static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String(), bool p_update_from_disk = false);
static Ref<GDScript> get_cached_script(const String &p_path);
static Error finish_compiling(const String &p_owner);

GDScriptCache();
Expand Down
Loading