Tokenizer: Add --check-config warning for macro with semicolon in argument

This commit is contained in:
Daniel Marjamäki 2017-04-07 19:19:10 +02:00
parent c16d82d729
commit 8ffed6862d
3 changed files with 54 additions and 0 deletions

View File

@ -3336,6 +3336,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
if (const Token *garbage = findGarbageCode()) if (const Token *garbage = findGarbageCode())
syntaxError(garbage); syntaxError(garbage);
checkConfiguration();
// if (x) MACRO() .. // if (x) MACRO() ..
for (const Token *tok = list.front(); tok; tok = tok->next()) { for (const Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "if (")) { if (Token::simpleMatch(tok, "if (")) {
@ -7638,6 +7640,14 @@ void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const
tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code."); tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code.");
} }
void Tokenizer::macroWithSemicolonError(const Token *tok, const std::string &macroName) const
{
reportError(tok,
Severity::information,
"macroWithSemicolon",
"Ensure that '" + macroName + "' is defined either using -I, --include or -D.");
}
void Tokenizer::cppcheckError(const Token *tok) const void Tokenizer::cppcheckError(const Token *tok) const
{ {
printDebugOutput(0); printDebugOutput(0);
@ -8004,6 +8014,25 @@ void Tokenizer::simplifyComma()
} }
} }
void Tokenizer::checkConfiguration() const
{
if (!_settings->checkConfiguration)
return;
for (const Token *tok = tokens(); tok; tok = tok->next()) {
if (!Token::Match(tok, "%name% ("))
continue;
if (Token::Match(tok, "if|for|while|switch"))
continue;
for (const Token *tok2 = tok->tokAt(2); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
if (tok2->str() == ";") {
macroWithSemicolonError(tok, tok->str());
break;
}
if (Token::Match(tok2, "(|{"))
tok2 = tok2->link();
}
}
}
void Tokenizer::validateC() const void Tokenizer::validateC() const
{ {

View File

@ -576,6 +576,10 @@ private:
/** Report that there is an unhandled "class x y {" code */ /** Report that there is an unhandled "class x y {" code */
void unhandled_macro_class_x_y(const Token *tok) const; void unhandled_macro_class_x_y(const Token *tok) const;
/** Check configuration (unknown macros etc) */
void checkConfiguration() const;
void macroWithSemicolonError(const Token *tok, const std::string &macroName) const;
/** /**
* Is there C++ code in C file? * Is there C++ code in C file?
*/ */

View File

@ -457,6 +457,9 @@ private:
// Make sure the Tokenizer::findGarbageCode() does not have false positives // Make sure the Tokenizer::findGarbageCode() does not have false positives
// The TestGarbage ensures that there are true positives // The TestGarbage ensures that there are true positives
TEST_CASE(findGarbageCode); TEST_CASE(findGarbageCode);
// --check-config
TEST_CASE(checkConfiguration);
} }
std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Native, const char* filename = "test.cpp", bool cpp11 = true) { std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Native, const char* filename = "test.cpp", bool cpp11 = true) {
@ -8250,6 +8253,24 @@ private:
// after (expr) // after (expr)
ASSERT_NO_THROW(tokenizeAndStringify("void f() { switch (a) int b; }")); ASSERT_NO_THROW(tokenizeAndStringify("void f() { switch (a) int b; }"));
} }
void checkConfig(const char code[]) {
errout.str("");
Settings s;
s.checkConfiguration = true;
// tokenize..
Tokenizer tokenizer(&s, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
}
void checkConfiguration() {
checkConfig("void f() { DEBUG(x();y()); }");
ASSERT_EQUALS("[test.cpp:1]: (information) Ensure that 'DEBUG' is defined either using -I, --include or -D.\n", errout.str());
}
}; };
REGISTER_TEST(TestTokenizer) REGISTER_TEST(TestTokenizer)