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