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 }