File indexing completed on 2024-05-19 05:41:39

0001 /*
0002     SPDX-FileCopyrightText: 2016 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "child-event-qobject-cast.h"
0008 #include "HierarchyUtils.h"
0009 #include "QtUtils.h"
0010 #include "StringUtils.h"
0011 #include "clazy_stl.h"
0012 
0013 #include <clang/AST/Decl.h>
0014 #include <clang/AST/DeclBase.h>
0015 #include <clang/AST/DeclCXX.h>
0016 #include <clang/AST/Expr.h>
0017 #include <clang/AST/ExprCXX.h>
0018 #include <clang/AST/Stmt.h>
0019 #include <clang/Basic/LLVM.h>
0020 #include <llvm/ADT/StringRef.h>
0021 #include <llvm/Support/Casting.h>
0022 
0023 #include <vector>
0024 
0025 class ClazyContext;
0026 
0027 using namespace clang;
0028 
0029 ChildEventQObjectCast::ChildEventQObjectCast(const std::string &name, ClazyContext *context)
0030     : CheckBase(name, context, Option_CanIgnoreIncludes)
0031 {
0032 }
0033 
0034 void ChildEventQObjectCast::VisitDecl(Decl *decl)
0035 {
0036     auto *childEventMethod = dyn_cast<CXXMethodDecl>(decl);
0037     if (!childEventMethod) {
0038         return;
0039     }
0040 
0041     Stmt *body = decl->getBody();
0042     if (!body) {
0043         return;
0044     }
0045 
0046     auto methodName = childEventMethod->getNameAsString();
0047     if (!clazy::equalsAny(methodName, {"event", "childEvent", "eventFilter"})) {
0048         return;
0049     }
0050 
0051     if (!clazy::isQObject(childEventMethod->getParent())) {
0052         return;
0053     }
0054 
0055     auto callExprs = clazy::getStatements<CallExpr>(body, &(sm()));
0056     for (auto *callExpr : callExprs) {
0057         if (callExpr->getNumArgs() != 1) {
0058             continue;
0059         }
0060 
0061         FunctionDecl *fdecl = callExpr->getDirectCallee();
0062         if (fdecl && clazy::name(fdecl) == "qobject_cast") {
0063             auto *childCall = dyn_cast<CXXMemberCallExpr>(callExpr->getArg(0));
0064             // The call to event->child()
0065             if (!childCall) {
0066                 continue;
0067             }
0068 
0069             auto *childFDecl = childCall->getDirectCallee();
0070             if (!childFDecl || childFDecl->getQualifiedNameAsString() != "QChildEvent::child") {
0071                 continue;
0072             }
0073 
0074             emitWarning(childCall, "qobject_cast in childEvent");
0075         }
0076     }
0077 }