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 "const-signal-or-slot.h" 0008 #include "AccessSpecifierManager.h" 0009 #include "ClazyContext.h" 0010 #include "QtUtils.h" 0011 #include "TypeUtils.h" 0012 0013 #include <clang/AST/DeclCXX.h> 0014 #include <clang/AST/Expr.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 namespace clang 0021 { 0022 class Decl; 0023 class FunctionDecl; 0024 } // namespace clang 0025 0026 using namespace clang; 0027 0028 ConstSignalOrSlot::ConstSignalOrSlot(const std::string &name, ClazyContext *context) 0029 : CheckBase(name, context, Option_CanIgnoreIncludes) 0030 { 0031 context->enableAccessSpecifierManager(); 0032 } 0033 0034 void ConstSignalOrSlot::VisitStmt(clang::Stmt *stmt) 0035 { 0036 auto *call = dyn_cast<CallExpr>(stmt); 0037 AccessSpecifierManager *accessSpecifierManager = m_context->accessSpecifierManager; 0038 if (!call || !accessSpecifierManager) { 0039 return; 0040 } 0041 0042 FunctionDecl *func = call->getDirectCallee(); 0043 if (!clazy::isConnect(func) || !clazy::connectHasPMFStyle(func)) { 0044 return; 0045 } 0046 0047 CXXMethodDecl *slot = clazy::receiverMethodForConnect(call); 0048 if (!slot || !slot->isConst() || slot->getReturnType()->isVoidType()) { // const and returning void must do something, so not a getter 0049 return; 0050 } 0051 0052 QtAccessSpecifierType specifierType = accessSpecifierManager->qtAccessSpecifierType(slot); 0053 if (specifierType == QtAccessSpecifier_Slot || specifierType == QtAccessSpecifier_Signal) { 0054 return; // For stuff explicitly marked as slots or signals we use VisitDecl 0055 } 0056 0057 // Here the user is connecting to a const method, which isn't marked as slot or signal and returns non-void 0058 // Looks like a getter! 0059 0060 emitWarning(stmt, slot->getQualifiedNameAsString() + " is not a slot, and is possibly a getter"); 0061 } 0062 0063 void ConstSignalOrSlot::VisitDecl(Decl *decl) 0064 { 0065 auto *method = dyn_cast<CXXMethodDecl>(decl); 0066 if (!method || !method->isConst()) { 0067 return; 0068 } 0069 0070 AccessSpecifierManager *a = m_context->accessSpecifierManager; 0071 if (!a) { 0072 return; 0073 } 0074 0075 if (method->isThisDeclarationADefinition() && !method->hasInlineBody()) { // Don't warn twice 0076 return; 0077 } 0078 0079 CXXRecordDecl *record = method->getParent(); 0080 if (clazy::derivesFrom(record, "QDBusAbstractInterface")) { 0081 return; 0082 } 0083 0084 QtAccessSpecifierType specifierType = a->qtAccessSpecifierType(method); 0085 0086 const bool isSlot = specifierType == QtAccessSpecifier_Slot; 0087 const bool isSignal = specifierType == QtAccessSpecifier_Signal; 0088 0089 if (!isSlot && !isSignal) { 0090 return; 0091 } 0092 0093 if (a->isScriptable(method)) { 0094 return; 0095 } 0096 0097 if (isSlot && !method->getReturnType()->isVoidType()) { 0098 emitWarning(decl, "getter " + method->getQualifiedNameAsString() + " possibly mismarked as a slot"); 0099 } else if (isSignal) { 0100 emitWarning(decl, "signal " + method->getQualifiedNameAsString() + " shouldn't be const"); 0101 } 0102 }