1 /*************************************************************************/
2 /* gd_mono_property.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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 #include "gd_mono_property.h"
32
33 #include "gd_mono_cache.h"
34 #include "gd_mono_class.h"
35 #include "gd_mono_marshal.h"
36 #include "gd_mono_utils.h"
37
38 #include <mono/metadata/attrdefs.h>
39
GDMonoProperty(MonoProperty * p_mono_property,GDMonoClass * p_owner)40 GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner) {
41 owner = p_owner;
42 mono_property = p_mono_property;
43 name = mono_property_get_name(mono_property);
44
45 MonoMethod *prop_method = mono_property_get_get_method(mono_property);
46
47 if (prop_method) {
48 MonoMethodSignature *getter_sig = mono_method_signature(prop_method);
49
50 MonoType *ret_type = mono_signature_get_return_type(getter_sig);
51
52 type.type_encoding = mono_type_get_type(ret_type);
53 MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
54 type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
55 } else {
56 prop_method = mono_property_get_set_method(mono_property);
57
58 MonoMethodSignature *setter_sig = mono_method_signature(prop_method);
59
60 void *iter = NULL;
61 MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter);
62
63 type.type_encoding = mono_type_get_type(param_raw_type);
64 MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
65 type.type_class = GDMono::get_singleton()->get_class(param_type_class);
66 }
67
68 attrs_fetched = false;
69 attributes = NULL;
70 }
71
~GDMonoProperty()72 GDMonoProperty::~GDMonoProperty() {
73 if (attributes) {
74 mono_custom_attrs_free(attributes);
75 }
76 }
77
is_static()78 bool GDMonoProperty::is_static() {
79 MonoMethod *prop_method = mono_property_get_get_method(mono_property);
80 if (prop_method == NULL)
81 prop_method = mono_property_get_set_method(mono_property);
82 return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC;
83 }
84
get_visibility()85 IMonoClassMember::Visibility GDMonoProperty::get_visibility() {
86 MonoMethod *prop_method = mono_property_get_get_method(mono_property);
87 if (prop_method == NULL)
88 prop_method = mono_property_get_set_method(mono_property);
89
90 switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
91 case MONO_METHOD_ATTR_PRIVATE:
92 return IMonoClassMember::PRIVATE;
93 case MONO_METHOD_ATTR_FAM_AND_ASSEM:
94 return IMonoClassMember::PROTECTED_AND_INTERNAL;
95 case MONO_METHOD_ATTR_ASSEM:
96 return IMonoClassMember::INTERNAL;
97 case MONO_METHOD_ATTR_FAMILY:
98 return IMonoClassMember::PROTECTED;
99 case MONO_METHOD_ATTR_PUBLIC:
100 return IMonoClassMember::PUBLIC;
101 default:
102 ERR_FAIL_V(IMonoClassMember::PRIVATE);
103 }
104 }
105
has_attribute(GDMonoClass * p_attr_class)106 bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) {
107 ERR_FAIL_NULL_V(p_attr_class, false);
108
109 if (!attrs_fetched)
110 fetch_attributes();
111
112 if (!attributes)
113 return false;
114
115 return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
116 }
117
get_attribute(GDMonoClass * p_attr_class)118 MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) {
119 ERR_FAIL_NULL_V(p_attr_class, NULL);
120
121 if (!attrs_fetched)
122 fetch_attributes();
123
124 if (!attributes)
125 return NULL;
126
127 return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
128 }
129
fetch_attributes()130 void GDMonoProperty::fetch_attributes() {
131 ERR_FAIL_COND(attributes != NULL);
132 attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property);
133 attrs_fetched = true;
134 }
135
has_getter()136 bool GDMonoProperty::has_getter() {
137 return mono_property_get_get_method(mono_property) != NULL;
138 }
139
has_setter()140 bool GDMonoProperty::has_setter() {
141 return mono_property_get_set_method(mono_property) != NULL;
142 }
143
set_value(MonoObject * p_object,MonoObject * p_value,MonoException ** r_exc)144 void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
145 MonoMethod *prop_method = mono_property_get_set_method(mono_property);
146 MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
147 mono_array_setref(params, 0, p_value);
148 MonoException *exc = NULL;
149 GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc);
150 if (exc) {
151 if (r_exc) {
152 *r_exc = exc;
153 } else {
154 GDMonoUtils::set_pending_exception(exc);
155 }
156 }
157 }
158
set_value(MonoObject * p_object,void ** p_params,MonoException ** r_exc)159 void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
160 MonoException *exc = NULL;
161 GDMonoUtils::property_set_value(mono_property, p_object, p_params, &exc);
162
163 if (exc) {
164 if (r_exc) {
165 *r_exc = exc;
166 } else {
167 GDMonoUtils::set_pending_exception(exc);
168 }
169 }
170 }
171
get_value(MonoObject * p_object,MonoException ** r_exc)172 MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) {
173 MonoException *exc = NULL;
174 MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, NULL, &exc);
175
176 if (exc) {
177 ret = NULL;
178 if (r_exc) {
179 *r_exc = exc;
180 } else {
181 GDMonoUtils::set_pending_exception(exc);
182 }
183 }
184
185 return ret;
186 }
187
get_bool_value(MonoObject * p_object)188 bool GDMonoProperty::get_bool_value(MonoObject *p_object) {
189 return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
190 }
191
get_int_value(MonoObject * p_object)192 int GDMonoProperty::get_int_value(MonoObject *p_object) {
193 return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
194 }
195
get_string_value(MonoObject * p_object)196 String GDMonoProperty::get_string_value(MonoObject *p_object) {
197 MonoObject *val = get_value(p_object);
198 return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
199 }
200