diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 1db9adb3c..44e3efe47 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4302,7 +4302,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) createLinks(); - reportUnknownMacrosInNonExecutableScopes(); + reportUnknownMacros(); simplifyHeaders(); @@ -9285,8 +9285,21 @@ static bool isCPPAttribute(const Token * tok) return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1); } -void Tokenizer::reportUnknownMacrosInNonExecutableScopes() +void Tokenizer::reportUnknownMacros() { + // Report unknown macros used in expressions "%name% %num%" + for (const Token *tok = tokens(); tok; tok = tok->next()) { + if (Token::Match(tok, "%name% %num%")) { + // A keyword is not an unknown macro + if (list.isKeyword(tok->str())) + continue; + + if (Token::Match(tok->previous(), "%op%|(")) + unknownMacroError(tok); + } + } + + // Report unknown macros in non-executable scopes.. for (const Token *tok = tokens(); tok; tok = tok->next()) { // Skip executable scopes.. if (tok->str() == "{") { @@ -9298,6 +9311,10 @@ void Tokenizer::reportUnknownMacrosInNonExecutableScopes() } if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) { + // A keyword is not an unknown macro + if (list.isKeyword(tok->str())) + continue; + const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2); const Token *bodyEnd = tok->link(); for (const Token *tok2 = bodyStart; tok2 && tok2 != bodyEnd; tok2 = tok2->next()) { diff --git a/lib/tokenize.h b/lib/tokenize.h index bead7d1dd..d22a98b9c 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -635,7 +635,7 @@ private: void validate() const; /** Detect unknown macros and throw unknownMacro */ - void reportUnknownMacrosInNonExecutableScopes(); + void reportUnknownMacros(); /** Detect garbage code and call syntaxError() if found. */ void findGarbageCode() const; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 18da6ca64..0974de9d0 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -43,6 +43,40 @@ TokenList::TokenList(const Settings* settings) : mIsC(false), mIsCpp(false) { + mKeywords.insert("auto"); + mKeywords.insert("break"); + mKeywords.insert("case"); + mKeywords.insert("char"); + mKeywords.insert("const"); + mKeywords.insert("continue"); + mKeywords.insert("default"); + mKeywords.insert("do"); + mKeywords.insert("double"); + mKeywords.insert("else"); + mKeywords.insert("enum"); + mKeywords.insert("extern"); + mKeywords.insert("float"); + mKeywords.insert("for"); + mKeywords.insert("goto"); + mKeywords.insert("if"); + mKeywords.insert("inline"); + mKeywords.insert("int"); + mKeywords.insert("long"); + mKeywords.insert("register"); + mKeywords.insert("restrict"); + mKeywords.insert("return"); + mKeywords.insert("short"); + mKeywords.insert("signed"); + mKeywords.insert("sizeof"); + mKeywords.insert("static"); + mKeywords.insert("struct"); + mKeywords.insert("switch"); + mKeywords.insert("typedef"); + mKeywords.insert("union"); + mKeywords.insert("unsigned"); + mKeywords.insert("void"); + mKeywords.insert("volatile"); + mKeywords.insert("while"); } TokenList::~TokenList() @@ -90,6 +124,38 @@ int TokenList::appendFileIfNew(const std::string &fileName) mIsC = mSettings->enforcedLang == Settings::C || (mSettings->enforcedLang == Settings::None && Path::isC(getSourceFilePath())); mIsCpp = mSettings->enforcedLang == Settings::CPP || (mSettings->enforcedLang == Settings::None && Path::isCPP(getSourceFilePath())); } + + if (mIsCpp) { + mKeywords.insert("catch"); + mKeywords.insert("delete"); + mKeywords.insert("class"); + mKeywords.insert("const_cast"); + mKeywords.insert("delete"); + mKeywords.insert("dynamic_cast"); + mKeywords.insert("explicit"); + mKeywords.insert("export"); + mKeywords.insert("false"); + mKeywords.insert("friend"); + mKeywords.insert("mutable"); + mKeywords.insert("namespace"); + mKeywords.insert("new"); + mKeywords.insert("operator"); + mKeywords.insert("private"); + mKeywords.insert("protected"); + mKeywords.insert("public"); + mKeywords.insert("reinterpret_cast"); + mKeywords.insert("static_cast"); + mKeywords.insert("template"); + mKeywords.insert("this"); + mKeywords.insert("throw"); + mKeywords.insert("true"); + mKeywords.insert("try"); + mKeywords.insert("typeid"); + mKeywords.insert("typename"); + mKeywords.insert("using"); + mKeywords.insert("virtual"); + mKeywords.insert("wchar_t"); + } } return mFiles.size() - 1; } @@ -140,7 +206,7 @@ void TokenList::addtoken(std::string str, const nonneg int lineno, const nonneg mTokensFrontBack.back->str(str); } - if (isCPP() && str == "delete") + if (isKeyword(str)) mTokensFrontBack.back->isKeyword(true); mTokensFrontBack.back->linenr(lineno); mTokensFrontBack.back->fileIndex(fileno); @@ -1690,3 +1756,7 @@ void TokenList::simplifyStdType() } } +bool TokenList::isKeyword(const std::string &str) const +{ + return mKeywords.find(str) != mKeywords.end(); +} diff --git a/lib/tokenlist.h b/lib/tokenlist.h index 3257ec671..9ef144c9f 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -188,6 +188,8 @@ public: void clangSetOrigFiles(); + bool isKeyword(const std::string &str) const; + private: /** Disable copy constructor, no implementation */ @@ -208,8 +210,11 @@ private: /** settings */ const Settings* mSettings; + std::set mKeywords; + /** File is known to be C/C++ code */ - bool mIsC, mIsCpp; + bool mIsC; + bool mIsCpp; }; /// @} diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 3d429c7a2..85800bc5a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -467,7 +467,7 @@ private: TEST_CASE(sizeofAddParentheses); - TEST_CASE(reportUnknownMacrosInNonExecutableScopes); + TEST_CASE(reportUnknownMacros); // Make sure the Tokenizer::findGarbageCode() does not have false positives // The TestGarbage ensures that there are true positives @@ -7972,10 +7972,13 @@ private: ASSERT_EQUALS("sizeof ( a ) > sizeof ( & main ) ;", tokenizeAndStringify("sizeof a > sizeof &main;")); } - void reportUnknownMacrosInNonExecutableScopes() { - const char code[] = "MY_UNKNOWN_IMP1(IInStream)\n" - "STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) { if (ptr); }"; - ASSERT_THROW(tokenizeAndStringify(code), InternalError); + void reportUnknownMacros() { + const char code1[] = "MY_UNKNOWN_IMP1(IInStream)\n" + "STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) { if (ptr); }"; + ASSERT_THROW(tokenizeAndStringify(code1), InternalError); + + const char code2[] = "void foo() { dostuff(x 0); }"; + ASSERT_THROW(tokenizeAndStringify(code2), InternalError); } void findGarbageCode() { // Test Tokenizer::findGarbageCode()