Skip to content

Commit 2f7785b

Browse files
dsnopekRepiteo
andcommitted
Add RequiredPtr<T> to mark Object * arguments and return values as required
Co-authored-by: Thaddeus Crews <[email protected]>
1 parent eb72ce2 commit 2f7785b

File tree

10 files changed

+176
-4
lines changed

10 files changed

+176
-4
lines changed

core/extension/extension_api_dump.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static String get_property_info_type_name(const PropertyInfo &p_info) {
8888
}
8989

9090
static String get_type_meta_name(const GodotTypeInfo::Metadata metadata) {
91-
static const char *argmeta[13] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32" };
91+
static const char *argmeta[14] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double", "char16", "char32", "required" };
9292
return argmeta[metadata];
9393
}
9494

core/object/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "core/templates/rb_map.h"
4343
#include "core/templates/safe_refcount.h"
4444
#include "core/variant/callable_bind.h"
45+
#include "core/variant/required_ptr.h"
4546
#include "core/variant/variant.h"
4647

4748
template <typename T>

core/typedefs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,15 @@ struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
324324
#define ___gd_is_defined(val) ____gd_is_defined(__GDARG_PLACEHOLDER_##val)
325325
#define GD_IS_DEFINED(x) ___gd_is_defined(x)
326326

327+
#define GODOT_DEPRECATED_BEGIN \
328+
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") \
329+
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") \
330+
GODOT_MSVC_WARNING_PUSH_AND_IGNORE(4996)
331+
#define GODOT_DEPRECATED_END \
332+
GODOT_CLANG_WARNING_POP \
333+
GODOT_GCC_WARNING_POP \
334+
GODOT_MSVC_WARNING_POP
335+
327336
// Whether the default value of a type is just all-0 bytes.
328337
// This can most commonly be exploited by using memset for these types instead of loop-construct.
329338
// Trivially constructible types are also zero-constructible.

core/variant/binder_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "core/templates/simple_type.h"
3737
#include "core/typedefs.h"
3838
#include "core/variant/method_ptrcall.h"
39+
#include "core/variant/required_ptr.h"
3940
#include "core/variant/type_info.h"
4041
#include "core/variant/variant.h"
4142
#include "core/variant/variant_internal.h"

core/variant/method_ptrcall.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,27 @@ struct PtrToArg<const T *> {
167167
}
168168
};
169169

170+
// This is for RequiredPtr.
171+
172+
template <class T>
173+
struct PtrToArg<RequiredPtr<T>> {
174+
typedef T *EncodeT;
175+
176+
_FORCE_INLINE_ static RequiredPtr<T> convert(const void *p_ptr) {
177+
if (p_ptr == nullptr) {
178+
// Should we show an error?
179+
GODOT_DEPRECATED_BEGIN
180+
return RequiredPtr<T>::_create_null();
181+
GODOT_DEPRECATED_END
182+
}
183+
return RequiredPtr<T>(*reinterpret_cast<T *const *>(p_ptr));
184+
}
185+
186+
_FORCE_INLINE_ static void encode(const RequiredPtr<T> &p_var, void *p_ptr) {
187+
*((T **)p_ptr) = p_var._internal_ptr();
188+
}
189+
};
190+
170191
// This is for ObjectID.
171192

172193
template <>

