diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-05-24 22:40:37 +0100 |
---|---|---|
committer | Philip Withnall <philip.withnall@collabora.co.uk> | 2014-05-24 22:40:37 +0100 |
commit | 48fea04635f4247e63d49f271974c9eedbf55257 (patch) | |
tree | fe92a8315ca1e031526d949a785613682acca4bb /clang-plugin | |
parent | d2abb89006cfe6d68ca8f522983c79f0408f8f23 (diff) |
clang-plugin: Move type lookups out into a new TypeManager
This implements caching of the looked up types (which should improve
performance) and also centralises the implementation so it can be used
by other checkers.
Diffstat (limited to 'clang-plugin')
-rw-r--r-- | clang-plugin/gsignal-checker.cpp | 103 | ||||
-rw-r--r-- | clang-plugin/gsignal-checker.h | 5 | ||||
-rw-r--r-- | clang-plugin/type-manager.cpp | 89 | ||||
-rw-r--r-- | clang-plugin/type-manager.h | 50 |
4 files changed, 178 insertions, 69 deletions
diff --git a/clang-plugin/gsignal-checker.cpp b/clang-plugin/gsignal-checker.cpp index f28a932..7ecf189 100644 --- a/clang-plugin/gsignal-checker.cpp +++ b/clang-plugin/gsignal-checker.cpp @@ -177,56 +177,14 @@ _gobject_look_up_signal (GIObjectInfo *dynamic_gobject_info, return signal_info; } -/* Find a #QualType for the typedeffed type with the given @name. This is a very - * slow call (it requires iterating through all defined types in the given - * @context), so its results should be cached where possible (FIXME: do this). - * - * If type lookup fails, a null type is returned. */ -static const QualType -_find_type_by_name (const ASTContext &context, const std::string name) -{ - for (ASTContext::const_type_iterator it = context.types_begin (), - ie = context.types_end (); it != ie; ++it) { - const Type *t = *it; - const TypedefType *tt = t->getAs<TypedefType> (); - - if (tt != NULL) { - const TypedefNameDecl *decl = tt->getDecl (); - - if (decl->getName () == name) { - DEBUG ("Found type ‘" << name << "’ with " - "desugared type ‘" << - tt->desugar ().getAsString () << "’."); - - return QualType (tt, 0); - } - } - } - - DEBUG ("Failed to find type ‘" << name << "’."); - - return QualType (); -} - -/* Version of _find_type_by_name() which makes it a pointer type. */ -static const QualType -_find_pointer_type_by_name (const ASTContext &context, const std::string name) -{ - QualType qt = _find_type_by_name (context, name); - if (!qt.isNull ()) { - return context.getPointerType (qt); - } - - return QualType (); -} - /* Look up the #QualType representing the type in @type_info, which must be * a %GI_TYPE_TAG_INTERFACE info. If type lookup fails, a null type is * returned. */ static QualType _type_interface_info_to_type (GITypeInfo *type_info, const ASTContext &context, - const GirManager &gir_manager) + const GirManager &gir_manager, + TypeManager &type_manager) { GIBaseInfo *interface_info; QualType retval; @@ -244,7 +202,7 @@ _type_interface_info_to_type (GITypeInfo *type_info, case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_UNION: { std::string c_type (gir_manager.get_c_name_for_type (interface_info)); - retval = _find_pointer_type_by_name (context, c_type); + retval = type_manager.find_pointer_type_by_name (c_type); break; } case GI_INFO_TYPE_FUNCTION: @@ -280,14 +238,16 @@ _type_interface_info_to_type (GITypeInfo *type_info, static QualType _type_info_to_type (GITypeInfo *type_info, const ASTContext &context, - const GirManager &gir_manager); + const GirManager &gir_manager, + TypeManager &type_manager); /* Look up the #QualType representing the type in @array_info, which must be * a %GI_TYPE_TAG_ARRAY info. If type lookup fails, a null type is returned. */ static QualType _type_array_info_to_type (GITypeInfo *array_info, const ASTContext &context, - const GirManager &gir_manager) + const GirManager &gir_manager, + TypeManager &type_manager) { switch (g_type_info_get_array_type (array_info)) { case GI_ARRAY_TYPE_C: { @@ -295,7 +255,8 @@ _type_array_info_to_type (GITypeInfo *array_info, GITypeInfo *param_type = g_type_info_get_param_type (array_info, 0); QualType element_type = _type_info_to_type (param_type, context, - gir_manager); + gir_manager, + type_manager); g_base_info_unref (param_type); if (element_type.isNull ()) { @@ -321,11 +282,11 @@ _type_array_info_to_type (GITypeInfo *array_info, } } case GI_ARRAY_TYPE_ARRAY: - return _find_pointer_type_by_name (context, "GArray"); + return type_manager.find_pointer_type_by_name ("GArray"); case GI_ARRAY_TYPE_PTR_ARRAY: - return _find_pointer_type_by_name (context, "GPtrArray"); + return type_manager.find_pointer_type_by_name ("GPtrArray"); case GI_ARRAY_TYPE_BYTE_ARRAY: - return _find_pointer_type_by_name (context, "GByteArray"); + return type_manager.find_pointer_type_by_name ("GByteArray"); default: llvm::errs () << "Warning: Unexpected array type " << g_type_info_get_array_type (array_info) << @@ -340,7 +301,8 @@ _type_array_info_to_type (GITypeInfo *array_info, static QualType _type_info_to_type (GITypeInfo *type_info, const ASTContext &context, - const GirManager &gir_manager) + const GirManager &gir_manager, + TypeManager &type_manager) { switch (g_type_info_get_tag (type_info)) { /* Basic types. */ @@ -380,18 +342,18 @@ _type_info_to_type (GITypeInfo *type_info, /* Non-basic types */ case GI_TYPE_TAG_ARRAY: return _type_array_info_to_type (type_info, context, - gir_manager); + gir_manager, type_manager); case GI_TYPE_TAG_INTERFACE: return _type_interface_info_to_type (type_info, context, - gir_manager); + gir_manager, type_manager); case GI_TYPE_TAG_GLIST: - return _find_pointer_type_by_name (context, "GList"); + return type_manager.find_pointer_type_by_name ("GList"); case GI_TYPE_TAG_GSLIST: - return _find_pointer_type_by_name (context, "GSList"); + return type_manager.find_pointer_type_by_name ("GSList"); case GI_TYPE_TAG_GHASH: - return _find_pointer_type_by_name (context, "GHashTable"); + return type_manager.find_pointer_type_by_name ("GHashTable"); case GI_TYPE_TAG_ERROR: { - QualType qt = _find_pointer_type_by_name (context, "GError"); + QualType qt = type_manager.find_pointer_type_by_name ("GError"); if (!qt.isNull ()) { return context.getPointerType (qt); @@ -449,7 +411,8 @@ _check_signal_callback_type (const Expr *expr, GISignalInfo *signal_info, CompilerInstance &compiler, const ASTContext &context, - const GirManager &gir_manager) + const GirManager &gir_manager, + TypeManager &type_manager) { const FunctionProtoType *callback_type = NULL; SourceRange decl_range; /* for the callback definition */ @@ -500,7 +463,8 @@ _check_signal_callback_type (const Expr *expr, dynamic_gobject_info, static_gobject_info, signal_info, compiler, - context, gir_manager); + context, gir_manager, + type_manager); } case Stmt::StmtClass::ImplicitCastExprClass: case Stmt::StmtClass::CStyleCastExprClass: { @@ -511,7 +475,8 @@ _check_signal_callback_type (const Expr *expr, dynamic_gobject_info, static_gobject_info, signal_info, compiler, - context, gir_manager); + context, gir_manager, + type_manager); } case Stmt::StmtClass::NoStmtClass: default: @@ -555,8 +520,7 @@ _check_signal_callback_type (const Expr *expr, /* First argument is always a pointer to the GObject * instance which the signal is defined on. */ std::string c_type (gir_manager.get_c_name_for_type (static_gobject_info)); - expected_type = _find_pointer_type_by_name (context, - c_type); + expected_type = type_manager.find_pointer_type_by_name (c_type); arg_name = "self"; QualType atp = actual_type; @@ -637,7 +601,8 @@ _check_signal_callback_type (const Expr *expr, expected_type = _type_info_to_type (&expected_type_info, context, - gir_manager); + gir_manager, + type_manager); if (expected_type.isNull ()) { /* Error. */ @@ -696,7 +661,7 @@ _check_signal_callback_type (const Expr *expr, g_callable_info_load_return_type (callable_info, &expected_type_info); actual_type = callback_type->getResultType (); expected_type = _type_info_to_type (&expected_type_info, context, - gir_manager); + gir_manager, type_manager); if (expected_type.isNull ()) { /* Error. */ @@ -743,7 +708,8 @@ _check_gsignal_callback_type (const CallExpr &call, const SignalFuncInfo *func_info, CompilerInstance &compiler, const ASTContext &context, - const GirManager &gir_manager) + const GirManager &gir_manager, + TypeManager &type_manager) { const Expr *callback_arg, *gobject_arg, *signal_name_arg; @@ -846,7 +812,8 @@ _check_gsignal_callback_type (const CallExpr &call, if (!_check_signal_callback_type (callback_arg->IgnoreParenImpCasts (), dynamic_gobject_info, static_gobject_info, signal_info, - compiler, context, gir_manager)) { + compiler, context, gir_manager, + type_manager)) { /* A diagnostic has already been emitted by * _check_signal_callback_type(). */ g_base_info_unref (signal_info); @@ -896,7 +863,7 @@ GSignalVisitor::VisitCallExpr (CallExpr* expr) const GirManager *gir_manager = this->_gir_manager.get (); _check_gsignal_callback_type (*expr, *func, func_info, this->_compiler, func->getASTContext (), - *gir_manager); + *gir_manager, this->_type_manager); return true; } diff --git a/clang-plugin/gsignal-checker.h b/clang-plugin/gsignal-checker.h index 4119b23..9ca86fc 100644 --- a/clang-plugin/gsignal-checker.h +++ b/clang-plugin/gsignal-checker.h @@ -32,6 +32,7 @@ #include "checker.h" #include "gir-manager.h" +#include "type-manager.h" namespace tartan { @@ -42,12 +43,14 @@ public: explicit GSignalVisitor (CompilerInstance& compiler, std::shared_ptr<const GirManager> gir_manager) : _compiler (compiler), _context (compiler.getASTContext ()), - _gir_manager (gir_manager) {} + _gir_manager (gir_manager), + _type_manager (compiler.getASTContext ()) {} private: CompilerInstance& _compiler; const ASTContext& _context; std::shared_ptr<const GirManager> _gir_manager; + TypeManager _type_manager; public: bool VisitCallExpr (CallExpr* call); diff --git a/clang-plugin/type-manager.cpp b/clang-plugin/type-manager.cpp new file mode 100644 index 0000000..4a28cce --- /dev/null +++ b/clang-plugin/type-manager.cpp @@ -0,0 +1,89 @@ +/* -*- Mode: C++; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Tartan + * Copyright © 2014 Collabora Ltd. + * + * Tartan is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tartan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tartan. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Philip Withnall <philip.withnall@collabora.co.uk> + */ + +#include <unordered_map> + +#include <clang/AST/Attr.h> +#include <clang/Lex/Lexer.h> + +#include "type-manager.h" +#include "debug.h" + +namespace tartan { + +/* Find a #QualType for the typedeffed type with the given @name. This is a very + * slow call (it requires iterating through all defined types in the given + * @context), so its results should be cached where possible (FIXME: do this). + * + * If type lookup fails, a null type is returned. */ +const QualType +TypeManager::find_type_by_name (const std::string name) +{ + /* Look up the type in the cache first. */ + std::unordered_map<std::string, QualType>::const_iterator cached = + this->_type_cache.find (name); + if (cached != this->_type_cache.end ()) { + return (*cached).second; + } + + for (ASTContext::const_type_iterator it = this->_context.types_begin (), + ie = this->_context.types_end (); it != ie; ++it) { + const Type *t = *it; + const TypedefType *tt = t->getAs<TypedefType> (); + + if (tt != NULL) { + const TypedefNameDecl *decl = tt->getDecl (); + + if (decl->getName () == name) { + DEBUG ("Found type ‘" << name << "’ with " + "desugared type ‘" << + tt->desugar ().getAsString () << "’."); + + QualType qt (tt, 0); + + /* Insert it into the cache. */ + std::string _name (name); + this->_type_cache.emplace (_name, qt); + + return qt; + } + } + } + + DEBUG ("Failed to find type ‘" << name << "’."); + + return QualType (); +} + +/* Version of _find_type_by_name() which makes it a pointer type. */ +const QualType +TypeManager::find_pointer_type_by_name (const std::string name) +{ + QualType qt = this->find_type_by_name (name); + if (!qt.isNull ()) { + return this->_context.getPointerType (qt); + } + + return QualType (); +} + +} /* namespace tartan */ diff --git a/clang-plugin/type-manager.h b/clang-plugin/type-manager.h new file mode 100644 index 0000000..edb1fee --- /dev/null +++ b/clang-plugin/type-manager.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * Tartan + * Copyright © 2014 Collabora Ltd. + * + * Tartan is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tartan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tartan. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Philip Withnall <philip.withnall@collabora.co.uk> + */ + +#ifndef TARTAN_TYPE_MANAGER_H +#define TARTAN_TYPE_MANAGER_H + +#include <unordered_map> + +#include <clang/AST/ASTContext.h> + +namespace tartan { + +using namespace clang; + +class TypeManager { +public: + explicit TypeManager (const ASTContext &context) : + _context (context) {}; + + const QualType find_type_by_name (const std::string name); + const QualType find_pointer_type_by_name (const std::string name); + +private: + const ASTContext &_context; + + std::unordered_map<std::string, QualType> _type_cache; +}; + +} /* namespace tartan */ + +#endif /* !TARTAN_TYPE_MANAGER_H */ |