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 ¶mType, 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