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())
syntaxError(garbage);
checkConfiguration();
// if (x) MACRO() ..
for (const Token *tok = list.front(); tok; tok = tok->next()) {
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.");
}
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
{
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
{

View File

@ -576,6 +576,10 @@ private:
/** Report that there is an unhandled "class x y {" code */
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?
*/

View File

@ -457,6 +457,9 @@ private:
// Make sure the Tokenizer::findGarbageCode() does not have false positives
// The TestGarbage ensures that there are true positives
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) {
@ -8250,6 +8253,24 @@ private:
// after (expr)
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)