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