summaryrefslogtreecommitdiffstats
path: root/core/object/class_db.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/object/class_db.cpp')
-rw-r--r--core/object/class_db.cpp130
1 files changed, 124 insertions, 6 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 760f3bfd0c..cc4a29164d 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -562,6 +562,60 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_n
return nullptr;
}
+Vector<uint32_t> ClassDB::get_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *type = classes.getptr(p_class);
+
+ while (type) {
+ if (type->method_map_compatibility.has(p_name)) {
+ LocalVector<MethodBind *> *c = type->method_map_compatibility.getptr(p_name);
+ Vector<uint32_t> ret;
+ for (uint32_t i = 0; i < c->size(); i++) {
+ ret.push_back((*c)[i]->get_hash());
+ }
+ return ret;
+ }
+ type = type->inherits_ptr;
+ }
+ return Vector<uint32_t>();
+}
+
+MethodBind *ClassDB::get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists, bool *r_is_deprecated) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *type = classes.getptr(p_class);
+
+ while (type) {
+ MethodBind **method = type->method_map.getptr(p_name);
+ if (method && *method) {
+ if (r_method_exists) {
+ *r_method_exists = true;
+ }
+ if ((*method)->get_hash() == p_hash) {
+ return *method;
+ }
+ }
+
+ LocalVector<MethodBind *> *compat = type->method_map_compatibility.getptr(p_name);
+ if (compat) {
+ if (r_method_exists) {
+ *r_method_exists = true;
+ }
+ for (uint32_t i = 0; i < compat->size(); i++) {
+ if ((*compat)[i]->get_hash() == p_hash) {
+ if (r_is_deprecated) {
+ *r_is_deprecated = true;
+ }
+ return (*compat)[i];
+ }
+ }
+ }
+ type = type->inherits_ptr;
+ }
+ return nullptr;
+}
+
void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield) {
OBJTYPE_WLOCK;
@@ -1274,11 +1328,30 @@ bool ClassDB::has_method(const StringName &p_class, const StringName &p_method,
}
void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) {
+ _bind_method_custom(p_class, p_method, false);
+}
+void ClassDB::bind_compatibility_method_custom(const StringName &p_class, MethodBind *p_method) {
+ _bind_method_custom(p_class, p_method, true);
+}
+
+void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) {
+ if (!type->method_map_compatibility.has(p_method->get_name())) {
+ type->method_map_compatibility.insert(p_method->get_name(), LocalVector<MethodBind *>());
+ }
+ type->method_map_compatibility[p_method->get_name()].push_back(p_method);
+}
+
+void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) {
ClassInfo *type = classes.getptr(p_class);
if (!type) {
ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'.");
}
+ if (p_compatibility) {
+ _bind_compatibility(type, p_method);
+ return;
+ }
+
if (type->method_map.has(p_method->get_name())) {
// overloading not supported
ERR_FAIL_MSG("Method already bound '" + p_class + "::" + p_method->get_name() + "'.");
@@ -1291,11 +1364,44 @@ void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method
type->method_map[p_method->get_name()] = p_method;
}
+MethodBind *ClassDB::_bind_vararg_method(MethodBind *p_bind, const StringName &p_name, const Vector<Variant> &p_default_args, bool p_compatibility) {
+ MethodBind *bind = p_bind;
+ bind->set_name(p_name);
+ bind->set_default_arguments(p_default_args);
+
+ String instance_type = bind->get_instance_class();
+
+ ClassInfo *type = classes.getptr(instance_type);
+ if (!type) {
+ memdelete(bind);
+ ERR_FAIL_COND_V(!type, nullptr);
+ }
+
+ if (p_compatibility) {
+ _bind_compatibility(type, bind);
+ return bind;
+ }
+
+ if (type->method_map.has(p_name)) {
+ memdelete(bind);
+ // Overloading not supported
+ ERR_FAIL_V_MSG(nullptr, "Method already bound: " + instance_type + "::" + p_name + ".");
+ }
+ type->method_map[p_name] = bind;
+#ifdef DEBUG_METHODS_ENABLED
+ // FIXME: <reduz> set_return_type is no longer in MethodBind, so I guess it should be moved to vararg method bind
+ //bind->set_return_type("Variant");
+ type->method_order.push_back(p_name);
+#endif
+
+ return bind;
+}
+
#ifdef DEBUG_METHODS_ENABLED
-MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
+MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_compatibility, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
StringName mdname = method_name.name;
#else
-MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) {
+MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_compatibility, const char *method_name, const Variant **p_defs, int p_defcount) {
StringName mdname = StaticCString::create(method_name);
#endif
@@ -1307,7 +1413,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), nullptr, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
+ ERR_FAIL_COND_V_MSG(!p_compatibility && has_method(instance_type, mdname), nullptr, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
#endif
ClassInfo *type = classes.getptr(instance_type);
@@ -1316,7 +1422,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
ERR_FAIL_V_MSG(nullptr, "Couldn't bind method '" + mdname + "' for instance '" + instance_type + "'.");
}
- if (type->method_map.has(mdname)) {
+ if (!p_compatibility && type->method_map.has(mdname)) {
memdelete(p_bind);
// overloading not supported
ERR_FAIL_V_MSG(nullptr, "Method already bound '" + instance_type + "::" + mdname + "'.");
@@ -1331,10 +1437,16 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
p_bind->set_argument_names(method_name.args);
- type->method_order.push_back(mdname);
+ if (!p_compatibility) {
+ type->method_order.push_back(mdname);
+ }
#endif
- type->method_map[mdname] = p_bind;
+ if (p_compatibility) {
+ _bind_compatibility(type, p_bind);
+ } else {
+ type->method_map[mdname] = p_bind;
+ }
Vector<Variant> defvals;
@@ -1608,7 +1720,13 @@ void ClassDB::cleanup() {
for (KeyValue<StringName, MethodBind *> &F : ti.method_map) {
memdelete(F.value);
}
+ for (KeyValue<StringName, LocalVector<MethodBind *>> &F : ti.method_map_compatibility) {
+ for (uint32_t i = 0; i < F.value.size(); i++) {
+ memdelete(F.value[i]);
+ }
+ }
}
+
classes.clear();
resource_base_extensions.clear();
compat_classes.clear();