File indexing completed on 2024-05-12 05:40:59
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 "returning-data-from-temporary.h" 0008 #include "HierarchyUtils.h" 0009 #include "TypeUtils.h" 0010 0011 #include <clang/AST/Decl.h> 0012 #include <clang/AST/DeclCXX.h> 0013 #include <clang/AST/Expr.h> 0014 #include <clang/AST/ExprCXX.h> 0015 #include <clang/AST/Stmt.h> 0016 #include <clang/AST/Type.h> 0017 #include <clang/Basic/LLVM.h> 0018 #include <llvm/Support/Casting.h> 0019 0020 class ClazyContext; 0021 0022 using namespace clang; 0023 0024 ReturningDataFromTemporary::ReturningDataFromTemporary(const std::string &name, ClazyContext *context) 0025 : CheckBase(name, context, Option_CanIgnoreIncludes) 0026 { 0027 } 0028 0029 void ReturningDataFromTemporary::VisitStmt(clang::Stmt *stmt) 0030 { 0031 if (handleReturn(dyn_cast<ReturnStmt>(stmt))) { 0032 return; 0033 } 0034 0035 handleDeclStmt(dyn_cast<DeclStmt>(stmt)); 0036 } 0037 0038 bool ReturningDataFromTemporary::handleReturn(ReturnStmt *ret) 0039 { 0040 if (!ret) { 0041 return false; 0042 } 0043 0044 auto *memberCall = clazy::unpeal<CXXMemberCallExpr>(clazy::getFirstChild(ret), clazy::IgnoreExprWithCleanups | clazy::IgnoreImplicitCasts); 0045 handleMemberCall(memberCall, false); 0046 return true; 0047 } 0048 0049 void ReturningDataFromTemporary::handleDeclStmt(DeclStmt *declStmt) 0050 { 0051 if (!declStmt) { 0052 return; 0053 } 0054 0055 for (auto *decl : declStmt->decls()) { 0056 auto *varDecl = dyn_cast<VarDecl>(decl); 0057 if (!varDecl) { 0058 continue; 0059 } 0060 0061 if (varDecl->getType().getAsString() != "const char *") { 0062 continue; 0063 } 0064 0065 Expr *init = varDecl->getInit(); 0066 if (!init) { 0067 continue; 0068 } 0069 0070 auto *memberCall = clazy::unpeal<CXXMemberCallExpr>(clazy::getFirstChild(init), clazy::IgnoreExprWithCleanups | clazy::IgnoreImplicitCasts); 0071 0072 handleMemberCall(memberCall, true); 0073 } 0074 } 0075 0076 void ReturningDataFromTemporary::handleMemberCall(CXXMemberCallExpr *memberCall, bool onlyTemporaries) 0077 { 0078 if (!memberCall) { 0079 return; 0080 } 0081 0082 CXXMethodDecl *method = memberCall->getMethodDecl(); 0083 if (!method) { 0084 return; 0085 } 0086 const auto methodName = method->getQualifiedNameAsString(); 0087 0088 if (methodName != "QByteArray::data" && methodName != "QByteArray::operator const char *" && methodName != "QByteArray::constData") { 0089 return; 0090 } 0091 0092 Expr *obj = memberCall->getImplicitObjectArgument(); 0093 Stmt *t = obj; 0094 DeclRefExpr *declRef = nullptr; 0095 CXXBindTemporaryExpr *temporaryExpr = nullptr; 0096 0097 while (t) { 0098 if (dyn_cast<ImplicitCastExpr>(t) || dyn_cast<MaterializeTemporaryExpr>(t) || dyn_cast<CXXFunctionalCastExpr>(t)) { 0099 t = clazy::getFirstChild(t); 0100 continue; 0101 } 0102 0103 if (!onlyTemporaries) { 0104 declRef = dyn_cast<DeclRefExpr>(t); 0105 if (declRef) { 0106 break; 0107 } 0108 } 0109 0110 temporaryExpr = dyn_cast<CXXBindTemporaryExpr>(t); 0111 if (temporaryExpr) { 0112 break; 0113 } 0114 0115 break; 0116 } 0117 0118 if (!temporaryExpr && !declRef) { 0119 return; 0120 } 0121 0122 if (declRef) { 0123 auto *varDecl = dyn_cast<VarDecl>(declRef->getDecl()); 0124 if (!varDecl || varDecl->isStaticLocal() || clazy::valueIsConst(varDecl->getType())) { 0125 return; 0126 } 0127 0128 QualType qt = varDecl->getType(); 0129 if (qt.isNull() || qt->isReferenceType()) { 0130 return; 0131 } 0132 } else if (temporaryExpr) { 0133 if (clazy::valueIsConst(temporaryExpr->getType())) { 0134 return; 0135 } 0136 } 0137 0138 emitWarning(memberCall, "Returning data of temporary QByteArray"); 0139 }