diff options
Diffstat (limited to 'src/QtUtils.h')
-rw-r--r-- | src/QtUtils.h | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/src/QtUtils.h b/src/QtUtils.h index 30c61f92..fcd421f0 100644 --- a/src/QtUtils.h +++ b/src/QtUtils.h @@ -53,7 +53,7 @@ class Expr; struct StmtBodyRange; -namespace QtUtils +namespace clazy { /** @@ -65,7 +65,7 @@ CLAZYLIB_EXPORT bool isQtIterableClass(clang::CXXRecordDecl *record); /** * Overload. */ -CLAZYLIB_EXPORT bool isQtIterableClass(const std::string &className); +CLAZYLIB_EXPORT bool isQtIterableClass(llvm::StringRef className); /** * Returns true if the class is a Qt class which can be iterated with foreach and also implicitly shared. @@ -86,7 +86,7 @@ inline bool isQtCOWIterator(clang::CXXRecordDecl *itRecord) return false; auto parent = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(itRecord->getParent()); - return parent && QtUtils::isQtCOWIterableClass(parent); + return parent && clazy::isQtCOWIterableClass(parent); } /** @@ -97,41 +97,49 @@ CLAZYLIB_EXPORT bool isQtAssociativeContainer(clang::CXXRecordDecl *record); /** * Overload. */ -CLAZYLIB_EXPORT bool isQtAssociativeContainer(const std::string &className); +CLAZYLIB_EXPORT bool isQtAssociativeContainer(llvm::StringRef className); /** * Returns a list of Qt containers. */ -CLAZYLIB_EXPORT const std::vector<std::string> & qtContainers(); +CLAZYLIB_EXPORT const std::vector<llvm::StringRef> & qtContainers(); /** * Returns a list of implicitly shared Qt containers. */ -CLAZYLIB_EXPORT const std::vector<std::string> & qtCOWContainers(); +CLAZYLIB_EXPORT const std::vector<llvm::StringRef> & qtCOWContainers(); /** * Returns a map with the list of method names that detach each container. */ -CLAZYLIB_EXPORT std::unordered_map<std::string, std::vector<std::string>> detachingMethods(); +CLAZYLIB_EXPORT std::unordered_map<std::string, std::vector<llvm::StringRef> > detachingMethods(); + +/** + * Returns a map with the list of method names that detach each container, but only those methods + * with const counterparts. + */ +CLAZYLIB_EXPORT std::unordered_map<std::string, std::vector<llvm::StringRef> > detachingMethodsWithConstCounterParts(); /** * Returns true if a type represents a Qt container class. */ CLAZYLIB_EXPORT bool isQtContainer(clang::QualType); +CLAZYLIB_EXPORT bool isQtContainer(const clang::CXXRecordDecl *); + /** * Returns true if -DQT_BOOTSTRAPPED was passed to the compiler */ inline bool isBootstrapping(const clang::PreprocessorOptions &ppOpts) { - return MacroUtils::isPredefined(ppOpts, "QT_BOOTSTRAPPED"); + return clazy::isPredefined(ppOpts, "QT_BOOTSTRAPPED"); } /** * Returns if decl is or derives from QObject */ -CLAZYLIB_EXPORT bool isQObject(clang::CXXRecordDecl *decl); +CLAZYLIB_EXPORT bool isQObject(const clang::CXXRecordDecl *decl); /** * Overload. @@ -148,7 +156,7 @@ CLAZYLIB_EXPORT bool isConvertibleTo(const clang::Type *source, const clang::Typ */ inline bool isInForeach(const clang::ASTContext *context, clang::SourceLocation loc) { - return MacroUtils::isInAnyMacro(context, loc, { "Q_FOREACH", "foreach" }); + return clazy::isInAnyMacro(context, loc, { "Q_FOREACH", "foreach" }); } /** @@ -226,7 +234,7 @@ CLAZYLIB_EXPORT clang::CXXMethodDecl* pmfFromUnary(clang::UnaryOperator *uo); */ inline clang::ValueDecl *signalSenderForConnect(clang::CallExpr *call) { - return FunctionUtils::valueDeclForCallArgument(call, 0); + return clazy::valueDeclForCallArgument(call, 0); } /** @@ -238,7 +246,7 @@ inline clang::ValueDecl *signalReceiverForConnect(clang::CallExpr *call) if (!call || call->getNumArgs() < 5) return nullptr; - return FunctionUtils::valueDeclForCallArgument(call, 3); + return clazy::valueDeclForCallArgument(call, 3); } /** @@ -248,12 +256,53 @@ inline clang::ValueDecl *signalReceiverForConnect(clang::CallExpr *call) inline clang::CXXMethodDecl* receiverMethodForConnect(clang::CallExpr *call) { - clang::CXXMethodDecl *receiverMethod = QtUtils::pmfFromConnect(call, 2); + clang::CXXMethodDecl *receiverMethod = clazy::pmfFromConnect(call, 2); if (receiverMethod) return receiverMethod; // It's either third or fourth argument - return QtUtils::pmfFromConnect(call, 3); + return clazy::pmfFromConnect(call, 3); +} + + +// Returns if callExpr is a call to qobject_cast() +inline bool is_qobject_cast(clang::Stmt *s, clang::CXXRecordDecl **castTo = nullptr, + clang::CXXRecordDecl **castFrom = nullptr) +{ + if (auto callExpr = llvm::dyn_cast<clang::CallExpr>(s)) { + clang::FunctionDecl *func = callExpr->getDirectCallee(); + if (!func || clazy::name(func) != "qobject_cast") + return false; + + if (castFrom) { + clang::Expr *expr = callExpr->getArg(0); + if (auto implicitCast = llvm::dyn_cast<clang::ImplicitCastExpr>(expr)) { + if (implicitCast->getCastKind() == clang::CK_DerivedToBase) { + expr = implicitCast->getSubExpr(); + } + } + clang::QualType qt = TypeUtils::pointeeQualType(expr->getType()); + if (!qt.isNull()) { + clang::CXXRecordDecl *record = qt->getAsCXXRecordDecl(); + *castFrom = record ? record->getCanonicalDecl() : nullptr; + } + } + + if (castTo) { + auto templateArgs = func->getTemplateSpecializationArgs(); + if (templateArgs->size() == 1) { + const clang::TemplateArgument &arg = templateArgs->get(0); + clang::QualType qt = TypeUtils::pointeeQualType(arg.getAsType()); + if (!qt.isNull()) { + clang::CXXRecordDecl *record = qt->getAsCXXRecordDecl(); + *castTo = record ? record->getCanonicalDecl() : nullptr; + } + } + } + return true; + } + + return false; } } |