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 }