Merge pull request #18494 from neikeq/v

Mono: BindingsGenerator enum fixes
This commit is contained in:
Ignacio Etcheverry 2018-04-28 22:31:45 +02:00 committed by GitHub
commit d0183effe0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 93 deletions

View File

@ -248,14 +248,14 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
if (imethod.is_virtual)
continue;
const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type);
const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type);
String im_sig;
String im_unique_sig;
if (p_itype.is_object_type) {
im_sig += "IntPtr " CS_PARAM_METHODBIND ", ";
im_unique_sig += imethod.return_type.operator String() + ",IntPtr,IntPtr";
im_unique_sig += imethod.return_type.cname.operator String() + ",IntPtr,IntPtr";
}
im_sig += "IntPtr " CS_PARAM_INSTANCE;
@ -263,7 +263,7 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
// Get arguments information
int i = 0;
for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
const TypeInterface *arg_type = _get_type_by_name_or_placeholder(F->get().type);
const TypeInterface *arg_type = _get_type_or_placeholder(F->get().type);
im_sig += ", ";
im_sig += arg_type->im_type_in;
@ -1069,12 +1069,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
}
if (getter && setter) {
ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG);
ERR_FAIL_COND_V(getter->return_type.cname != setter->arguments.back()->get().type.cname, ERR_BUG);
}
StringName proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
const TypeReference &proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name);
const TypeInterface *prop_itype = _get_type_or_null(proptype_name);
ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found
String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname));
@ -1122,9 +1122,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.push_back(getter->proxy_name + "(");
if (p_iprop.index != -1) {
const ArgumentInterface &idx_arg = getter->arguments.front()->get();
if (idx_arg.type != name_cache.type_int) {
if (idx_arg.type.cname != name_cache.type_int) {
// Assume the index parameter is an enum
const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type);
const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type);
CRASH_COND(idx_arg_type == NULL);
p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index));
} else {
@ -1139,9 +1139,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.push_back(setter->proxy_name + "(");
if (p_iprop.index != -1) {
const ArgumentInterface &idx_arg = setter->arguments.front()->get();
if (idx_arg.type != name_cache.type_int) {
if (idx_arg.type.cname != name_cache.type_int) {
// Assume the index parameter is an enum
const TypeInterface *idx_arg_type = _get_type_by_name_or_null(idx_arg.type);
const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type);
CRASH_COND(idx_arg_type == NULL);
p_output.push_back("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", ");
} else {
@ -1158,7 +1158,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output) {
const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
String method_bind_field = "method_bind_" + itos(p_method_bind_count);
@ -1175,7 +1175,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Retrieve information from the arguments
for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
const ArgumentInterface &iarg = F->get();
const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
// Add the current arguments to the signature
// If the argument has a default value which is not a constant, we will make it Nullable
@ -1328,21 +1328,19 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
const InternalCall *im_icall = match->value();
String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
im_call += "." + im_icall->name + "(" + icall_params + ");\n";
im_call += "." + im_icall->name + "(" + icall_params + ")";
if (p_imethod.arguments.size())
p_output.push_back(cs_in_statements);
if (return_type->cname == name_cache.type_void) {
p_output.push_back(im_call);
p_output.push_back(im_call + ";\n");
} else if (return_type->cs_out.empty()) {
p_output.push_back("return " + im_call);
p_output.push_back("return " + im_call + ";\n");
} else {
p_output.push_back(return_type->im_type_out);
p_output.push_back(" " LOCAL_RET " = ");
p_output.push_back(im_call);
p_output.push_back(INDENT3);
p_output.push_back(sformat(return_type->cs_out, LOCAL_RET) + "\n");
p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out));
p_output.push_back("\n");
}
p_output.push_back(CLOSE_BLOCK_L2);
@ -1540,9 +1538,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
if (p_imethod.is_virtual)
return OK; // Ignore
bool ret_void = p_imethod.return_type == name_cache.type_void;
bool ret_void = p_imethod.return_type.cname == name_cache.type_void;
const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
String argc_str = itos(p_imethod.arguments.size());
@ -1554,7 +1552,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
int i = 0;
for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
const ArgumentInterface &iarg = F->get();
const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
String c_param_name = "arg" + itos(i + 1);
@ -1695,42 +1693,49 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
return OK;
}
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const StringName &p_cname) {
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(const TypeReference &p_typeref) {
const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_cname);
const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_typeref.cname);
if (builtin_type_match)
return &builtin_type_match->get();
const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_cname);
const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_typeref.cname);
if (obj_type_match)
return &obj_type_match.get();
const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_cname);
if (p_typeref.is_enum) {
const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_typeref.cname);
if (enum_match)
return &enum_match->get();
if (enum_match)
return &enum_match->get();
// Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead.
const Map<StringName, TypeInterface>::Element *int_match = builtin_types.find(name_cache.type_int);
ERR_FAIL_NULL_V(int_match, NULL);
return &int_match->get();
}
return NULL;
}
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const StringName &p_cname) {
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placeholder(const TypeReference &p_typeref) {
const TypeInterface *found = _get_type_by_name_or_null(p_cname);
const TypeInterface *found = _get_type_or_null(p_typeref);
if (found)
return found;
ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_cname.operator String());
ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_typeref.cname.operator String());
const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_cname);
const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_typeref.cname);
if (match)
return &match->get();
TypeInterface placeholder;
TypeInterface::create_placeholder_type(placeholder, p_cname);
TypeInterface::create_placeholder_type(placeholder, p_typeref.cname);
return &placeholder_types.insert(placeholder.cname, placeholder)->get();
}
@ -1874,7 +1879,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
// The method Object.free is registered as a virtual method, but without the virtual flag.
// This is because this method is not supposed to be overridden, but called.
// We assume the return type is void.
imethod.return_type = name_cache.type_void;
imethod.return_type.cname = name_cache.type_void;
// Actually, more methods like this may be added in the future,
// which could actually will return something different.
@ -1889,21 +1894,22 @@ void BindingsGenerator::_populate_object_type_interfaces() {
} else {
ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
}
} else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant?
imethod.return_type = return_info.class_name;
} else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
imethod.return_type.cname = return_info.class_name;
imethod.return_type.is_enum = true;
} else if (return_info.class_name != StringName()) {
imethod.return_type = return_info.class_name;
imethod.return_type.cname = return_info.class_name;
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type = return_info.hint_string;
imethod.return_type.cname = return_info.hint_string;
} else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
imethod.return_type = name_cache.type_Variant;
imethod.return_type.cname = name_cache.type_Variant;
} else if (return_info.type == Variant::NIL) {
imethod.return_type = name_cache.type_void;
imethod.return_type.cname = name_cache.type_void;
} else {
imethod.return_type = Variant::get_type_name(return_info.type);
imethod.return_type.cname = Variant::get_type_name(return_info.type);
}
if (!itype.requires_collections && imethod.return_type == name_cache.type_Dictionary)
if (!itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary)
itype.requires_collections = true;
for (int i = 0; i < argc; i++) {
@ -1912,21 +1918,22 @@ void BindingsGenerator::_populate_object_type_interfaces() {
ArgumentInterface iarg;
iarg.name = arginfo.name;
if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { // TODO redundant?
iarg.type = arginfo.class_name;
if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
iarg.type.cname = arginfo.class_name;
iarg.type.is_enum = true;
} else if (arginfo.class_name != StringName()) {
iarg.type = arginfo.class_name;
iarg.type.cname = arginfo.class_name;
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type = arginfo.hint_string;
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
iarg.type = name_cache.type_Variant;
iarg.type.cname = name_cache.type_Variant;
} else {
iarg.type = Variant::get_type_name(arginfo.type);
iarg.type.cname = Variant::get_type_name(arginfo.type);
}
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
if (!itype.requires_collections && iarg.type == name_cache.type_Dictionary)
if (!itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary)
itype.requires_collections = true;
if (m && m->has_default_argument(i)) {
@ -1938,7 +1945,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
if (imethod.is_vararg) {
ArgumentInterface ivararg;
ivararg.type = name_cache.type_VarArg;
ivararg.type.cname = name_cache.type_VarArg;
ivararg.name = "@args";
imethod.add_argument(ivararg);
}
@ -2023,17 +2030,11 @@ void BindingsGenerator::_populate_object_type_interfaces() {
itype.enums.push_back(ienum);
TypeInterface enum_itype;
enum_itype.is_enum = true;
enum_itype.name = itype.name + "." + String(*k);
enum_itype.cname = StringName(enum_itype.name);
enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
enum_itype.c_arg_in = "&%s";
enum_itype.c_type = "int";
enum_itype.c_type_in = "int";
enum_itype.c_type_out = "int";
enum_itype.cs_type = enum_itype.proxy_name;
enum_itype.im_type_in = enum_itype.proxy_name;
enum_itype.im_type_out = enum_itype.proxy_name;
enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[enum_itype.proxy_name];
TypeInterface::postsetup_enum_type(enum_itype);
enum_types.insert(enum_itype.cname, enum_itype);
}
@ -2068,7 +2069,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
switch (p_val.get_type()) {
case Variant::NIL:
if (ClassDB::class_exists(r_iarg.type)) {
if (ClassDB::class_exists(r_iarg.type.cname)) {
// Object type
r_iarg.default_argument = "null";
} else {
@ -2081,7 +2082,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
r_iarg.default_argument = bool(p_val) ? "true" : "false";
break;
case Variant::INT:
if (r_iarg.type != name_cache.type_int) {
if (r_iarg.type.cname != name_cache.type_int) {
r_iarg.default_argument = "(%s)" + r_iarg.default_argument;
}
break;
@ -2142,7 +2143,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
default: {}
}
if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == name_cache.type_Variant && r_iarg.default_argument != "null")
if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "null")
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
}
@ -2161,7 +2162,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_arg_in = "&%s_in"; \
itype.c_type_in = m_type_in; \
itype.cs_in = "ref %s"; \
itype.cs_out = "return (" #m_type ")%0;"; \
itype.cs_out = "return (%1)%0;"; \
itype.im_type_out = "object"; \
builtin_types.insert(itype.cname, itype); \
}
@ -2256,7 +2257,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
itype.cs_in = "NodePath." CS_SMETHOD_GETINSTANCE "(%0)";
itype.cs_out = "return new NodePath(%0);";
itype.cs_out = "return new %1(%0);";
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
_populate_builtin_type(itype, Variant::NODE_PATH);
@ -2279,7 +2280,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
itype.cs_in = "RID." CS_SMETHOD_GETINSTANCE "(%0)";
itype.cs_out = "return new RID(%0);";
itype.cs_out = "return new %1(%0);";
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
_populate_builtin_type(itype, Variant::_RID);
@ -2408,11 +2409,11 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
iarg.name = pi.name;
if (pi.type == Variant::NIL)
iarg.type = name_cache.type_Variant;
iarg.type.cname = name_cache.type_Variant;
else
iarg.type = Variant::get_type_name(pi.type);
iarg.type.cname = Variant::get_type_name(pi.type);
if (!r_itype.requires_collections && iarg.type == name_cache.type_Dictionary)
if (!r_itype.requires_collections && iarg.type.cname == name_cache.type_Dictionary)
r_itype.requires_collections = true;
if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0)
@ -2423,12 +2424,12 @@ void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::
if (mi.return_val.type == Variant::NIL) {
if (mi.return_val.name != "")
imethod.return_type = name_cache.type_Variant;
imethod.return_type.cname = name_cache.type_Variant;
} else {
imethod.return_type = Variant::get_type_name(mi.return_val.type);
imethod.return_type.cname = Variant::get_type_name(mi.return_val.type);
}
if (!r_itype.requires_collections && imethod.return_type == name_cache.type_Dictionary)
if (!r_itype.requires_collections && imethod.return_type.cname == name_cache.type_Dictionary)
r_itype.requires_collections = true;
if (r_itype.class_doc) {
@ -2494,13 +2495,11 @@ void BindingsGenerator::_populate_global_constants() {
EnumInterface &ienum = E->get();
TypeInterface enum_itype;
enum_itype = TypeInterface::create_value_type(ienum.cname);
enum_itype.c_arg_in = "&%s";
enum_itype.c_type = "int";
enum_itype.c_type_in = "int";
enum_itype.c_type_out = "int";
enum_itype.im_type_in = enum_itype.name;
enum_itype.im_type_out = enum_itype.name;
enum_itype.is_enum = true;
enum_itype.name = ienum.cname.operator String();
enum_itype.cname = ienum.cname;
enum_itype.proxy_name = enum_itype.name;
TypeInterface::postsetup_enum_type(enum_itype);
enum_types.insert(enum_itype.cname, enum_itype);
ienum.prefix = _determine_enum_prefix(ienum);
@ -2521,15 +2520,13 @@ void BindingsGenerator::_populate_global_constants() {
hardcoded_enums.push_back("Vector3.Axis");
for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) {
// These enums are not generated and must be written manually (e.g.: Vector3.Axis)
// Here, we are assuming core types do not begin with underscore
// Here, we assume core types do not begin with underscore
TypeInterface enum_itype;
enum_itype = TypeInterface::create_value_type(E->get());
enum_itype.c_arg_in = "&%s";
enum_itype.c_type = "int";
enum_itype.c_type_in = "int";
enum_itype.c_type_out = "int";
enum_itype.im_type_in = enum_itype.name;
enum_itype.im_type_out = enum_itype.name;
enum_itype.is_enum = true;
enum_itype.name = E->get().operator String();
enum_itype.cname = E->get();
enum_itype.proxy_name = enum_itype.name;
TypeInterface::postsetup_enum_type(enum_itype);
enum_types.insert(enum_itype.cname, enum_itype);
}
}

View File

@ -81,6 +81,15 @@ class BindingsGenerator {
const DocData::PropertyDoc *prop_doc;
};
struct TypeReference {
StringName cname;
bool is_enum;
TypeReference() {
is_enum = false;
}
};
struct ArgumentInterface {
enum DefaultParamMode {
CONSTANT,
@ -88,7 +97,8 @@ class BindingsGenerator {
NULLABLE_REF
};
StringName type;
TypeReference type;
String name;
String default_argument;
DefaultParamMode def_param_mode;
@ -110,7 +120,7 @@ class BindingsGenerator {
/**
* [TypeInterface::name] of the return type
*/
StringName return_type;
TypeReference return_type;
/**
* Determines if the method has a variable number of arguments (VarArg)
@ -146,7 +156,7 @@ class BindingsGenerator {
}
MethodInterface() {
return_type = BindingsGenerator::get_singleton()->name_cache.type_void;
return_type.cname = BindingsGenerator::get_singleton()->name_cache.type_void;
is_vararg = false;
is_virtual = false;
requires_object_call = false;
@ -175,6 +185,7 @@ class BindingsGenerator {
ClassDB::APIType api_type;
bool is_enum;
bool is_object_type;
bool is_singleton;
bool is_reference;
@ -276,7 +287,9 @@ class BindingsGenerator {
* One or more statements that determine how a variable of this type is returned from a method.
* It must contain the return statement(s).
* Formatting elements:
* %0 or %s: name of the variable to be returned
* %0: internal method call statement
* %1: [cs_type] of the return type
* %2: [im_type_out] of the return type
*/
String cs_out;
@ -293,8 +306,6 @@ class BindingsGenerator {
/**
* Type used for the return type of internal call methods.
* If [cs_out] is not empty and the method return type is not void,
* it is also used for the type of the return variable.
*/
String im_type_out;
@ -379,10 +390,24 @@ class BindingsGenerator {
r_itype.im_type_out = r_itype.proxy_name;
}
static void postsetup_enum_type(TypeInterface &r_enum_itype) {
r_enum_itype.c_arg_in = "&%s";
r_enum_itype.c_type = "int";
r_enum_itype.c_type_in = "int";
r_enum_itype.c_type_out = "int";
r_enum_itype.cs_type = r_enum_itype.proxy_name;
r_enum_itype.cs_in = "(int)%s";
r_enum_itype.cs_out = "return (%1)%0;";
r_enum_itype.im_type_in = "int";
r_enum_itype.im_type_out = "int";
r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name];
}
TypeInterface() {
api_type = ClassDB::API_NONE;
is_enum = false;
is_object_type = false;
is_singleton = false;
is_reference = false;
@ -492,6 +517,8 @@ class BindingsGenerator {
return "Ref";
else if (p_type.is_object_type)
return "Obj";
else if (p_type.is_enum)
return "int";
return p_type.name;
}
@ -501,8 +528,8 @@ class BindingsGenerator {
void _generate_header_icalls();
void _generate_method_icalls(const TypeInterface &p_itype);
const TypeInterface *_get_type_by_name_or_null(const StringName &p_cname);
const TypeInterface *_get_type_by_name_or_placeholder(const StringName &p_cname);
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg);
void _populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype);