diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 0b92554a5..74dd791b8 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4198,12 +4198,15 @@ void Tokenizer::removeMacrosInGlobalScope() tok->deleteNext(); } - if ((!tok->previous() || Token::Match(tok->previous(), "[;{}]")) && - Token::Match(tok, "%type%") && tok->isUpperCaseName()) { + if (Token::Match(tok, "%type%") && tok->isUpperCaseName() && + (!tok->previous() || Token::Match(tok->previous(), "[;{}]") || (tok->previous()->isName() && endsWith(tok->previous()->str(), ':')))) { const Token *tok2 = tok->next(); if (tok2 && tok2->str() == "(") tok2 = tok2->link()->next(); + if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) + unknownMacroError(tok); + // remove unknown macros before namespace|class|struct|union if (Token::Match(tok2, "namespace|class|struct|union")) { // is there a "{" for? @@ -4218,14 +4221,15 @@ void Tokenizer::removeMacrosInGlobalScope() } // replace unknown macros before foo( - if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) { - std::string typeName; - for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next()) - typeName += tok3->str(); - Token::eraseTokens(tok, tok2); - tok->str(typeName); - } - + /* + if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) { + std::string typeName; + for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next()) + typeName += tok3->str(); + Token::eraseTokens(tok, tok2); + tok->str(typeName); + } + */ // remove unknown macros before foo::foo( if (Token::Match(tok2, "%type% :: %type%")) { const Token *tok3 = tok2; @@ -7916,6 +7920,12 @@ void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX); } +void Tokenizer::unknownMacroError(const Token *tok1) const +{ + printDebugOutput(0); + throw InternalError(tok1, "There is an unknown macro here somewhere. Configuration is required. If " + tok1->str() + " is a macro then please configure it.", InternalError::SYNTAX); +} + void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const { reportError(tok, diff --git a/lib/tokenize.h b/lib/tokenize.h index 594f85f89..d8cadbff2 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -598,6 +598,9 @@ public: /** Syntax error. C++ code in C file. */ void syntaxErrorC(const Token *tok, const std::string &what) const; + /** Warn about unknown macro(s), configuration is recommended */ + void unknownMacroError(const Token *tok1) const; + private: /** Report that there is an unhandled "class x y {" code */ diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 0891604cd..6eabb296d 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -1448,9 +1448,8 @@ private: const char code[] = "typedef char (* type1)[10];\n" "LOCAL(type1) foo() { }"; - // this is invalid C so just make sure it doesn't generate an internal error - checkSimplifyTypedef(code); - ASSERT_EQUALS("", errout.str()); + // this is invalid C, assert that an "unknown macro" warning is written + ASSERT_THROW(checkSimplifyTypedef(code), InternalError); } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 0fa97f2c7..d0d591e47 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6155,8 +6155,8 @@ private: ASSERT_EQUALS("; foo :: foo ( ) { }", tokenizeAndStringify("; AB(foo*) foo::foo() { }")); - // #4834 - ASSERT_EQUALS("A(B) foo ( ) { }", tokenizeAndStringify("A(B) foo() {}")); + // #4834 - syntax error + ASSERT_THROW(tokenizeAndStringify("A(B) foo() {}"), InternalError); // #3855 ASSERT_EQUALS("; class foo { }",