From 6f6f9dd5bc6214095c168d096f732a840a930587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 19 Feb 2020 21:11:54 +0100 Subject: [PATCH] Tokenizer: Throw unknownMacro in non-executable scope --- lib/tokenize.cpp | 25 +++++++++++++++++++++++++ lib/tokenize.h | 3 +++ test/testsymboldatabase.cpp | 7 +++---- test/testtokenize.cpp | 8 ++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e187937b4..a9a77039a 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4302,6 +4302,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) createLinks(); + reportUnknownMacrosInNonExecutableScopes(); + simplifyHeaders(); // Remove __asm.. @@ -9283,6 +9285,29 @@ static bool isCPPAttribute(const Token * tok) return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1); } +void Tokenizer::reportUnknownMacrosInNonExecutableScopes() +{ + for (const Token *tok = tokens(); tok; tok = tok->next()) { + // Skip executable scopes.. + if (tok->str() == "{") { + const Token *prev = tok->previous(); + while (prev && prev->isName()) + prev = prev->previous(); + if (prev && prev->str() == ")") + tok = tok->link(); + } + + if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) { + 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()) { + if (Token::Match(tok2, "if|switch|for|while|return")) + unknownMacroError(tok); + } + } + } +} + void Tokenizer::findGarbageCode() const { const bool isCPP11 = isCPP() && mSettings->standards.cpp >= Standards::CPP11; diff --git a/lib/tokenize.h b/lib/tokenize.h index f349d8da0..bead7d1dd 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -634,6 +634,9 @@ private: */ void validate() const; + /** Detect unknown macros and throw unknownMacro */ + void reportUnknownMacrosInNonExecutableScopes(); + /** Detect garbage code and call syntaxError() if found. */ void findGarbageCode() const; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 0bd77b223..6e3002aae 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -2537,10 +2537,9 @@ private: void symboldatabase5() { // ticket #2178 - segmentation fault - check("int CL_INLINE_DECL(integer_decode_float) (int x) {\n" - " return (sign ? cl_I() : 0);\n" - "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_THROW(check("int CL_INLINE_DECL(integer_decode_float) (int x) {\n" + " return (sign ? cl_I() : 0);\n" + "}"), InternalError); } void symboldatabase6() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 497387fb8..d93b184f5 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -466,6 +466,8 @@ private: TEST_CASE(sizeofAddParentheses); + TEST_CASE(reportUnknownMacrosInNonExecutableScopes); + // Make sure the Tokenizer::findGarbageCode() does not have false positives // The TestGarbage ensures that there are true positives TEST_CASE(findGarbageCode); @@ -7959,6 +7961,12 @@ 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 findGarbageCode() { // Test Tokenizer::findGarbageCode() // before if|for|while|switch ASSERT_NO_THROW(tokenizeAndStringify("void f() { do switch (a) {} while (1); }"))