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 "qproperty-without-notify.h" 0008 #include "clazy_stl.h" 0009 0010 #include <clang/Basic/IdentifierTable.h> 0011 #include <clang/Basic/SourceManager.h> 0012 #include <clang/Lex/Lexer.h> 0013 #include <clang/Lex/Token.h> 0014 #include <llvm/ADT/StringRef.h> 0015 0016 #include <vector> 0017 0018 class ClazyContext; 0019 namespace clang 0020 { 0021 class MacroInfo; 0022 } // namespace clang 0023 0024 using namespace clang; 0025 0026 QPropertyWithoutNotify::QPropertyWithoutNotify(const std::string &name, ClazyContext *context) 0027 : CheckBase(name, context, Option_CanIgnoreIncludes) 0028 { 0029 enablePreProcessorCallbacks(); 0030 } 0031 0032 void QPropertyWithoutNotify::VisitMacroExpands(const clang::Token &MacroNameTok, const clang::SourceRange &range, const MacroInfo *) 0033 { 0034 IdentifierInfo *ii = MacroNameTok.getIdentifierInfo(); 0035 if (!ii) { 0036 return; 0037 } 0038 0039 if (ii->getName() == "Q_GADGET") { 0040 m_lastIsGadget = true; 0041 return; 0042 } 0043 0044 if (ii->getName() == "Q_OBJECT") { 0045 m_lastIsGadget = false; 0046 return; 0047 } 0048 0049 // Gadgets can't have NOTIFY 0050 if (m_lastIsGadget || ii->getName() != "Q_PROPERTY") { 0051 return; 0052 } 0053 0054 if (sm().isInSystemHeader(range.getBegin())) { 0055 return; 0056 } 0057 CharSourceRange crange = Lexer::getAsCharRange(range, sm(), lo()); 0058 0059 std::string text = static_cast<std::string>(Lexer::getSourceText(crange, sm(), lo())); 0060 if (text.empty()) { 0061 // If the text is empty, it is more likely there is an error 0062 // in parsing than an empty Q_PROPERTY macro call (which would 0063 // be a moc error anyhow). 0064 return; 0065 } 0066 0067 if (text.back() == ')') { 0068 text.pop_back(); 0069 } 0070 0071 std::vector<std::string> split = clazy::splitString(text, ' '); 0072 0073 bool found_read = false; 0074 bool found_constant = false; 0075 bool found_notify = false; 0076 for (std::string &token : split) { 0077 clazy::rtrim(/*by-ref*/ token); 0078 if (!found_read && token == "READ") { 0079 found_read = true; 0080 continue; 0081 } 0082 0083 if (!found_constant && token == "CONSTANT") { 0084 found_constant = true; 0085 continue; 0086 } 0087 0088 if (!found_notify && token == "NOTIFY") { 0089 found_notify = true; 0090 continue; 0091 } 0092 } 0093 0094 if (!found_read || (found_notify || found_constant)) { 0095 return; 0096 } 0097 0098 emitWarning(range.getBegin(), "Q_PROPERTY should have either NOTIFY or CONSTANT"); 0099 }