core/variant/required_ptr.h

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**************************************************************************/
2+
/* required_ptr.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#pragma once
32+
33+
#include "core/variant/variant.h"
34+
35+
template <typename T>
36+
class [[nodiscard]] RequiredPtr {
37+
T *_value = nullptr;
38+
39+
RequiredPtr(std::nullptr_t) {}
40+
41+
public:
42+
using element_type = T;
43+
44+
[[nodiscard, deprecated("Should not be called directly; only used in EXTRACT_REQUIRED_PTR_OR_FAIL* macros.")]]
45+
_FORCE_INLINE_ T *_internal_ptr() const { return _value; }
46+
[[nodiscard, deprecated("Should not be called directly; only used in EXTRACT_REQUIRED_PTR_OR_FAIL* macros.")]]
47+
_FORCE_INLINE_ bool _is_null() const { return _value == nullptr; }
48+
49+
[[nodiscard, deprecated("Should not be called directly; only used internally.")]]
50+
_FORCE_INLINE_ static RequiredPtr<T> _create_null() { return RequiredPtr<T>(nullptr); }
51+
52+
RequiredPtr() = delete;
53+
54+
RequiredPtr(const RequiredPtr &p_other) = default;
55+
RequiredPtr(RequiredPtr &&p_other) = default;
56+
RequiredPtr &operator=(const RequiredPtr &p_other) = default;
57+
RequiredPtr &operator=(RequiredPtr &&p_other) = default;
58+
59+
GODOT_DEPRECATED_BEGIN
60+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
61+
_FORCE_INLINE_ RequiredPtr(const RequiredPtr<T_Other> &p_other) :
62+
_value(p_other._internal_ptr()) {}
63+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
64+
_FORCE_INLINE_ RequiredPtr &operator=(const RequiredPtr<T_Other> &p_other) {
65+
_value = p_other._internal_ptr();
66+
return *this;
67+
}
68+
GODOT_DEPRECATED_END
69+
70+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
71+
_FORCE_INLINE_ RequiredPtr(const T_Other *p_ptr) :
72+
_value(const_cast<std::remove_const_t<T_Other> *>(p_ptr)) {}
73+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
74+
_FORCE_INLINE_ RequiredPtr &operator=(const T_Other *p_ptr) {
75+
_value = const_cast<std::remove_const_t<T_Other> *>(p_ptr);
76+
return *this;
77+
}
78+
79+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
80+
_FORCE_INLINE_ RequiredPtr(const Ref<T_Other> &p_ref) :
81+
_value(p_ref.ptr()) {}
82+
template <typename T_Other, std::enable_if_t<std::is_base_of_v<T, T_Other>, int> = 0>
83+
_FORCE_INLINE_ RequiredPtr &operator=(const Ref<T_Other> &p_ref) {
84+
_value = p_ref.ptr();
85+
return *this;
86+
}
87+
88+
_FORCE_INLINE_ RequiredPtr(const Variant &p_variant) :
89+
_value(static_cast<T *>(p_variant.get_validated_object())) {}
90+
_FORCE_INLINE_ RequiredPtr &operator=(const Variant &p_variant) {
91+
_value = static_cast<T *>(p_variant.get_validated_object());
92+
return *this;
93+
}
94+
};
95+
96+
#define TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, m_retval, m_msg, m_editor) \
97+
GODOT_DEPRECATED_BEGIN \
98+
if (unlikely(m_param._is_null())) { \
99+
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Required object \"" _STR(m_param) "\" is null.", m_msg, m_editor); \
100+
return m_retval; \
101+
} \
102+
std::conditional_t< \
103+
std::is_base_of_v<RefCounted, std::decay_t<decltype(m_param)>::element_type>, \
104+
Ref<std::decay_t<decltype(m_param)>::element_type>, \
105+
std::decay_t<decltype(m_param)>::element_type *> \
106+
m_name = m_param._internal_ptr(); \
107+
GODOT_DEPRECATED_END \
108+
static_assert(true)
109+
110+
#define EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param) TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, void(), "", false)
111+
#define EXTRACT_REQUIRED_PTR_OR_FAIL_MSG(m_name, m_param, m_msg) TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, void(), m_msg, false)
112+
#define EXTRACT_REQUIRED_PTR_OR_FAIL_EDMSG(m_name, m_param, m_msg) TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, void(), m_msg, true)
113+
#define EXTRACT_REQUIRED_PTR_OR_FAIL_V(m_name, m_param, m_retval) TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, m_retval, "", false)
114+
#define EXTRACT_REQUIRED_PTR_OR_FAIL_V_MSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, m_retval, m_msg, false)
115+
#define EXTRACT_REQUIRED_PTR_OR_FAIL_V_EDMSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_REQUIRED_PTR_OR_FAIL(m_name, m_param, m_retval, m_msg, true)

core/variant/type_info.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum Metadata {
5050
METADATA_REAL_IS_DOUBLE,
5151
METADATA_INT_IS_CHAR16,
5252
METADATA_INT_IS_CHAR32,
53+
METADATA_OBJECT_IS_REQUIRED,
5354
};
5455
}
5556

@@ -180,6 +181,18 @@ struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> {
180181
}
181182
};
182183

184+
template <class T>
185+
class RequiredPtr;
186+
187+
template <typename T>
188+
struct GetTypeInfo<RequiredPtr<T>, std::enable_if_t<std::is_base_of_v<Object, T>>> {
189+
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
190+
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_OBJECT_IS_REQUIRED;
191+
static inline PropertyInfo get_class_info() {
192+
return PropertyInfo(StringName(T::get_class_static()));
193+
}
194+
};
195+
183196
namespace GodotTypeInfo {
184197
namespace Internal {
185198
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {

core/variant/variant_internal.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,18 @@ struct VariantInternalAccessor<Object *> {
10451045
static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { VariantInternal::object_assign(v, p_value); }
10461046
};
10471047

1048+
template <class T>
1049+
struct VariantInternalAccessor<RequiredPtr<T>> {
1050+
static _FORCE_INLINE_ RequiredPtr<T> get(const Variant *v) { return RequiredPtr<T>(Object::cast_to<T>(const_cast<Object *>(*VariantInternal::get_object(v)))); }
1051+
static _FORCE_INLINE_ void set(Variant *v, const RequiredPtr<T> &p_value) { VariantInternal::object_assign(v, p_value.ptr()); }
1052+
};
1053+
1054+
template <class T>
1055+
struct VariantInternalAccessor<const RequiredPtr<T> &> {
1056+
static _FORCE_INLINE_ RequiredPtr<T> get(const Variant *v) { return RequiredPtr<T>(Object::cast_to<T>(*VariantInternal::get_object(v))); }
1057+
static _FORCE_INLINE_ void set(Variant *v, const RequiredPtr<T> &p_value) { VariantInternal::object_assign(v, p_value.ptr()); }
1058+
};
1059+
10481060
template <>
10491061
struct VariantInternalAccessor<Variant> {
10501062
static _FORCE_INLINE_ Variant &get(Variant *v) { return *v; }

scene/main/node.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,11 +1809,11 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name, InternalM
18091809
emit_signal(SNAME("child_order_changed"));
18101810
}
18111811

1812-
void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_internal) {
1812+
void Node::add_child(const RequiredPtr<Node> &rp_child, bool p_force_readable_name, InternalMode p_internal) {
18131813
ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Adding children to a node inside the SceneTree is only allowed from the main thread. Use call_deferred(\"add_child\",node).");
18141814

18151815
ERR_THREAD_GUARD
1816-
ERR_FAIL_NULL(p_child);
1816+
EXTRACT_REQUIRED_PTR_OR_FAIL(p_child, rp_child);
18171817
ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself!
18181818
ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent
18191819
#ifdef DEBUG_ENABLED

scene/main/node.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ class Node : public Object {
490490

491491
InternalMode get_internal_mode() const;
492492

493-
void add_child(Node *p_child, bool p_force_readable_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
493+
void add_child(const RequiredPtr<Node> &rp_child, bool p_force_readable_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED);
494494
void add_sibling(Node *p_sibling, bool p_force_readable_name = false);
495495
void remove_child(Node *p_child);
496496

0 commit comments

Comments
 (0)