src/checks/level1/qdeleteall.cpp (62 lines of code) (raw):

/* SPDX-FileCopyrightText: 2015 Albert Astals Cid <albert.astals@canonical.com> SPDX-License-Identifier: LGPL-2.0-or-later */ #include "qdeleteall.h" #include "ClazyContext.h" #include "HierarchyUtils.h" #include "QtUtils.h" #include "StringUtils.h" #include <clang/AST/Decl.h> #include <clang/AST/DeclCXX.h> #include <clang/AST/Expr.h> #include <clang/AST/ExprCXX.h> #include <clang/AST/Stmt.h> #include <clang/Basic/LLVM.h> #include <llvm/ADT/StringRef.h> #include <llvm/Support/Casting.h> using namespace clang; QDeleteAll::QDeleteAll(const std::string &name, ClazyContext *context) : CheckBase(name, context, Option_CanIgnoreIncludes) { } void QDeleteAll::VisitStmt(clang::Stmt *stmt) { // Find a call to QMap/QSet/QHash::values/keys auto *offendingCall = dyn_cast<CXXMemberCallExpr>(stmt); FunctionDecl *func = offendingCall ? offendingCall->getDirectCallee() : nullptr; if (!func) { return; } const std::string funcName = func->getNameAsString(); const bool isValues = funcName == "values"; if (!isValues && funcName != "keys") { return; } std::string offendingClassName; // 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 if (auto *cast = dyn_cast<ImplicitCastExpr>(offendingCall->getImplicitObjectArgument())) { if (auto *subExpr = dyn_cast<DeclRefExpr>(cast->getSubExpr())) { if (auto *ptr = subExpr->getType().getTypePtrOrNull(); ptr && ptr->isRecordType()) { offendingClassName = ptr->getAsRecordDecl()->getNameAsString(); } } } // Check if we have whitelisted the classname if (offendingClassName.empty() || !clazy::isQtAssociativeContainer(offendingClassName)) { return; } // Once found see if the first parent call is qDeleteAll int i = 1; Stmt *p = clazy::parent(m_context->parentMap, stmt, i); while (p) { auto *pc = dyn_cast<CallExpr>(p); if (const FunctionDecl *f = pc ? pc->getDirectCallee() : nullptr) { if ((clazy::name(f) == "qDeleteAll") && (func->getNumParams() == 0)) { // Ignore values method calls where lookup-parameter is given, like the deprecated QHash::values(Key) std::string msg = "qDeleteAll() is being used on an unnecessary temporary container created by " + offendingClassName + "::" + funcName + "()"; if (isValues) { msg += ", use qDeleteAll(mycontainer) instead"; } else { msg += ", use qDeleteAll(mycontainer.keyBegin(), mycontainer.keyEnd()) instead"; } emitWarning(p->getBeginLoc(), msg); } break; } ++i; p = clazy::parent(m_context->parentMap, stmt, i); } }