aboutsummaryrefslogtreecommitdiffstats
path: root/src/QtUtils.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/QtUtils.h')
-rw-r--r--src/QtUtils.h77
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;
}
}