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