File indexing completed on 2025-04-06 05:21:32

0001 /*
0002     SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com
0003     SPDX-FileContributor: Shivam Kunwar <shivam.kunwar@kdab.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "unused-result-check.h"
0009 #include "StringUtils.h"
0010 
0011 #include <clang/AST/AST.h>
0012 #include <clang/AST/ExprCXX.h>
0013 #include <clang/ASTMatchers/ASTMatchFinder.h>
0014 #include <clang/ASTMatchers/ASTMatchers.h>
0015 #include <clang/ASTMatchers/ASTMatchersInternal.h>
0016 
0017 using namespace clang::ast_matchers;
0018 class ClazyContext;
0019 
0020 using namespace clang;
0021 
0022 class Caller : public ClazyAstMatcherCallback
0023 {
0024 public:
0025     Caller(CheckBase *check)
0026         : ClazyAstMatcherCallback(check)
0027     {
0028     }
0029     void run(const MatchFinder::MatchResult &result) override
0030     {
0031         if (const auto *callExpr = result.Nodes.getNodeAs<CXXMemberCallExpr>("callExpr")) {
0032             if (callExpr->getMethodDecl()->isConst() && !callExpr->getMethodDecl()->getReturnType()->isVoidType()) {
0033                 const auto &parents = result.Context->getParents(*callExpr);
0034 
0035                 if (parents[0].get<Stmt>() != nullptr && parents[0].get<Decl>() == nullptr) {
0036                     if (!llvm::dyn_cast<Expr>(parents[0].get<Stmt>()) && !llvm::dyn_cast<ReturnStmt>(parents[0].get<Stmt>())
0037                         && !llvm::dyn_cast<IfStmt>(parents[0].get<Stmt>()) && !llvm::dyn_cast<WhileStmt>(parents[0].get<Stmt>())
0038                         && !llvm::dyn_cast<DoStmt>(parents[0].get<Stmt>()) && !llvm::dyn_cast<SwitchStmt>(parents[0].get<Stmt>())
0039                         && !llvm::dyn_cast<ForStmt>(parents[0].get<Stmt>())
0040                         && !llvm::dyn_cast<CXXThisExpr>(parents[0].get<Stmt>())
0041                         // Ignore this false positive from a Qt header for now, we pass a mutable pointer to a static function
0042                         && clazy::qualifiedMethodName(callExpr->getMethodDecl()) != "QMetaType::registerHelper") {
0043                         m_check->emitWarning(callExpr->getExprLoc(), "Result of const member function is not used.");
0044                     }
0045                 }
0046 
0047                 else if (parents[0].get<Decl>() != nullptr && parents[0].get<Stmt>() == nullptr) {
0048                     if (!llvm::dyn_cast<VarDecl>(parents[0].get<Decl>()) && !llvm::dyn_cast<CXXConstructorDecl>(parents[0].get<Decl>())) {
0049                         m_check->emitWarning(callExpr->getExprLoc(), "Result of const member function is not used.");
0050                     }
0051                 }
0052             }
0053         }
0054     }
0055 };
0056 
0057 UnusedResultCheck::UnusedResultCheck(const std::string &name, ClazyContext *context)
0058     : CheckBase(name, context, Option_CanIgnoreIncludes)
0059     , m_astMatcherCallBack(std::make_unique<Caller>(this))
0060 {
0061 }
0062 
0063 UnusedResultCheck::~UnusedResultCheck() = default;
0064 
0065 void UnusedResultCheck::VisitStmt(Stmt *stmt)
0066 {
0067 }
0068 
0069 void UnusedResultCheck::registerASTMatchers(MatchFinder &finder)
0070 {
0071     finder.addMatcher(cxxMemberCallExpr().bind("callExpr"), m_astMatcherCallBack.get());
0072 }