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

0001 /*
0002     SPDX-FileCopyrightText: 2017 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "overridden-signal.h"
0008 #include "AccessSpecifierManager.h"
0009 #include "ClazyContext.h"
0010 #include "FunctionUtils.h"
0011 #include "QtUtils.h"
0012 #include "StringUtils.h"
0013 
0014 #include <clang/AST/DeclCXX.h>
0015 #include <clang/Basic/LLVM.h>
0016 #include <llvm/ADT/StringRef.h>
0017 #include <llvm/Support/Casting.h>
0018 
0019 namespace clang
0020 {
0021 class Decl;
0022 } // namespace clang
0023 
0024 using namespace clang;
0025 
0026 OverriddenSignal::OverriddenSignal(const std::string &name, ClazyContext *context)
0027     : CheckBase(name, context, Option_CanIgnoreIncludes)
0028 {
0029     context->enableAccessSpecifierManager();
0030 }
0031 
0032 void OverriddenSignal::VisitDecl(clang::Decl *decl)
0033 {
0034     AccessSpecifierManager *accessSpecifierManager = m_context->accessSpecifierManager;
0035     auto *method = dyn_cast<CXXMethodDecl>(decl);
0036     if (!accessSpecifierManager || !method) {
0037         return;
0038     }
0039 
0040     if (method->isThisDeclarationADefinition() && !method->hasInlineBody()) {
0041         return;
0042     }
0043 
0044     CXXRecordDecl *record = method->getParent();
0045     CXXRecordDecl *baseClass = clazy::getQObjectBaseClass(record);
0046     if (!baseClass) {
0047         return;
0048     }
0049 
0050     const bool methodIsSignal = accessSpecifierManager->qtAccessSpecifierType(method) == QtAccessSpecifier_Signal;
0051     const StringRef methodName = clazy::name(method);
0052 
0053     std::string warningMsg;
0054     while (baseClass) {
0055         for (auto *baseMethod : baseClass->methods()) {
0056             if (clazy::name(baseMethod) == methodName) {
0057                 if (!clazy::parametersMatch(method, baseMethod)) { // overloading is permitted.
0058                     continue;
0059                 }
0060 
0061                 const bool baseMethodIsSignal = accessSpecifierManager->qtAccessSpecifierType(baseMethod) == QtAccessSpecifier_Signal;
0062 
0063                 if (methodIsSignal && baseMethodIsSignal) {
0064                     warningMsg = "Overriding signal with signal: " + method->getQualifiedNameAsString();
0065                 } else if (methodIsSignal && !baseMethodIsSignal) {
0066                     warningMsg = "Overriding non-signal with signal: " + method->getQualifiedNameAsString();
0067                 } else if (!methodIsSignal && baseMethodIsSignal) {
0068                     warningMsg = "Overriding signal with non-signal: " + method->getQualifiedNameAsString();
0069                 }
0070 
0071                 if (!warningMsg.empty()) {
0072                     emitWarning(decl, warningMsg);
0073                     return;
0074                 }
0075             }
0076         }
0077 
0078         baseClass = clazy::getQObjectBaseClass(baseClass);
0079     }
0080 }