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) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
0005     Author: Sérgio Martins <sergio.martins@kdab.com>
0006 
0007     Copyright (C) 2015-2016 Sergio Martins <smartins@kde.org>
0008 
0009     This library is free software; you can redistribute it and/or
0010     modify it under the terms of the GNU Library General Public
0011     License as published by the Free Software Foundation; either
0012     version 2 of the License, or (at your option) any later version.
0013 
0014     This library is distributed in the hope that it will be useful,
0015     but WITHOUT ANY WARRANTY; without even the implied warranty of
0016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017     Library General Public License for more details.
0018 
0019     You should have received a copy of the GNU Library General Public License
0020     along with this library; see the file COPYING.LIB.  If not, write to
0021     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022     Boston, MA 02110-1301, USA.
0023 */
0024 
0025 #include "Utils.h"
0026 #include "StringUtils.h"
0027 #include "HierarchyUtils.h"
0028 #include "StmtBodyRange.h"
0029 #include "clazy_stl.h"
0030 
0031 #include <clang/AST/Expr.h>
0032 #include <clang/AST/DeclCXX.h>
0033 #include <clang/AST/DeclTemplate.h>
0034 #include <clang/AST/ExprCXX.h>
0035 #include <clang/Basic/SourceLocation.h>
0036 #include <clang/Lex/Lexer.h>
0037 #include <clang/AST/Decl.h>
0038 #include <clang/AST/DeclBase.h>
0039 #include <clang/AST/DeclGroup.h>
0040 #include <clang/AST/OperationKinds.h>
0041 #include <clang/AST/Stmt.h>
0042 #include <clang/AST/StmtIterator.h>
0043 #include <clang/AST/Type.h>
0044 #include <clang/Basic/CharInfo.h>
0045 #include <clang/Basic/IdentifierTable.h>
0046 #include <clang/Basic/LLVM.h>
0047 #include <clang/Basic/SourceManager.h>
0048 #include <clang/Lex/Token.h>
0049 #include <llvm/Support/Casting.h>
0050 
0051 #include <cctype>
0052 #include <iterator>
0053 #include <utility>
0054 
0055 namespace clang {
0056 class LangOptions;
0057 }  // namespace clang
0058 
0059 using namespace clang;
0060 using namespace std;
0061 
0062 bool Utils::hasConstexprCtor(CXXRecordDecl *decl)
0063 {
0064     return clazy::any_of(decl->ctors(), [](CXXConstructorDecl *ctor) {
0065         return ctor->isConstexpr();
0066     });
0067 }
0068 
0069 CXXRecordDecl * Utils::namedCastInnerDecl(CXXNamedCastExpr *staticOrDynamicCast)
0070 {
0071     Expr *e = staticOrDynamicCast->getSubExpr();
0072     if (!e) return nullptr;
0073     if (auto implicitCast = dyn_cast<ImplicitCastExpr>(e)) {
0074         // Sometimes it's automatically cast to base
0075         if (implicitCast->getCastKind() == CK_DerivedToBase) {
0076             e = implicitCast->getSubExpr();
0077         }
0078     }
0079 
0080     QualType qt = e->getType();
0081     const Type *t = qt.getTypePtrOrNull();
0082     if (!t) return nullptr;
0083     QualType qt2 = t->getPointeeType();
0084     const Type *t2 = qt2.getTypePtrOrNull();
0085     if (!t2) return nullptr;
0086     return t2->getAsCXXRecordDecl();
0087 }
0088 
0089 CXXRecordDecl * Utils::namedCastOuterDecl(CXXNamedCastExpr *staticOrDynamicCast)
0090 {
0091     QualType qt = staticOrDynamicCast->getTypeAsWritten();
0092     const Type *t = qt.getTypePtrOrNull();
0093     QualType qt2 = t->getPointeeType();
0094     const Type *t2 = qt2.getTypePtrOrNull();
0095     if (!t2) return nullptr;
0096     return t2->getAsCXXRecordDecl();
0097 }
0098 
0099 bool Utils::allChildrenMemberCallsConst(Stmt *stm)
0100 {
0101     if (!stm)
0102         return false;
0103 
0104     auto expr = dyn_cast<MemberExpr>(stm);
0105 
0106     if (expr) {
0107         auto methodDecl = dyn_cast<CXXMethodDecl>(expr->getMemberDecl());
0108         if (methodDecl && !methodDecl->isConst())
0109             return false;
0110     }
0111 
0112     return clazy::all_of(stm->children(), [](Stmt *child) {
0113         return allChildrenMemberCallsConst(child);
0114     });
0115 }
0116 
0117 bool Utils::childsHaveSideEffects(Stmt *stm)
0118 {
0119     if (!stm)
0120         return false;
0121 
0122     auto unary = dyn_cast<UnaryOperator>(stm);
0123     if (unary && (unary->isIncrementOp() || unary->isDecrementOp()))
0124         return true;
0125 
0126     auto binary = dyn_cast<BinaryOperator>(stm);
0127     if (binary && (binary->isAssignmentOp() || binary->isShiftAssignOp() || binary->isCompoundAssignmentOp()))
0128         return true;
0129 
0130     static const std::vector<StringRef> method_blacklist = {
0131         "isDestroyed",
0132         "isRecursive", // TODO: Use qualified name instead ?
0133         "q_func",
0134         "d_func",
0135         "begin",
0136         "end",
0137         "data",
0138         "fragment",
0139         "glIsRenderbuffer"
0140     };
0141 
0142     auto memberCall = dyn_cast<MemberExpr>(stm);
0143     if (memberCall) {
0144         auto methodDecl = dyn_cast<CXXMethodDecl>(memberCall->getMemberDecl());
0145         if (methodDecl && !methodDecl->isConst() && !methodDecl->isStatic() &&
0146             !clazy::contains(method_blacklist, clazy::name(methodDecl)))
0147             return true;
0148     }
0149 
0150     /* // too many false positives, qIsFinite() etc for example
0151     auto callExpr = dyn_cast<CallExpr>(stm);
0152     if (callExpr) {
0153         FunctionDecl *callee = callExpr->getDirectCallee();
0154         if (callee && callee->isGlobal())
0155             return true;
0156     }*/
0157 
0158     return clazy::any_of(stm->children(), [](Stmt *s) {
0159         return childsHaveSideEffects(s);
0160     });
0161 }
0162 
0163 CXXRecordDecl *Utils::recordFromVarDecl(Decl *decl)
0164 {
0165     auto varDecl = dyn_cast<VarDecl>(decl);
0166     if (!varDecl)
0167         return nullptr;
0168 
0169     QualType qt = varDecl->getType();
0170     const Type *t = qt.getTypePtrOrNull();
0171     if (!t)
0172         return nullptr;
0173 
0174     return t->getAsCXXRecordDecl();
0175 }
0176 
0177 ClassTemplateSpecializationDecl *Utils::templateSpecializationFromVarDecl(Decl *decl)
0178 {
0179     auto record = recordFromVarDecl(decl);
0180     if (record)
0181         return dyn_cast<ClassTemplateSpecializationDecl>(record);
0182 
0183     return nullptr;
0184 }
0185 
0186 ValueDecl *Utils::valueDeclForMemberCall(CXXMemberCallExpr *memberCall)
0187 {
0188     if (!memberCall)
0189         return nullptr;
0190 
0191     Expr *implicitObject = memberCall->getImplicitObjectArgument();
0192     if (!implicitObject)
0193         return nullptr;
0194 
0195     auto declRefExpr = dyn_cast<DeclRefExpr>(implicitObject);
0196     auto memberExpr =  dyn_cast<MemberExpr>(implicitObject);
0197     if (declRefExpr) {
0198         return declRefExpr->getDecl();
0199     } else if (memberExpr) {
0200         return memberExpr->getMemberDecl();
0201     }
0202 
0203     // Maybe there's an implicit cast in between..
0204     auto memberExprs = clazy::getStatements<MemberExpr>(implicitObject, nullptr, {}, /**depth=*/ 1, /*includeParent=*/ true);
0205     auto declRefs = clazy::getStatements<DeclRefExpr>(implicitObject, nullptr, {}, /**depth=*/ 1, /*includeParent=*/ true);
0206 
0207     if (!memberExprs.empty()) {
0208         return memberExprs.at(0)->getMemberDecl();
0209     }
0210 
0211     if (!declRefs.empty()) {
0212         return declRefs.at(0)->getDecl();
0213     }
0214 
0215     return nullptr;
0216 }
0217 
0218 ValueDecl *Utils::valueDeclForOperatorCall(CXXOperatorCallExpr *operatorCall)
0219 {
0220     if (!operatorCall)
0221         return nullptr;
0222 
0223     // CXXOperatorCallExpr doesn't have API to access the value decl.
0224     // By inspecting several ASTs I noticed it's always in the 2nd child
0225 
0226     Stmt *child2 = clazy::childAt(operatorCall, 1);
0227     if (!child2)
0228         return nullptr;
0229 
0230     if (auto memberExpr = dyn_cast<MemberExpr>(child2)) {
0231         return memberExpr->getMemberDecl();
0232     } else {
0233         vector<DeclRefExpr*> refs;
0234         clazy::getChilds<DeclRefExpr>(child2, refs);
0235         if (refs.size() == 1) {
0236             return refs[0]->getDecl();
0237         }
0238     }
0239 
0240     return nullptr;
0241 }
0242 
0243 clang::ValueDecl * Utils::valueDeclForCallExpr(clang::CallExpr *expr)
0244 {
0245     if (auto memberExpr = dyn_cast<CXXMemberCallExpr>(expr)) {
0246         return valueDeclForMemberCall(memberExpr);
0247     } else if (auto operatorExpr = dyn_cast<CXXOperatorCallExpr>(expr)) {
0248         return valueDeclForOperatorCall(operatorExpr);
0249     }
0250 
0251     return nullptr;
0252 }
0253 
0254 static bool referencesVar(Stmt *s, const VarDecl *varDecl)
0255 {
0256     // look for a DeclRefExpr that references varDecl
0257     while (s) {
0258         auto it = s->child_begin();
0259         Stmt *child = it == s->child_end() ? nullptr : *it;
0260         if (auto declRef = dyn_cast_or_null<DeclRefExpr>(child)) {
0261             if (declRef->getDecl() == varDecl)
0262                 return true;
0263         }
0264         s = child;
0265     }
0266 
0267     return false;
0268 }
0269 
0270 
0271 bool Utils::containsNonConstMemberCall(clang::ParentMap *map, Stmt *body, const VarDecl *varDecl)
0272 {
0273     if (!varDecl)
0274         return false;
0275 
0276     std::vector<CXXMemberCallExpr*> memberCallExprs;
0277     clazy::getChilds<CXXMemberCallExpr>(body, memberCallExprs);
0278     for (auto memberCall : memberCallExprs) {
0279         CXXMethodDecl *methodDecl = memberCall->getMethodDecl();
0280         if (methodDecl && !methodDecl->isConst()) {
0281             ValueDecl *valueDecl = Utils::valueDeclForMemberCall(memberCall);
0282             if (valueDecl == varDecl)
0283                 return true;
0284         }
0285     }
0286 
0287     std::vector<CXXOperatorCallExpr*> operatorCalls;
0288     clazy::getChilds<CXXOperatorCallExpr>(body, operatorCalls);
0289     for (auto operatorCall : operatorCalls) {
0290         FunctionDecl *fDecl = operatorCall->getDirectCallee();
0291         if (fDecl) {
0292             auto methodDecl = dyn_cast<CXXMethodDecl>(fDecl);
0293             if (methodDecl && !methodDecl->isConst()) {
0294                 ValueDecl *valueDecl = Utils::valueDeclForOperatorCall(operatorCall);
0295                 if (valueDecl == varDecl)
0296                     return true;
0297             }
0298         }
0299     }
0300 
0301     std::vector<BinaryOperator*> assignmentOperators;
0302     clazy::getChilds<BinaryOperator>(body, assignmentOperators);
0303     for (auto op : assignmentOperators) {
0304         if (!op->isAssignmentOp())
0305             continue;
0306 
0307         if (referencesVar(op, varDecl))
0308             return true;
0309     }
0310 
0311     return false;
0312 }
0313 
0314 template<class T>
0315 static bool isArgOfFunc(T expr, FunctionDecl *fDecl, const VarDecl *varDecl, bool byRefOrPtrOnly)
0316 {
0317     unsigned int param = -1;
0318     for (auto arg : expr->arguments()) {
0319         ++param;
0320         auto refExpr = dyn_cast<DeclRefExpr>(arg);
0321         if (!refExpr)  {
0322             if (clazy::hasChildren(arg)) {
0323                 Stmt* firstChild = *(arg->child_begin()); // Can be null (bug #362236)
0324                 refExpr = firstChild ? dyn_cast<DeclRefExpr>(firstChild) : nullptr;
0325                 if (!refExpr)
0326                     continue;
0327             } else {
0328                 continue;
0329             }
0330         }
0331 
0332         if (refExpr->getDecl() != varDecl) // It's our variable ?
0333             continue;
0334 
0335         if (!byRefOrPtrOnly) {
0336             // We found it
0337             return true;
0338         }
0339 
0340         // It is, lets see if the callee takes our variable by const-ref
0341         if (param >= fDecl->param_size())
0342             continue;
0343 
0344         ParmVarDecl *paramDecl = fDecl->getParamDecl(param);
0345         if (!paramDecl)
0346             continue;
0347 
0348         QualType qt = paramDecl->getType();
0349         const clang::Type *t = qt.getTypePtrOrNull();
0350         if (!t)
0351             continue;
0352 
0353         if ((t->isReferenceType() || t->isPointerType()) && !t->getPointeeType().isConstQualified())
0354             return true; // function receives non-const ref, so our foreach variable cant be const-ref
0355     }
0356 
0357     return false;
0358 }
0359 
0360 bool Utils::isPassedToFunction(const StmtBodyRange &bodyRange, const VarDecl *varDecl, bool byRefOrPtrOnly)
0361 {
0362     if (!bodyRange.isValid())
0363         return false;
0364 
0365     Stmt *body = bodyRange.body;
0366     std::vector<CallExpr*> callExprs;
0367     clazy::getChilds<CallExpr>(body, callExprs);
0368     for (CallExpr *callexpr : callExprs) {
0369         if (bodyRange.isOutsideRange(callexpr))
0370             continue;
0371 
0372         FunctionDecl *fDecl = callexpr->getDirectCallee();
0373         if (!fDecl)
0374             continue;
0375 
0376         if (isArgOfFunc(callexpr, fDecl, varDecl, byRefOrPtrOnly))
0377             return true;
0378     }
0379 
0380     std::vector<CXXConstructExpr*> constructExprs;
0381     clazy::getChilds<CXXConstructExpr>(body, constructExprs);
0382     for (CXXConstructExpr *constructExpr : constructExprs) {
0383         if (bodyRange.isOutsideRange(constructExpr))
0384             continue;
0385         FunctionDecl *fDecl = constructExpr->getConstructor();
0386         if (isArgOfFunc(constructExpr, fDecl, varDecl, byRefOrPtrOnly))
0387             return true;
0388     }
0389 
0390     return false;
0391 }
0392 
0393 bool Utils::addressIsTaken(const clang::CompilerInstance &ci, Stmt *body, const clang::ValueDecl *valDecl)
0394 {
0395     if (!body || !valDecl)
0396         return false;
0397 
0398     auto unaries = clazy::getStatements<UnaryOperator>(body);
0399     return clazy::any_of(unaries, [valDecl](UnaryOperator *op) {
0400         if (op->getOpcode() != clang::UO_AddrOf)
0401             return false;
0402 
0403         auto declRef = clazy::getFirstChildOfType<DeclRefExpr>(op);
0404         return declRef && declRef->getDecl() == valDecl;
0405     });
0406 }
0407 
0408 bool Utils::isReturned(Stmt *body, const VarDecl *varDecl)
0409 {
0410     if (!body)
0411         return false;
0412 
0413     std::vector<ReturnStmt*> returns;
0414     clazy::getChilds<ReturnStmt>(body, returns);
0415     for (ReturnStmt *returnStmt : returns) {
0416         Expr* retValue = returnStmt->getRetValue();
0417         if (!retValue)
0418             continue;
0419         auto declRef = clazy::unpeal<DeclRefExpr>(retValue, clazy::IgnoreImplicitCasts);
0420         if (!declRef)
0421             continue;
0422         if (declRef->getDecl() == varDecl)
0423             return true;
0424     }
0425 
0426     return false;
0427 }
0428 
0429 bool Utils::isAssignedTo(Stmt *body, const VarDecl *varDecl)
0430 {
0431     if (!body)
0432         return false;
0433 
0434     std::vector<BinaryOperator*> operatorCalls;
0435     clazy::getChilds<BinaryOperator>(body, operatorCalls);
0436     for (BinaryOperator *binaryOperator : operatorCalls) {
0437         if (binaryOperator->getOpcode() != clang::BO_Assign)
0438             continue;
0439 
0440         Expr *rhs = binaryOperator->getRHS();
0441         auto declRef = clazy::unpeal<DeclRefExpr>(rhs, clazy::IgnoreImplicitCasts);
0442         if (!declRef)
0443             continue;
0444 
0445         if (declRef->getDecl() == varDecl)
0446             return true;
0447     }
0448 
0449     return false;
0450 }
0451 
0452 bool Utils::isAssignedFrom(Stmt *body, const VarDecl *varDecl)
0453 {
0454     if (!body)
0455         return false;
0456 
0457     std::vector<CXXOperatorCallExpr*> operatorCalls;
0458     clazy::getChilds<CXXOperatorCallExpr>(body, operatorCalls);
0459     for (CXXOperatorCallExpr *operatorExpr : operatorCalls) {
0460         FunctionDecl *fDecl = operatorExpr->getDirectCallee();
0461         if (!fDecl)
0462             continue;
0463 
0464         auto methodDecl = dyn_cast<CXXMethodDecl>(fDecl);
0465         if (methodDecl && methodDecl->isCopyAssignmentOperator()) {
0466             ValueDecl *valueDecl = Utils::valueDeclForOperatorCall(operatorExpr);
0467             if (valueDecl == varDecl)
0468                 return true;
0469         }
0470     }
0471 
0472     return false;
0473 }
0474 
0475 bool Utils::callHasDefaultArguments(clang::CallExpr *expr)
0476 {
0477     std::vector<clang::CXXDefaultArgExpr*> exprs;
0478     clazy::getChilds<clang::CXXDefaultArgExpr>(expr, exprs, 1);
0479     return !exprs.empty();
0480 }
0481 
0482 bool Utils::containsStringLiteral(Stmt *stm, bool allowEmpty, int depth)
0483 {
0484     if (!stm)
0485         return false;
0486 
0487     std::vector<StringLiteral*> stringLiterals;
0488     clazy::getChilds<StringLiteral>(stm, stringLiterals, depth);
0489 
0490     if (allowEmpty)
0491         return !stringLiterals.empty();
0492 
0493     for (StringLiteral *sl : stringLiterals) {
0494         if (sl->getLength() > 0)
0495             return true;
0496     }
0497 
0498     return false;
0499 }
0500 
0501 bool Utils::ternaryOperatorIsOfStringLiteral(ConditionalOperator *ternary)
0502 {
0503     bool skipFirst = true;
0504     for (auto child : ternary->children()) {
0505         if (skipFirst) {
0506             skipFirst = false;
0507             continue;
0508         }
0509 
0510         if (isa<StringLiteral>(child))
0511             continue;
0512 
0513         auto arrayToPointerDecay = dyn_cast<ImplicitCastExpr>(child);
0514         if (!arrayToPointerDecay || !isa<StringLiteral>(*(arrayToPointerDecay->child_begin())))
0515             return false;
0516     }
0517 
0518     return true;
0519 }
0520 
0521 bool Utils::isAssignOperator(CXXOperatorCallExpr *op, StringRef className,
0522                              StringRef argumentType, const clang::LangOptions &lo)
0523 {
0524     if (!op)
0525         return false;
0526 
0527     FunctionDecl *functionDecl = op->getDirectCallee();
0528     if (!functionDecl || functionDecl->param_size() != 1 )
0529         return false;
0530 
0531     if (!className.empty()) {
0532         auto methodDecl = dyn_cast<clang::CXXMethodDecl>(functionDecl);
0533         if (!clazy::isOfClass(methodDecl, className))
0534             return false;
0535     }
0536 
0537     if (functionDecl->getNameAsString() != "operator=")
0538         return false;
0539 
0540     if (!argumentType.empty() && !clazy::hasArgumentOfType(functionDecl, argumentType, lo))
0541         return false;
0542 
0543 
0544     return true;
0545 }
0546 
0547 
0548 bool Utils::isImplicitCastTo(Stmt *s, const string &className)
0549 {
0550     auto expr = dyn_cast<ImplicitCastExpr>(s);
0551     if (!expr)
0552         return false;
0553 
0554     auto record = expr->getBestDynamicClassType();
0555     return record && clazy::name(record) == className;
0556 }
0557 
0558 
0559 bool Utils::isInsideOperatorCall(ParentMap *map, Stmt *s, const std::vector<StringRef> &anyOf)
0560 {
0561     if (!s)
0562         return false;
0563 
0564     auto oper = dyn_cast<CXXOperatorCallExpr>(s);
0565     if (oper) {
0566         auto func = oper->getDirectCallee();
0567         if (func) {
0568             if (anyOf.empty())
0569                 return true;
0570 
0571             auto method = dyn_cast<CXXMethodDecl>(func);
0572             if (method) {
0573                 auto record = method->getParent();
0574                 if (record && clazy::contains(anyOf, clazy::name(record)))
0575                     return true;
0576             }
0577         }
0578     }
0579 
0580     return isInsideOperatorCall(map, clazy::parent(map, s), anyOf);
0581 }
0582 
0583 
0584 bool Utils::insideCTORCall(ParentMap *map, Stmt *s, const std::vector<llvm::StringRef> &anyOf)
0585 {
0586     if (!s)
0587         return false;
0588 
0589     auto expr = dyn_cast<CXXConstructExpr>(s);
0590     if (expr && expr->getConstructor() && clazy::contains(anyOf, clazy::name(expr->getConstructor()))) {
0591         return true;
0592     }
0593 
0594     return insideCTORCall(map, clazy::parent(map, s), anyOf);
0595 }
0596 
0597 bool Utils::presumedLocationsEqual(const clang::PresumedLoc &l1, const clang::PresumedLoc &l2)
0598 {
0599     return l1.isValid() && l2.isValid() && l1.getColumn() == l2.getColumn() &&
0600            l1.getLine()   == l2.getLine()   &&
0601            StringRef(l1.getFilename()) == StringRef(l2.getFilename());
0602 }
0603 
0604 CXXRecordDecl *Utils::isMemberVariable(ValueDecl *decl)
0605 {
0606     return decl ? dyn_cast<CXXRecordDecl>(decl->getDeclContext()) : nullptr;
0607 }
0608 
0609 std::vector<CXXMethodDecl *> Utils::methodsFromString(const CXXRecordDecl *record, const string &methodName)
0610 {
0611     if (!record)
0612         return {};
0613 
0614     vector<CXXMethodDecl *> methods;
0615     clazy::append_if(record->methods(), methods, [methodName](CXXMethodDecl *m) {
0616         return clazy::name(m) == methodName;
0617     });
0618 
0619     // Also include the base classes
0620     for (auto base : record->bases()) {
0621         const Type *t = base.getType().getTypePtrOrNull();
0622         if (t) {
0623             auto baseMethods = methodsFromString(t->getAsCXXRecordDecl(), methodName);
0624             if (!baseMethods.empty())
0625                 clazy::append(baseMethods, methods);
0626         }
0627     }
0628 
0629     return methods;
0630 }
0631 
0632 const CXXRecordDecl *Utils::recordForMemberCall(CXXMemberCallExpr *call, string &implicitCallee)
0633 {
0634     implicitCallee.clear();
0635     Expr *implicitArgument= call->getImplicitObjectArgument();
0636     if (!implicitArgument) {
0637         return nullptr;
0638     }
0639 
0640     Stmt *s = implicitArgument;
0641     while (s) {
0642         if (auto declRef = dyn_cast<DeclRefExpr>(s)) {
0643             if (declRef->getDecl()) {
0644                 implicitCallee = declRef->getDecl()->getNameAsString();
0645                 QualType qt = declRef->getDecl()->getType();
0646                 return qt->getPointeeCXXRecordDecl();
0647             } else {
0648                 return nullptr;
0649             }
0650         } else if (auto thisExpr = dyn_cast<CXXThisExpr>(s)) {
0651             implicitCallee = "this";
0652             return thisExpr->getType()->getPointeeCXXRecordDecl();
0653         } else if (auto memberExpr = dyn_cast<MemberExpr>(s)) {
0654             auto decl = memberExpr->getMemberDecl();
0655             if (decl) {
0656                 implicitCallee = decl->getNameAsString();
0657                 QualType qt = decl->getType();
0658                 return qt->getPointeeCXXRecordDecl();
0659             } else {
0660                 return nullptr;
0661             }
0662         }
0663 
0664         s = s->child_begin() == s->child_end() ? nullptr : *(s->child_begin());
0665     }
0666 
0667     return nullptr;
0668 }
0669 
0670 bool Utils::isAscii(StringLiteral *lt)
0671 {
0672     // 'é' for some reason has isAscii() == true, so also call containsNonAsciiOrNull
0673     return lt && lt->isAscii() && !lt->containsNonAsciiOrNull();
0674 }
0675 
0676 bool Utils::isInDerefExpression(Stmt *s, ParentMap *map)
0677 {
0678     if (!s)
0679         return false;
0680 
0681     Stmt *p = s;
0682     do {
0683         p = clazy::parent(map, p);
0684         auto op = p ? dyn_cast<CXXOperatorCallExpr>(p) : nullptr;
0685         if (op && op->getOperator() == OO_Star) {
0686             return op;
0687         }
0688     } while (p);
0689 
0690     return false;
0691 }
0692 
0693 std::vector<CallExpr *> Utils::callListForChain(CallExpr *lastCallExpr)
0694 {
0695     if (!lastCallExpr)
0696         return {};
0697 
0698     const bool isOperator = isa<CXXOperatorCallExpr>(lastCallExpr);
0699     vector<CallExpr *> callexprs = { lastCallExpr };
0700     Stmt *s = lastCallExpr;
0701     do {
0702         const int childCount = std::distance(s->child_begin(), s->child_end());
0703         if (isOperator && childCount > 1 && s == lastCallExpr) {
0704             // for operator case, the chained call childs are in the second child
0705             s = *(++s->child_begin());
0706         } else {
0707             s = childCount > 0 ? *s->child_begin() : nullptr;
0708         }
0709 
0710         if (s) {
0711             auto callExpr = dyn_cast<CallExpr>(s);
0712             if (callExpr && callExpr->getCalleeDecl()) {
0713                 callexprs.push_back(callExpr);
0714             } else if (auto memberExpr = dyn_cast<MemberExpr>(s)) {
0715                 if (isa<FieldDecl>(memberExpr->getMemberDecl()))
0716                     break; // accessing a public member via . or -> breaks the chain
0717             } else if (isa<ConditionalOperator>(s)) {
0718                 // Gets very greasy with conditional operators
0719                 // This would match: (should() ? container1 : container2).append()
0720                 // and it would return { append(), should()}
0721                 break;
0722             }
0723         }
0724     } while (s);
0725 
0726     return callexprs;
0727 }
0728 
0729 CXXRecordDecl *Utils::rootBaseClass(CXXRecordDecl *derived)
0730 {
0731     if (!derived || derived->getNumBases() == 0)
0732         return derived;
0733 
0734     CXXBaseSpecifier *base = derived->bases_begin();
0735     CXXRecordDecl *record = base->getType()->getAsCXXRecordDecl();
0736 
0737     return record ? rootBaseClass(record) : derived;
0738 }
0739 
0740 CXXConstructorDecl *Utils::copyCtor(const CXXRecordDecl *record)
0741 {
0742     for (auto ctor : record->ctors()) {
0743         if (ctor->isCopyConstructor())
0744             return ctor;
0745     }
0746 
0747     return nullptr;
0748 }
0749 
0750 CXXMethodDecl *Utils::copyAssign(const CXXRecordDecl *record)
0751 {
0752     for (auto copyAssign : record->methods()) {
0753         if (copyAssign->isCopyAssignmentOperator())
0754             return copyAssign;
0755     }
0756 
0757     return nullptr;
0758 }
0759 
0760 bool Utils::hasMember(CXXRecordDecl *record, const string &memberTypeName)
0761 {
0762     if (!record)
0763         return false;
0764 
0765     for (auto field : record->fields()) {
0766         field->getParent()->getNameAsString();
0767         QualType qt = field->getType();
0768         const Type *t = qt.getTypePtrOrNull();
0769         if (t && t->getAsCXXRecordDecl()) {
0770             CXXRecordDecl *rec = t->getAsCXXRecordDecl();
0771             if (clazy::name(rec) == memberTypeName)
0772                 return true;
0773         }
0774     }
0775 
0776     return false;
0777 }
0778 
0779 bool Utils::isSharedPointer(CXXRecordDecl *record)
0780 {
0781     static const vector<string> names = { "std::shared_ptr", "QSharedPointer", "boost::shared_ptr" };
0782     return record ? clazy::contains(names, record->getQualifiedNameAsString()) : false;
0783 }
0784 
0785 bool Utils::isInitializedExternally(clang::VarDecl *varDecl)
0786 {
0787     if (!varDecl)
0788         return false;
0789 
0790     DeclContext *context = varDecl->getDeclContext();
0791     auto fDecl = context ? dyn_cast<FunctionDecl>(context) : nullptr;
0792     Stmt *body = fDecl ? fDecl->getBody() : nullptr;
0793     if (!body)
0794         return false;
0795 
0796     vector<DeclStmt*> declStmts;
0797     clazy::getChilds<DeclStmt>(body, declStmts);
0798     for (DeclStmt *declStmt : declStmts) {
0799         if (referencesVarDecl(declStmt, varDecl)) {
0800             vector<DeclRefExpr*> declRefs;
0801 
0802             clazy::getChilds<DeclRefExpr>(declStmt, declRefs);
0803             if (!declRefs.empty())
0804                 return true;
0805 
0806             vector<CallExpr*> callExprs;
0807             clazy::getChilds<CallExpr>(declStmt, callExprs);
0808             if (!callExprs.empty())
0809                 return true;
0810         }
0811     }
0812 
0813     return false;
0814 }
0815 
0816 bool Utils::functionHasEmptyBody(clang::FunctionDecl *func)
0817 {
0818     Stmt *body = func ? func->getBody() : nullptr;
0819     return !clazy::hasChildren(body);
0820 }
0821 
0822 clang::Expr *Utils::isWriteOperator(Stmt *stm)
0823 {
0824     if (!stm)
0825         return nullptr;
0826 
0827     if (auto up = dyn_cast<UnaryOperator>(stm)) {
0828         auto opcode = up->getOpcode();
0829         if (opcode == clang::UO_AddrOf || opcode == clang::UO_Deref)
0830             return nullptr;
0831 
0832         return up->getSubExpr();
0833     }
0834 
0835     if (auto bp = dyn_cast<BinaryOperator>(stm))
0836         return bp->getLHS();
0837 
0838     return nullptr;
0839 }
0840 
0841 bool Utils::referencesVarDecl(clang::DeclStmt *declStmt, clang::VarDecl *varDecl)
0842 {
0843     if (!declStmt || !varDecl)
0844         return false;
0845 
0846     if (declStmt->isSingleDecl() && declStmt->getSingleDecl() == varDecl)
0847         return true;
0848 
0849     return clazy::any_of(declStmt->getDeclGroup(), [varDecl](Decl *decl) {
0850         return varDecl == decl;
0851     });
0852 }
0853 
0854 UserDefinedLiteral *Utils::userDefinedLiteral(Stmt *stm, const std::string &type, const clang::LangOptions &lo)
0855 {
0856     auto udl = dyn_cast<UserDefinedLiteral>(stm);
0857     if (!udl)
0858         udl = clazy::getFirstChildOfType<UserDefinedLiteral>(stm);
0859 
0860     if (udl && clazy::returnTypeName(udl, lo) == type) {
0861         return udl;
0862     }
0863 
0864     return nullptr;
0865 }
0866 
0867 clang::ArrayRef<clang::ParmVarDecl *> Utils::functionParameters(clang::FunctionDecl *func)
0868 {
0869     return func->parameters();
0870 }
0871 
0872 vector<CXXCtorInitializer *> Utils::ctorInitializer(CXXConstructorDecl *ctor, clang::ParmVarDecl *param)
0873 {
0874     if (!ctor)
0875         return {};
0876 
0877     vector <CXXCtorInitializer *> result;
0878 
0879     for (auto it = ctor->init_begin(), end = ctor->init_end(); it != end; ++it) {
0880         auto ctorInit = *it;
0881         vector<DeclRefExpr*> declRefs;
0882         clazy::getChilds(ctorInit->getInit(), declRefs);
0883         for (auto declRef : declRefs) {
0884             if (declRef->getDecl() == param) {
0885                 result.push_back(ctorInit);
0886                 break;
0887             }
0888         }
0889     }
0890 
0891     return result;
0892 }
0893 
0894 bool Utils::ctorInitializerContainsMove(CXXCtorInitializer *init)
0895 {
0896     if (!init)
0897         return false;
0898 
0899     vector<CallExpr*> calls;
0900     clazy::getChilds(init->getInit(), calls);
0901 
0902     for (auto call : calls) {
0903         if (FunctionDecl *funcDecl = call->getDirectCallee()) {
0904             auto name = funcDecl->getQualifiedNameAsString();
0905             if (name == "std::move" || name == "std::__1::move")
0906                 return true;
0907         }
0908     }
0909 
0910     return false;
0911 }
0912 
0913 bool Utils::ctorInitializerContainsMove(const vector<CXXCtorInitializer*> &ctorInits)
0914 {
0915     return clazy::any_of(ctorInits, [](CXXCtorInitializer *ctorInit) {
0916         return Utils::ctorInitializerContainsMove(ctorInit);
0917     });
0918 }
0919 
0920 string Utils::filenameForLoc(SourceLocation loc, const clang::SourceManager &sm)
0921 {
0922     if (loc.isMacroID())
0923         loc = sm.getExpansionLoc(loc);
0924 
0925     const string filename = static_cast<string>(sm.getFilename(loc));
0926     auto splitted = clazy::splitString(filename, '/');
0927     if (splitted.empty())
0928         return {};
0929 
0930     return splitted[splitted.size() - 1];
0931 }
0932 
0933 SourceLocation Utils::locForNextToken(SourceLocation loc, const clang::SourceManager &sm, const clang::LangOptions &lo)
0934 {
0935     std::pair<FileID, unsigned> locInfo = sm.getDecomposedLoc(loc);
0936     bool InvalidTemp = false;
0937     StringRef File = sm.getBufferData(locInfo.first, &InvalidTemp);
0938     if (InvalidTemp)
0939         return {};
0940 
0941     const char *TokenBegin = File.data() + locInfo.second;
0942     Lexer lexer(sm.getLocForStartOfFile(locInfo.first), lo, File.begin(),
0943                 TokenBegin, File.end());
0944 
0945     Token Tok;
0946     lexer.LexFromRawLexer(Tok);
0947 
0948     SourceLocation TokenLoc = Tok.getLocation();
0949 
0950     // Calculate how much whitespace needs to be skipped if any.
0951     unsigned NumWhitespaceChars = 0;
0952     const char *TokenEnd = sm.getCharacterData(TokenLoc) +
0953                            Tok.getLength();
0954     unsigned char C = *TokenEnd;
0955     while (isHorizontalWhitespace(C)) {
0956         C = *(++TokenEnd);
0957         NumWhitespaceChars++;
0958     }
0959 
0960     // Skip \r, \n, \r\n, or \n\r
0961     if (C == '\n' || C == '\r') {
0962         char PrevC = C;
0963         C = *(++TokenEnd);
0964         NumWhitespaceChars++;
0965         if ((C == '\n' || C == '\r') && C != PrevC)
0966             NumWhitespaceChars++;
0967     }
0968 
0969     return loc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars);
0970 }
0971 
0972 bool Utils::literalContainsEscapedBytes(StringLiteral *lt, const SourceManager &sm, const LangOptions &lo)
0973 {
0974     if (!lt)
0975         return false;
0976 
0977     // The AST doesn't have the info, we need to ask the Lexer
0978     SourceRange sr = lt->getSourceRange();
0979     CharSourceRange cr = Lexer::getAsCharRange(sr, sm, lo);
0980     const StringRef str = Lexer::getSourceText(cr, sm, lo);
0981 
0982     for (int i = 0, size = str.size(); i < size - 1; ++i) {
0983         if (str[i] == '\\') {
0984             auto next = str[i+1];
0985             if (next == 'U' || next == 'u' || next == 'x' || std::isdigit(next))
0986                 return true;
0987         }
0988     }
0989 
0990     return false;
0991 }