diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-12-22 11:07:51 +0000 |
---|---|---|
committer | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-12-22 11:07:51 +0000 |
commit | 2aca9f7c51fd7d8d56f11a49a6e3481add1d6dc9 (patch) | |
tree | 7d11a604302024eb718b58d7139ddc85cf4d0eaf /clang-plugin | |
parent | f35f55f09cfec76eef7cf1616792e87cb4e10df6 (diff) |
gir-manager: Fix method lookup
Previously, we were only looking at GI_INFO_TYPE_FUNCTION, which is
incorrect, because that only exposes top-level functions (and not
methods) to the search.
Fix method lookup by looking at all GIBaseInfo instances, recursively
searching within GI_INFO_TYPE_OBJECTs (for example). This means method
lookup from GIR files is actually successful most of the time.
Diffstat (limited to 'clang-plugin')
-rw-r--r-- | clang-plugin/gir-manager.cpp | 189 |
1 files changed, 158 insertions, 31 deletions
diff --git a/clang-plugin/gir-manager.cpp b/clang-plugin/gir-manager.cpp index a167fda..af181cc 100644 --- a/clang-plugin/gir-manager.cpp +++ b/clang-plugin/gir-manager.cpp @@ -69,6 +69,97 @@ GirManager::load_namespace (const std::string& gi_namespace, this->_typelibs.push_back (r); } +/* Returns a reference to the #GIFunctionInfo, or %NULL. */ +static GIFunctionInfo * +_find_function_in_function (GIFunctionInfo *info, const std::string &func_name) +{ + if (g_function_info_get_symbol (info) == func_name) { + return g_base_info_ref (info); + } + + return NULL; +} + +/* Returns a reference to the #GIFunctionInfo, or %NULL. */ +static GIFunctionInfo * +_find_function_in_struct (GIStructInfo *info, const std::string &func_name) +{ + GIFunctionInfo *f_info = NULL; + gint n_methods = g_struct_info_get_n_methods (info); + + for (gint i = 0; i < n_methods && f_info == NULL; i++) { + GIFunctionInfo *_info = g_struct_info_get_method (info, i); + f_info = _find_function_in_function (_info, func_name); + g_base_info_unref (_info); + } + + return f_info; +} + +/* Returns a reference to the #GIFunctionInfo, or %NULL. */ +static GIFunctionInfo * +_find_function_in_enum (GIEnumInfo *info, const std::string &func_name) +{ + GIFunctionInfo *f_info = NULL; + gint n_methods = g_enum_info_get_n_methods (info); + + for (gint i = 0; i < n_methods && f_info == NULL; i++) { + GIFunctionInfo *_info = g_enum_info_get_method (info, i); + f_info = _find_function_in_function (_info, func_name); + g_base_info_unref (_info); + } + + return f_info; +} + +/* Returns a reference to the #GIFunctionInfo, or %NULL. */ +static GIFunctionInfo * +_find_function_in_object (GIObjectInfo *info, const std::string &func_name) +{ + GIFunctionInfo *f_info = NULL; + gint n_methods = g_object_info_get_n_methods (info); + + for (gint i = 0; i < n_methods && f_info == NULL; i++) { + GIFunctionInfo *_info = g_object_info_get_method (info, i); + f_info = _find_function_in_function (_info, func_name); + g_base_info_unref (_info); + } + + return f_info; +} + +/* Returns a reference to the #GIFunctionInfo, or %NULL. */ +static GIFunctionInfo * +_find_function_in_interface (GIInterfaceInfo *info, const std::string &func_name) +{ + GIFunctionInfo *f_info = NULL; + gint n_methods = g_interface_info_get_n_methods (info); + + for (gint i = 0; i < n_methods && f_info == NULL; i++) { + GIFunctionInfo *_info = g_interface_info_get_method (info, i); + f_info = _find_function_in_function (_info, func_name); + g_base_info_unref (_info); + } + + return f_info; +} + +/* Returns a reference to the #GIFunctionInfo, or %NULL. */ +static GIFunctionInfo * +_find_function_in_union (GIUnionInfo *info, const std::string &func_name) +{ + GIFunctionInfo *f_info = NULL; + gint n_methods = g_union_info_get_n_methods (info); + + for (gint i = 0; i < n_methods && f_info == NULL; i++) { + GIFunctionInfo *_info = g_union_info_get_method (info, i); + f_info = _find_function_in_function (_info, func_name); + g_base_info_unref (_info); + } + + return f_info; +} + /* Try to find typelib information about the function. * Note: This returns a reference which needs freeing using * g_base_info_unref(). */ @@ -76,52 +167,88 @@ GIBaseInfo* GirManager::find_function_info (const std::string& func_name) const { GIBaseInfo *info = NULL; - std::string func_name_stripped; for (std::vector<Nspace>::const_iterator it = this->_typelibs.begin (), - ie = this->_typelibs.end (); it != ie; ++it) { + ie = this->_typelibs.end (); it != ie && info == NULL; ++it) { const Nspace r = *it; - /* The func_name includes the namespace, which needs stripping. - * e.g. g_irepository_find_by_name → find_by_name. */ + /* Check the function matches this namespace. + * e.g. g_irepository_find_by_name → + * (g_irepository_, find_by_name). */ if (!r.c_prefix_lower.empty () && - func_name.size () > r.c_prefix_lower.size () && - func_name.compare (0, r.c_prefix_lower.size (), - r.c_prefix_lower) == 0 && - func_name[r.c_prefix_lower.size ()] == '_') { - size_t prefix_len = - r.c_prefix_lower.size () + 1 /* underscore */; - - func_name_stripped = func_name.substr (prefix_len); - } else if (r.c_prefix_lower.empty ()) { - func_name_stripped = func_name; - } else { + (func_name.size () <= r.c_prefix_lower.size () || + func_name.compare (0, r.c_prefix_lower.size (), + r.c_prefix_lower) != 0 || + func_name[r.c_prefix_lower.size ()] != '_')) { continue; } - info = g_irepository_find_by_name (this->_repo, - r.nspace.c_str (), - func_name_stripped.c_str ()); + /* Iterate through every info in the namespace, trying to match + * the entire @func_name against the info, or one of the methods + * it contains. */ + guint n_infos = g_irepository_get_n_infos (this->_repo, + r.nspace.c_str ()); - if (info != NULL) { - /* Successfully found an entry in the typelib. */ - break; + for (guint i = 0; i < n_infos && info == NULL; i++) { + GIBaseInfo *_info; + + _info = g_irepository_get_info (this->_repo, + r.nspace.c_str (), i); + + switch (g_base_info_get_type (_info)) { + case GI_INFO_TYPE_FUNCTION: + info = _find_function_in_function (_info, + func_name); + break; + case GI_INFO_TYPE_STRUCT: + info = _find_function_in_struct (_info, + func_name); + break; + case GI_INFO_TYPE_ENUM: + info = _find_function_in_enum (_info, + func_name); + break; + case GI_INFO_TYPE_OBJECT: + info = _find_function_in_object (_info, + func_name); + break; + case GI_INFO_TYPE_INTERFACE: + info = _find_function_in_interface (_info, + func_name); + break; + case GI_INFO_TYPE_UNION: + info = _find_function_in_union (_info, + func_name); + break; + case GI_INFO_TYPE_INVALID: + case GI_INFO_TYPE_CALLBACK: + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_FLAGS: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_INVALID_0: + case GI_INFO_TYPE_VALUE: + case GI_INFO_TYPE_SIGNAL: + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_PROPERTY: + case GI_INFO_TYPE_FIELD: + case GI_INFO_TYPE_ARG: + case GI_INFO_TYPE_TYPE: + case GI_INFO_TYPE_UNRESOLVED: + default: + /* Doesn’t have methods — ignore. */ + break; + } + + g_base_info_unref (_info); } } /* Double-check that this isn’t a shadowed function, since the parameter * information from shadowed functions doesn’t match up with what Clang * has parsed. */ - if (info != NULL && - g_base_info_get_type (info) == GI_INFO_TYPE_FUNCTION && - func_name != g_function_info_get_symbol (info)) { - DEBUG ("Ignoring function " << func_name << "() due to " - "mismatch with C symbol ‘" << - g_function_info_get_symbol (info) << "’."); - - g_base_info_unref (info); - info = NULL; - } + assert (info == NULL || + (g_base_info_get_type (info) == GI_INFO_TYPE_FUNCTION && + func_name == g_function_info_get_symbol (info))); return info; } |