From 8ffed6862d8c71e742d8edddd94d3679b5ea864d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 7 Apr 2017 19:19:10 +0200 Subject: [PATCH] Tokenizer: Add --check-config warning for macro with semicolon in argument --- lib/tokenize.cpp | 29 +++++++++++++++++++++++++++++ lib/tokenize.h | 4 ++++ test/testtokenize.cpp | 21 +++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 958c0dfd0..8e2e2c625 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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 ¯oName) 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 { diff --git a/lib/tokenize.h b/lib/tokenize.h index fc7d8e00e..ee0e53afd 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -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 ¯oName) const; + /** * Is there C++ code in C file? */ diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 4c652f30f..cceada414 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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)