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 #include "TypeUtils.h"
0008 #include "ClazyContext.h"
0009 #include "HierarchyUtils.h"
0010 #include "StmtBodyRange.h"
0011 #include "StringUtils.h"
0012 #include "Utils.h"
0013 
0014 #include <clang/AST/ASTContext.h>
0015 #include <clang/AST/DeclCXX.h>
0016 #include <clang/AST/Expr.h>
0017 #include <clang/AST/ExprCXX.h>
0018 #include <clang/AST/Stmt.h>
0019 #include <clang/AST/Type.h>
0020 #include <clang/Basic/LLVM.h>
0021 
0022 using namespace clang;
0023 
0024 bool clazy::classifyQualType(const ClazyContext *context, clang::QualType qualType, const VarDecl *varDecl, QualTypeClassification &classif, clang::Stmt *body)
0025 {
0026     QualType unrefQualType = clazy::unrefQualType(qualType);
0027     const Type *paramType = unrefQualType.getTypePtrOrNull();
0028     if (!paramType || paramType->isIncompleteType()) {
0029         return false;
0030     }
0031 
0032     if (isUndeducibleAuto(paramType)) {
0033         return false;
0034     }
0035 
0036     classif.size_of_T = context->astContext.getTypeSize(unrefQualType) / 8;
0037     classif.isBig = classif.size_of_T > 16;
0038     CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl();
0039     CXXMethodDecl *copyCtor = recordDecl ? Utils::copyCtor(recordDecl) : nullptr;
0040     classif.isNonTriviallyCopyable =
0041         recordDecl && (recordDecl->hasNonTrivialCopyConstructor() || recordDecl->hasNonTrivialDestructor() || (copyCtor && copyCtor->isDeleted()));
0042     classif.isReference = qualType->isLValueReferenceType();
0043     classif.isConst = unrefQualType.isConstQualified();
0044 
0045     if (qualType->isRValueReferenceType()) { // && ref, nothing to do here
0046         return true;
0047     }
0048 
0049     if (classif.isConst && !classif.isReference) {
0050         classif.passNonTriviallyCopyableByConstRef = classif.isNonTriviallyCopyable;
0051         if (classif.isBig) {
0052             classif.passBigTypeByConstRef = true;
0053         }
0054     } else if (classif.isConst && classif.isReference && !classif.isNonTriviallyCopyable && !classif.isBig) {
0055         classif.passSmallTrivialByValue = true;
0056     } else if (varDecl && !classif.isConst && !classif.isReference && (classif.isBig || classif.isNonTriviallyCopyable)) {
0057         if (body
0058             && (Utils::containsNonConstMemberCall(context->parentMap, body, varDecl)
0059                 || Utils::isPassedToFunction(StmtBodyRange(body), varDecl, /*byrefonly=*/true))) {
0060             return true;
0061         }
0062 
0063         classif.passNonTriviallyCopyableByConstRef = classif.isNonTriviallyCopyable;
0064         if (classif.isBig) {
0065             classif.passBigTypeByConstRef = true;
0066         }
0067     }
0068 
0069     return true;
0070 }
0071 
0072 bool clazy::isSmallTrivial(const ClazyContext *context, QualType qualType)
0073 {
0074     if (qualType.isNull()) {
0075         return false;
0076     }
0077 
0078     if (qualType->isPointerType()) {
0079         qualType = qualType->getPointeeType();
0080     }
0081 
0082     if (qualType->isPointerType()) { // We don't care about ** (We can change this whenever we have a use case)
0083         return false;
0084     }
0085 
0086     QualType unrefQualType = clazy::unrefQualType(qualType);
0087     const Type *paramType = unrefQualType.getTypePtrOrNull();
0088     if (!paramType || paramType->isIncompleteType()) {
0089         return false;
0090     }
0091 
0092     if (isUndeducibleAuto(paramType)) {
0093         return false;
0094     }
0095 
0096     if (qualType->isRValueReferenceType()) { // && ref, nothing to do here
0097         return false;
0098     }
0099 
0100     CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl();
0101     CXXMethodDecl *copyCtor = recordDecl ? Utils::copyCtor(recordDecl) : nullptr;
0102     const bool hasDeletedCopyCtor = copyCtor && copyCtor->isDeleted();
0103     const bool isTrivial = recordDecl && !recordDecl->hasNonTrivialCopyConstructor() && !recordDecl->hasNonTrivialDestructor() && !hasDeletedCopyCtor;
0104 
0105     if (isTrivial) {
0106         const auto typeSize = context->astContext.getTypeSize(unrefQualType) / 8;
0107         const bool isSmall = typeSize <= 16;
0108         return isSmall;
0109     }
0110 
0111     return false;
0112 }
0113 
0114 void clazy::heapOrStackAllocated(Expr *arg, const std::string &type, const clang::LangOptions &lo, bool &isStack, bool &isHeap)
0115 {
0116     isStack = false;
0117     isHeap = false;
0118     if (isa<CXXNewExpr>(arg)) {
0119         isHeap = true;
0120         return;
0121     }
0122 
0123     std::vector<DeclRefExpr *> declrefs;
0124     clazy::getChilds(arg, declrefs, 3);
0125 
0126     std::vector<DeclRefExpr *> interestingDeclRefs;
0127     for (auto *declref : declrefs) {
0128         const auto *t = declref->getType().getTypePtrOrNull();
0129         if (!t) {
0130             continue;
0131         }
0132 
0133         // Remove the '*' if it's a pointer
0134         QualType qt = t->isPointerType() ? t->getPointeeType() : declref->getType();
0135 
0136         if (t && type == clazy::simpleTypeName(qt, lo)) {
0137             interestingDeclRefs.push_back(declref);
0138         }
0139     }
0140 
0141     if (interestingDeclRefs.size() > 1) {
0142         // Too complex
0143         return;
0144     }
0145 
0146     if (!interestingDeclRefs.empty()) {
0147         auto *declref = interestingDeclRefs[0];
0148         isStack = !declref->getType().getTypePtr()->isPointerType();
0149         isHeap = !isStack;
0150     }
0151 }
0152 
0153 bool clazy::derivesFrom(const CXXRecordDecl *derived, const CXXRecordDecl *possibleBase, std::vector<CXXRecordDecl *> *baseClasses)
0154 {
0155     if (!derived || !possibleBase || derived == possibleBase) {
0156         return false;
0157     }
0158 
0159     for (auto base : derived->bases()) {
0160         const Type *type = base.getType().getTypePtrOrNull();
0161         if (!type) {
0162             continue;
0163         }
0164         CXXRecordDecl *baseDecl = type->getAsCXXRecordDecl();
0165         baseDecl = baseDecl ? baseDecl->getCanonicalDecl() : nullptr;
0166 
0167         if (possibleBase == baseDecl || derivesFrom(baseDecl, possibleBase, baseClasses)) {
0168             if (baseClasses) {
0169                 baseClasses->push_back(baseDecl);
0170             }
0171             return true;
0172         }
0173     }
0174 
0175     return false;
0176 }
0177 
0178 bool clazy::derivesFrom(const clang::CXXRecordDecl *derived, const std::string &possibleBase)
0179 {
0180     if (!derived || !derived->hasDefinition()) {
0181         return false;
0182     }
0183 
0184     if (derived->getQualifiedNameAsString() == possibleBase) {
0185         return true;
0186     }
0187 
0188     for (auto base : derived->bases()) {
0189         if (derivesFrom(recordFromBaseSpecifier(base), possibleBase)) {
0190             return true;
0191         }
0192     }
0193 
0194     return false;
0195 }
0196 
0197 bool clazy::derivesFrom(QualType derivedQT, const std::string &possibleBase)
0198 {
0199     derivedQT = pointeeQualType(derivedQT);
0200     const auto *const t = derivedQT.getTypePtrOrNull();
0201     return t ? derivesFrom(t->getAsCXXRecordDecl(), possibleBase) : false;
0202 }