diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp index ca780cd07..88b78ef59 100644 --- a/lib/checkinternal.cpp +++ b/lib/checkinternal.cpp @@ -22,6 +22,7 @@ #include "symboldatabase.h" #include #include +#include // Register this check class (by creating a static instance of it). // Disabled in release builds @@ -48,6 +49,32 @@ void CheckInternal::checkTokenMatchPatterns() continue; } + const char *p = pattern.c_str(); + while (*p) { + while (*p && std::isspace(*p)) + p++; + const char *start = p; + while (*p && !std::isspace(*p)) + p++; + const char *end = p - 1; + if (start < end && !(*start == '[' && *end == ']')) { + // check multicompare pattern.. + for (const char *s = start; s != end; s++) { + if (*s == '|') { + if (*(s+1) == '%' && + std::isalpha(*(s+2)) && + std::strncmp(s+1,"%op%",4)!=0 && + std::strncmp(s+1,"%or%",4)!=0 && + std::strncmp(s+1,"%cop%",5)!=0 && + std::strncmp(s+1,"%var%",5)!=0 && + std::strncmp(s+1,"%oror%",6)!=0) { + multiComparePatternError(tok, pattern, funcname); + } + } + } + } + } + // Check for signs of complex patterns if (pattern.find_first_of("[|%") != std::string::npos) continue; @@ -245,6 +272,13 @@ void CheckInternal::checkRedundantNextPrevious() } } +void CheckInternal::multiComparePatternError(const Token* tok, const std::string& pattern, const std::string &funcname) +{ + reportError(tok, Severity::error, "multiComparePatternError", + "Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::" + funcname + "() call: \"" + pattern + "\"" + ); +} + void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname) { reportError(tok, Severity::warning, "simplePatternError", diff --git a/lib/checkinternal.h b/lib/checkinternal.h index a49336c1a..805b64c60 100644 --- a/lib/checkinternal.h +++ b/lib/checkinternal.h @@ -73,6 +73,7 @@ public: void checkRedundantNextPrevious(); private: + void multiComparePatternError(const Token *tok, const std::string &pattern, const std::string &funcname); void simplePatternError(const Token *tok, const std::string &pattern, const std::string &funcname); void complexPatternError(const Token *tok, const std::string &pattern, const std::string &funcname); void missingPercentCharacterError(const Token *tok, const std::string &pattern, const std::string &funcname); @@ -81,6 +82,7 @@ private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { CheckInternal c(0, settings, errorLogger); + c.multiComparePatternError(0, ";|%type%", "Match"); c.simplePatternError(0, "class {", "Match"); c.complexPatternError(0, "%type% ( )", "Match"); c.missingPercentCharacterError(0, "%num", "Match"); diff --git a/test/testinternal.cpp b/test/testinternal.cpp index dcaafced4..3d6cb4944 100644 --- a/test/testinternal.cpp +++ b/test/testinternal.cpp @@ -40,6 +40,7 @@ private: TEST_CASE(unknownPattern) TEST_CASE(redundantNextPrevious) TEST_CASE(internalError) + TEST_CASE(invalidMultiCompare); } void check(const char code[]) { @@ -222,7 +223,9 @@ private: " const Token *tok;\n" " Token::Match(tok, \"foo|%type|bar\");\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo|%type|bar\"\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::Match() call: \"foo|%type|bar\"\n" + "[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo|%type|bar\"\n" + , errout.str()); // Make sure we don't take %or% for a broken %oror% check("void f() {\n" @@ -312,6 +315,21 @@ private: "};"); ASSERT_EQUALS("", errout.str()); } + + void invalidMultiCompare() { + // #5310 + check("void f() {\n" + " const Token *tok;\n" + " Token::Match(tok, \";|%type%\");\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Bad multicompare pattern (a %cmd% must be first unless it is %or%,%op%,%cop%,%var%,%oror%) inside Token::Match() call: \";|%type%\"\n", errout.str()); + + check("void f() {\n" + " const Token *tok;\n" + " Token::Match(tok, \";|%oror%\");\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestInternal)