File indexing completed on 2024-05-12 05:41:01
0001 /* 0002 SPDX-FileCopyrightText: 2018 Sergio Martins <smartins@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "qrequiredresult-candidates.h" 0008 #include "QtUtils.h" 0009 #include "TypeUtils.h" 0010 #include "Utils.h" 0011 0012 #include <clang/AST/AST.h> 0013 0014 using namespace clang; 0015 0016 static bool hasUnusedResultAttr(clang::FunctionDecl *func) 0017 { 0018 auto RetType = func->getReturnType(); 0019 if (const auto *Ret = RetType->getAsRecordDecl()) { 0020 if (const auto *R = Ret->getAttr<clang::WarnUnusedResultAttr>()) { 0021 return R != nullptr; 0022 } 0023 } else if (const auto *ET = RetType->getAs<clang::EnumType>()) { 0024 if (const clang::EnumDecl *ED = ET->getDecl()) { 0025 if (const auto *R = ED->getAttr<clang::WarnUnusedResultAttr>()) { 0026 return R != nullptr; 0027 } 0028 } 0029 } 0030 return func->getAttr<clang::WarnUnusedResultAttr>() != nullptr; 0031 } 0032 0033 QRequiredResultCandidates::QRequiredResultCandidates(const std::string &name, ClazyContext *context) 0034 : CheckBase(name, context) 0035 { 0036 } 0037 0038 void QRequiredResultCandidates::VisitDecl(clang::Decl *decl) 0039 { 0040 auto *method = dyn_cast<CXXMethodDecl>(decl); 0041 if (!method || !method->isConst()) { 0042 return; 0043 } 0044 0045 if (method->isThisDeclarationADefinition() && !method->hasInlineBody()) { // Don't warn twice 0046 return; 0047 } 0048 0049 if (hasUnusedResultAttr(method)) { // Also catches nodiscard 0050 return; 0051 } 0052 0053 if (method->getAccess() == AS_private) { // We're only interested on our public API 0054 return; 0055 } 0056 0057 QualType qt = method->getReturnType(); 0058 CXXRecordDecl *returnClass = qt->getAsCXXRecordDecl(); 0059 returnClass = returnClass ? returnClass->getCanonicalDecl() : nullptr; 0060 if (!returnClass) { 0061 return; 0062 } 0063 0064 CXXRecordDecl *classDecl = method->getParent(); 0065 classDecl = classDecl ? classDecl->getCanonicalDecl() : nullptr; 0066 0067 if (classDecl->getAccess() == AS_private) { // A nested private class. We're only interested on our public API 0068 return; 0069 } 0070 0071 if (returnClass == classDecl) { 0072 const std::string methodName = static_cast<std::string>(clazy::name(method)); 0073 if (methodName.empty()) { // fixes assert 0074 return; 0075 } 0076 0077 if (clazy::startsWith(methodName, "to") || clazy::startsWith(methodName, "operator") || !clazy::endsWith(methodName, "ed")) { 0078 return; 0079 } 0080 0081 emitWarning(decl, "Add Q_REQUIRED_RESULT to " + method->getQualifiedNameAsString() + "()"); 0082 } 0083 }