File indexing completed on 2024-04-21 05:38:49
0001 /* 0002 SPDX-FileCopyrightText: 2016-2017 Sergio Martins <smartins@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef CLAZY_TYPE_UTILS_H 0008 #define CLAZY_TYPE_UTILS_H 0009 0010 #include <clang/AST/ASTContext.h> 0011 #include <clang/AST/Decl.h> 0012 #include <clang/AST/DeclCXX.h> 0013 #include <clang/AST/Expr.h> 0014 #include <clang/AST/StmtCXX.h> 0015 #include <clang/AST/Type.h> 0016 #include <llvm/Support/Casting.h> 0017 0018 #include <string> 0019 #include <vector> 0020 0021 namespace clang 0022 { 0023 class CompilerInstance; 0024 class Expr; 0025 class LangOptions; 0026 class QualType; 0027 class Stmt; 0028 class VarDecl; 0029 class Type; 0030 class CXXRecordDecl; 0031 class CXXBaseSpecifier; 0032 } 0033 0034 class ClazyContext; 0035 0036 namespace clazy 0037 { 0038 /** 0039 * Returns the sizeof(void*) for the platform we're compiling for, in bits. 0040 */ 0041 inline int sizeOfPointer(const clang::ASTContext *context, clang::QualType qt) 0042 { 0043 if (!qt.getTypePtrOrNull()) { 0044 return -1; 0045 } 0046 // HACK: What's a better way of getting the size of a pointer ? 0047 return context->getTypeSize(context->getPointerType(qt)); 0048 } 0049 0050 struct QualTypeClassification { 0051 bool isConst = false; 0052 bool isReference = false; 0053 bool isBig = false; 0054 bool isNonTriviallyCopyable = false; 0055 bool passBigTypeByConstRef = false; 0056 bool passNonTriviallyCopyableByConstRef = false; 0057 bool passSmallTrivialByValue = false; 0058 int size_of_T = 0; 0059 }; 0060 0061 /** 0062 * Classifies a QualType, for example: 0063 * 0064 * This function is useful to know if a type should be passed by value or const-ref. 0065 * The optional parameter body is in order to advise non-const-ref -> value, since the body 0066 * needs to be inspected to see if we that would compile. 0067 */ 0068 bool classifyQualType(const ClazyContext *context, 0069 clang::QualType qualType, 0070 const clang::VarDecl *varDecl, 0071 QualTypeClassification &classification, 0072 clang::Stmt *body = nullptr); 0073 0074 /** 0075 * @brief Lighter version of classifyQualType in case you just want to know if it's small and trivially copyable&destructible 0076 * @param context The clazy context 0077 * @param qualType The QualType we're testing. 0078 * @return true if the type specified by QualType (or its pointee) are small and trivially copyable/destructible. 0079 */ 0080 bool isSmallTrivial(const ClazyContext *context, clang::QualType qualType); 0081 0082 /** 0083 * If qt is a reference, return it without a reference. 0084 * If qt is not a reference, return qt. 0085 * 0086 * This is useful because sometimes you have an argument like "const QString &", but qualType.isConstQualified() 0087 * returns false. Must go through qualType->getPointeeType().isConstQualified(). 0088 */ 0089 inline clang::QualType unrefQualType(clang::QualType qualType) 0090 { 0091 const clang::Type *t = qualType.getTypePtrOrNull(); 0092 return (t && t->isReferenceType()) ? t->getPointeeType() : qualType; 0093 } 0094 0095 /** 0096 * If qt is a pointer or ref, return it without * or &. 0097 * Otherwise return qt unchanged. 0098 */ 0099 inline clang::QualType pointeeQualType(clang::QualType qualType) 0100 { 0101 // TODO: Make this recursive when we need to remove more than one level of * 0102 const clang::Type *t = qualType.getTypePtrOrNull(); 0103 return (t && (t->isReferenceType() || t->isPointerType())) ? t->getPointeeType() : qualType; 0104 } 0105 0106 /** 0107 * Returns if @p arg is stack or heap allocated. 0108 * true means it is. false means it either isn't or the situation was too complex to judge. 0109 */ 0110 void heapOrStackAllocated(clang::Expr *arg, const std::string &type, const clang::LangOptions &lo, bool &isStack, bool &isHeap); 0111 0112 /** 0113 * Returns true if t is an AutoType that can't be deduced. 0114 */ 0115 inline bool isUndeducibleAuto(const clang::Type *t) 0116 { 0117 if (!t) { 0118 return false; 0119 } 0120 0121 const auto *at = llvm::dyn_cast<clang::AutoType>(t); 0122 return at && at->getDeducedType().isNull(); 0123 } 0124 0125 inline const clang::Type *unpealAuto(clang::QualType q) 0126 { 0127 if (q.isNull()) { 0128 return nullptr; 0129 } 0130 0131 if (const auto *t = llvm::dyn_cast<clang::AutoType>(q.getTypePtr())) { 0132 return t->getDeducedType().getTypePtrOrNull(); 0133 } 0134 0135 return q.getTypePtr(); 0136 } 0137 0138 /** 0139 * Returns true if childDecl is a descent from parentDecl 0140 **/ 0141 bool derivesFrom(const clang::CXXRecordDecl *derived, const clang::CXXRecordDecl *possibleBase, std::vector<clang::CXXRecordDecl *> *baseClasses = nullptr); 0142 0143 // Overload 0144 bool derivesFrom(const clang::CXXRecordDecl *derived, const std::string &possibleBase); 0145 0146 // Overload 0147 bool derivesFrom(clang::QualType derived, const std::string &possibleBase); 0148 0149 /** 0150 * Returns the CXXRecordDecl represented by the CXXBaseSpecifier 0151 */ 0152 inline clang::CXXRecordDecl *recordFromBaseSpecifier(const clang::CXXBaseSpecifier &base) 0153 { 0154 const clang::Type *t = base.getType().getTypePtrOrNull(); 0155 return t ? t->getAsCXXRecordDecl() : nullptr; 0156 } 0157 /** 0158 * Returns true if the value is const. This is usually equivalent to qt.isConstQualified() but 0159 * takes care of the special case where qt represents a pointer. Many times you don't care if the 0160 * pointer is const or not and just care about the pointee. 0161 * 0162 * A a; => false 0163 * const A a; => true 0164 * A* a; => false 0165 * const A* a; => true 0166 * A *const a; => false 0167 */ 0168 inline bool valueIsConst(clang::QualType qt) 0169 { 0170 return pointeeQualType(qt).isConstQualified(); 0171 } 0172 0173 inline clang::CXXRecordDecl *typeAsRecord(clang::QualType qt) 0174 { 0175 if (qt.isNull()) { 0176 return nullptr; 0177 } 0178 0179 return qt->getAsCXXRecordDecl(); 0180 } 0181 0182 inline clang::CXXRecordDecl *typeAsRecord(clang::Expr *expr) 0183 { 0184 if (!expr) { 0185 return nullptr; 0186 } 0187 0188 return typeAsRecord(pointeeQualType(expr->getType())); 0189 } 0190 0191 inline clang::CXXRecordDecl *typeAsRecord(clang::ValueDecl *value) 0192 { 0193 if (!value) { 0194 return nullptr; 0195 } 0196 0197 return typeAsRecord(pointeeQualType(value->getType())); 0198 } 0199 0200 /** 0201 * Returns the class that the typedef refered by qt is in. 0202 * 0203 * class Foo { 0204 * typedef A B; 0205 * }; 0206 * 0207 * For the above example Foo would be returned. 0208 */ 0209 inline clang::CXXRecordDecl *parentRecordForTypedef(clang::QualType qt) 0210 { 0211 auto *t = qt.getTypePtrOrNull(); 0212 0213 if (const auto *elab = llvm::dyn_cast<clang::ElaboratedType>(t)) { 0214 t = elab->desugar().getTypePtrOrNull(); 0215 } 0216 0217 if (const auto *tdt = llvm::dyn_cast<clang::TypedefType>(t)) { 0218 clang::TypedefNameDecl *tdnd = tdt->getDecl(); 0219 return llvm::dyn_cast_or_null<clang::CXXRecordDecl>(tdnd->getDeclContext()); 0220 } 0221 0222 return nullptr; 0223 } 0224 0225 // Example: const QString & 0226 inline bool isConstRef(const clang::Type *t) 0227 { 0228 return t && t->isReferenceType() && t->getPointeeType().isConstQualified(); 0229 } 0230 } 0231 0232 #endif