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 }