File indexing completed on 2024-04-21 05:38:48

0001 /*
0002     SPDX-FileCopyrightText: 2015-2016 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef CLAZY_QT_UTILS_H
0008 #define CLAZY_QT_UTILS_H
0009 
0010 #include "StringUtils.h"
0011 #include "Utils.h"
0012 #include "clazy_stl.h"
0013 
0014 #include <clang/AST/ASTContext.h>
0015 #include <clang/AST/Decl.h>
0016 #include <clang/AST/DeclCXX.h>
0017 #include <clang/AST/DeclTemplate.h>
0018 #include <clang/AST/Expr.h>
0019 #include <clang/AST/OperationKinds.h>
0020 #include <clang/AST/Stmt.h>
0021 #include <clang/AST/TemplateBase.h>
0022 #include <clang/AST/Type.h>
0023 #include <clang/Basic/SourceLocation.h>
0024 #include <llvm/ADT/StringRef.h>
0025 #include <llvm/Support/Casting.h>
0026 
0027 #include <string>
0028 #include <unordered_map>
0029 #include <vector>
0030 
0031 namespace clang
0032 {
0033 class CXXRecordDecl;
0034 class CompilerInstance;
0035 class Type;
0036 class CXXMemberCallExpr;
0037 class CallExpr;
0038 class ValueDecl;
0039 class LangOptions;
0040 class QualType;
0041 class VarDecl;
0042 class SourceLocation;
0043 class FunctionDecl;
0044 class UnaryOperator;
0045 class CXXMethodDecl;
0046 class Expr;
0047 class PreprocessorOptions;
0048 class SourceManager;
0049 }
0050 
0051 struct StmtBodyRange;
0052 
0053 namespace clazy
0054 {
0055 /**
0056  * Returns true if the class is a Qt class which can be iterated with foreach.
0057  * Which means all containers and also stuff like QAssociativeIterable.
0058  */
0059 bool isQtIterableClass(clang::CXXRecordDecl *record);
0060 
0061 /**
0062  * Overload.
0063  */
0064 bool isQtIterableClass(llvm::StringRef className);
0065 
0066 /**
0067  * Returns true if the method is of QMetaMethod type
0068  */
0069 bool isQMetaMethod(clang::CallExpr *call, unsigned int argIndex);
0070 /**
0071  * Returns true if the class is a Qt class which can be iterated with foreach and also implicitly shared.
0072  */
0073 bool isQtCOWIterableClass(clang::CXXRecordDecl *record);
0074 
0075 /**
0076  * Overload.
0077  */
0078 bool isQtCOWIterableClass(const std::string &className);
0079 
0080 /**
0081  * Returns if the iterators belongs to a COW container
0082  */
0083 inline bool isQtCOWIterator(clang::CXXRecordDecl *itRecord)
0084 {
0085     if (!itRecord) {
0086         return false;
0087     }
0088 
0089     auto *parent = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(itRecord->getParent());
0090     return parent && clazy::isQtCOWIterableClass(parent);
0091 }
0092 
0093 /**
0094  * Returns true if the class is a Qt class which is an associative container (QHash, QMap, QSet)
0095  */
0096 bool isQtAssociativeContainer(clang::CXXRecordDecl *record);
0097 
0098 /**
0099  * Overload.
0100  */
0101 bool isQtAssociativeContainer(llvm::StringRef className);
0102 
0103 /**
0104  * Returns a list of Qt containers.
0105  */
0106 const std::vector<llvm::StringRef> &qtContainers();
0107 
0108 /**
0109  * Returns a list of implicitly shared Qt containers.
0110  */
0111 const std::vector<llvm::StringRef> &qtCOWContainers();
0112 
0113 /**
0114  * Returns a map with the list of method names that detach each container.
0115  */
0116 std::unordered_map<std::string, std::vector<llvm::StringRef>> detachingMethods();
0117 
0118 /**
0119  * Returns a map with the list of method names that detach each container, but only those methods
0120  * with const counterparts.
0121  */
0122 std::unordered_map<std::string, std::vector<llvm::StringRef>> detachingMethodsWithConstCounterParts();
0123 
0124 /**
0125  * Returns true if a type represents a Qt container class.
0126  */
0127 bool isQtContainer(clang::QualType);
0128 
0129 bool isQtContainer(const clang::CXXRecordDecl *);
0130 
0131 /**
0132  * Returns true if -DQT_BOOTSTRAPPED was passed to the compiler
0133  */
0134 bool isBootstrapping(const clang::PreprocessorOptions &ppOpts);
0135 
0136 /**
0137  * Returns if decl is or derives from QObject
0138  */
0139 bool isQObject(const clang::CXXRecordDecl *decl);
0140 
0141 /**
0142  * Overload.
0143  */
0144 bool isQObject(clang::QualType);
0145 
0146 /**
0147  * Convertible means that a signal with of type source can connect to a signal/slot of type target
0148  */
0149 bool isConvertibleTo(const clang::Type *source, const clang::Type *target);
0150 
0151 /**
0152  * Returns true if \a loc is in a foreach macro
0153  */
0154 bool isInForeach(const clang::ASTContext *context, clang::SourceLocation loc);
0155 
0156 /**
0157  * Returns true if \a record is a java-style iterator
0158  */
0159 bool isJavaIterator(clang::CXXRecordDecl *record);
0160 
0161 bool isJavaIterator(clang::CXXMemberCallExpr *call);
0162 
0163 /**
0164  * Returns true if a class has a ctor that has a parameter of type paramType.
0165  * ok will be false if an error occurred, or if the record is a fwd declaration, which isn't enough
0166  * for we to find out the signature.
0167  * numCtors will have the number of constructors analyized.
0168  */
0169 bool recordHasCtorWithParam(clang::CXXRecordDecl *record, const std::string &paramType, bool &ok, int &numCtors);
0170 
0171 /**
0172  * Returns true if recordDecl is one of the container classes that supports reserve(), such
0173  * as QList, QVector, etc.
0174  */
0175 bool isAReserveClass(clang::CXXRecordDecl *recordDecl);
0176 
0177 /**
0178  * Returns the base class that inherits QObject.
0179  * Useful when the class has more than one base class and we're only interested in the QObject one.
0180  */
0181 clang::CXXRecordDecl *getQObjectBaseClass(clang::CXXRecordDecl *recordDecl);
0182 
0183 /**
0184  * Returns true if the function declaration is QObject::connect().
0185  */
0186 bool isConnect(clang::FunctionDecl *func);
0187 /**
0188  * Returns true if the function declaration represents a QObject::connect() using the new Qt5
0189  * (pointer to member) syntax.
0190  *
0191  * It's assumed that func represents a connect().
0192  */
0193 bool connectHasPMFStyle(clang::FunctionDecl *func);
0194 
0195 /**
0196  * Returns the method referenced by a PMF-style connect for the specified connect() call.
0197  */
0198 clang::CXXMethodDecl *pmfFromConnect(clang::CallExpr *funcCall, int argIndex);
0199 
0200 clang::CXXMethodDecl *pmfFromExpr(clang::Expr *e);
0201 clang::CXXMethodDecl *pmfFromUnary(clang::UnaryOperator *uo);
0202 
0203 /**
0204  * Returns the varDecl for the 1st argument in a connect call
0205  */
0206 clang::ValueDecl *signalSenderForConnect(clang::CallExpr *call);
0207 
0208 /**
0209  * Returns the varDecl for 3rd argument in connects that are passed an explicit
0210  * receiver or context QObject.
0211  */
0212 clang::ValueDecl *signalReceiverForConnect(clang::CallExpr *call);
0213 
0214 /**
0215  * Returns the receiver method, in a PMF connect statement.
0216  * The method can be a slot or a signal. If it's a lambda or functor nullptr is returned
0217  */
0218 inline clang::CXXMethodDecl *receiverMethodForConnect(clang::CallExpr *call)
0219 {
0220     clang::CXXMethodDecl *receiverMethod = clazy::pmfFromConnect(call, 2);
0221     if (receiverMethod) {
0222         return receiverMethod;
0223     }
0224 
0225     // It's either third or fourth argument
0226     return clazy::pmfFromConnect(call, 3);
0227 }
0228 
0229 inline bool isUIFile(clang::SourceLocation loc, const clang::SourceManager &sm)
0230 {
0231     const std::string filename = Utils::filenameForLoc(loc, sm);
0232     return clazy::startsWith(filename, "ui_") && clazy::endsWith(filename, ".h");
0233 }
0234 
0235 }
0236 
0237 #endif