File indexing completed on 2024-05-12 05:40:58
0001 /* 0002 SPDX-FileCopyrightText: 2015 Albert Astals Cid <albert.astals@canonical.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "qdeleteall.h" 0008 #include "ClazyContext.h" 0009 #include "HierarchyUtils.h" 0010 #include "QtUtils.h" 0011 #include "StringUtils.h" 0012 0013 #include <clang/AST/Decl.h> 0014 #include <clang/AST/DeclCXX.h> 0015 #include <clang/AST/Expr.h> 0016 #include <clang/AST/ExprCXX.h> 0017 #include <clang/AST/Stmt.h> 0018 #include <clang/Basic/LLVM.h> 0019 #include <llvm/ADT/StringRef.h> 0020 #include <llvm/Support/Casting.h> 0021 0022 using namespace clang; 0023 0024 QDeleteAll::QDeleteAll(const std::string &name, ClazyContext *context) 0025 : CheckBase(name, context, Option_CanIgnoreIncludes) 0026 { 0027 } 0028 0029 void QDeleteAll::VisitStmt(clang::Stmt *stmt) 0030 { 0031 // Find a call to QMap/QSet/QHash::values/keys 0032 auto *offendingCall = dyn_cast<CXXMemberCallExpr>(stmt); 0033 FunctionDecl *func = offendingCall ? offendingCall->getDirectCallee() : nullptr; 0034 if (!func) { 0035 return; 0036 } 0037 0038 const std::string funcName = func->getNameAsString(); 0039 const bool isValues = funcName == "values"; 0040 if (!isValues && funcName != "keys") { 0041 return; 0042 } 0043 std::string offendingClassName; 0044 // In case QMultiHash::values is used in Qt5, values is defined in the QHash baseclass, look up the original record to be sure we have a QMultiHash 0045 if (auto *cast = dyn_cast<ImplicitCastExpr>(offendingCall->getImplicitObjectArgument())) { 0046 if (auto *subExpr = dyn_cast<DeclRefExpr>(cast->getSubExpr())) { 0047 if (auto *ptr = subExpr->getType().getTypePtrOrNull(); ptr && ptr->isRecordType()) { 0048 offendingClassName = ptr->getAsRecordDecl()->getNameAsString(); 0049 } 0050 } 0051 } 0052 // Check if we have whitelisted the classname 0053 if (offendingClassName.empty() || !clazy::isQtAssociativeContainer(offendingClassName)) { 0054 return; 0055 } 0056 0057 // Once found see if the first parent call is qDeleteAll 0058 int i = 1; 0059 Stmt *p = clazy::parent(m_context->parentMap, stmt, i); 0060 while (p) { 0061 auto *pc = dyn_cast<CallExpr>(p); 0062 if (FunctionDecl *f = pc ? pc->getDirectCallee() : nullptr) { 0063 if (clazy::name(f) == "qDeleteAll") { 0064 std::string msg = "qDeleteAll() is being used on an unnecessary temporary container created by " + offendingClassName + "::" + funcName + "()"; 0065 if (func->getNumParams() == 0) { // Ignore values method calls where lookup-parameter is given, like the deprecated QHash::values(Key) 0066 if (isValues) { 0067 msg += ", use qDeleteAll(mycontainer) instead"; 0068 } else { 0069 msg += ", use qDeleteAll(mycontainer.keyBegin(), mycontainer.keyEnd()) instead"; 0070 } 0071 emitWarning(p->getBeginLoc(), msg); 0072 } 0073 } 0074 break; 0075 } 0076 ++i; 0077 p = clazy::parent(m_context->parentMap, stmt, i); 0078 } 0079 }