File indexing completed on 2024-05-12 05:40:59

0001 /*
0002     SPDX-FileCopyrightText: 2017 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "skipped-base-method.h"
0008 #include "FunctionUtils.h"
0009 #include "HierarchyUtils.h"
0010 #include "TypeUtils.h"
0011 
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 #include <vector>
0021 
0022 class ClazyContext;
0023 
0024 using namespace clang;
0025 
0026 SkippedBaseMethod::SkippedBaseMethod(const std::string &name, ClazyContext *context)
0027     : CheckBase(name, context)
0028 {
0029 }
0030 
0031 void SkippedBaseMethod::VisitStmt(clang::Stmt *stmt)
0032 {
0033     auto *memberCall = dyn_cast<CXXMemberCallExpr>(stmt);
0034     if (!memberCall) {
0035         return;
0036     }
0037 
0038     auto *expr = memberCall->getImplicitObjectArgument();
0039     auto *thisExpr = clazy::unpeal<CXXThisExpr>(expr, clazy::IgnoreImplicitCasts);
0040     if (!thisExpr) {
0041         return;
0042     }
0043 
0044     const CXXRecordDecl *thisClass = thisExpr->getType()->getPointeeCXXRecordDecl();
0045     const CXXRecordDecl *baseClass = memberCall->getRecordDecl();
0046 
0047     std::vector<CXXRecordDecl *> baseClasses;
0048     if (!clazy::derivesFrom(thisClass, baseClass, &baseClasses) || baseClasses.size() < 2) {
0049         return;
0050     }
0051 
0052     // We're calling a grand-base method, so check if a more direct base also implements it
0053     for (int i = baseClasses.size() - 1; i > 0; --i) { // the higher indexes have the most derived classes
0054         CXXRecordDecl *moreDirectBaseClass = baseClasses[i];
0055         if (clazy::classImplementsMethod(moreDirectBaseClass, memberCall->getMethodDecl())) {
0056             std::string msg =
0057                 "Maybe you meant to call " + moreDirectBaseClass->getNameAsString() + "::" + memberCall->getMethodDecl()->getNameAsString() + "() instead";
0058             emitWarning(stmt, msg);
0059         }
0060     }
0061 }