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

0001 /*
0002     SPDX-FileCopyrightText: 2016 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "base-class-event.h"
0008 #include "HierarchyUtils.h"
0009 #include "QtUtils.h"
0010 #include "clazy_stl.h"
0011 
0012 #include <clang/AST/DeclCXX.h>
0013 #include <clang/AST/ExprCXX.h>
0014 #include <clang/AST/Stmt.h>
0015 #include <clang/Basic/LLVM.h>
0016 #include <llvm/ADT/StringRef.h>
0017 #include <llvm/Support/Casting.h>
0018 
0019 #include <array>
0020 #include <vector>
0021 
0022 class ClazyContext;
0023 namespace clang
0024 {
0025 class Decl;
0026 } // namespace clang
0027 
0028 using namespace clang;
0029 
0030 BaseClassEvent::BaseClassEvent(const std::string &name, ClazyContext *context)
0031     : CheckBase(name, context)
0032 {
0033 }
0034 
0035 void BaseClassEvent::VisitDecl(Decl *decl)
0036 {
0037     auto *method = dyn_cast<CXXMethodDecl>(decl);
0038     if (!method || !method->hasBody() || !method->isThisDeclarationADefinition()) {
0039         return;
0040     }
0041 
0042     const std::string methodName = method->getNameAsString();
0043     const bool isEvent = methodName == "event";
0044     const bool isEventFilter = isEvent ? false : methodName == "eventFilter";
0045 
0046     if (!isEvent && !isEventFilter) {
0047         return;
0048     }
0049 
0050     CXXRecordDecl *classDecl = method->getParent();
0051     if (!clazy::isQObject(classDecl)) {
0052         return;
0053     }
0054 
0055     const std::string className = classDecl->getQualifiedNameAsString();
0056     if (clazy::contains(std::array<StringRef, 2>({"QObject", "QWidget"}), className)) {
0057         return;
0058     }
0059 
0060     CXXRecordDecl *baseClass = clazy::getQObjectBaseClass(classDecl);
0061     const std::string baseClassName = baseClass ? baseClass->getQualifiedNameAsString() : std::string("BaseClass");
0062 
0063     if (isEventFilter && clazy::contains(std::array<StringRef, 2>({"QObject", "QWidget"}), baseClassName)) {
0064         // This is fine, QObject and QWidget eventFilter() don't do anything
0065         return;
0066     }
0067 
0068     Stmt *body = method->getBody();
0069     std::vector<ReturnStmt *> returns;
0070     clazy::getChilds<ReturnStmt>(body, /*by-ref*/ returns);
0071     for (ReturnStmt *returnStmt : returns) {
0072         Stmt *maybeBoolExpr = clazy::childAt(returnStmt, 0);
0073         if (!maybeBoolExpr) {
0074             continue;
0075         }
0076         auto *boolExpr = dyn_cast<CXXBoolLiteralExpr>(maybeBoolExpr);
0077         if (!boolExpr || boolExpr->getValue()) { // if getValue() is true that's a return true, which is fine
0078             continue;
0079         }
0080 
0081         emitWarning(returnStmt->getBeginLoc(), "Return " + baseClassName + "::" + methodName + "() instead of false");
0082     }
0083 }