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