Add internal check that searches Token::Match() patterns for missing % end charaters

Example: "%type" or "foo %var bar"
This commit is contained in:
Thomas Jarosch 2011-10-29 12:13:46 +02:00
parent b67cb077a3
commit 3d438003ff
3 changed files with 121 additions and 1 deletions

View File

@ -116,6 +116,56 @@ void CheckInternal::checkTokenSimpleMatchPatterns()
}
}
void CheckInternal::checkMissingPercentCharacter()
{
set<string> magics;
magics.insert("%any%");
magics.insert("%var%");
magics.insert("%type%");
magics.insert("%num%");
magics.insert("%bool%");
magics.insert("%str%");
magics.insert("%varid%");
magics.insert("%or%");
magics.insert("%oror%");
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (!Token::simpleMatch(tok, "Token :: Match (") && !Token::simpleMatch(tok, "Token :: findmatch ("))
continue;
const std::string funcname = tok->strAt(2);
// Get pattern string
const Token *pattern_tok = tok->tokAt(4)->nextArgument();
if (!pattern_tok || !Token::Match(pattern_tok, "%str%"))
continue;
const string pattern = pattern_tok->strValue();
set<string>::const_iterator magic, magics_end = magics.end();
for (magic = magics.begin(); magic != magics_end; ++magic) {
const string broken_magic = (*magic).substr(0, (*magic).size()-1);
string::size_type pos = 0;
while((pos = pattern.find(broken_magic, pos)) != string::npos) {
// Check if it's the full pattern
if (pattern.find(*magic, pos) != pos) {
// Known whitelist of substrings
if ((broken_magic == "%var" && pattern.find("%varid%", pos) == pos) ||
(broken_magic == "%or" && pattern.find("%oror%", pos) == pos)) {
++pos;
continue;
}
missingPercentCharacterError(tok, pattern, funcname);
}
++pos;
}
}
}
}
void CheckInternal::simplePatternError(const Token* tok, const string& pattern, const std::string &funcname)
{
reportError(tok, Severity::warning, "simplePatternError",
@ -129,3 +179,10 @@ void CheckInternal::complexPatternError(const Token* tok, const string& pattern,
"Found complex pattern inside Token::" + funcname + "() call: \"" + pattern + "\""
);
}
void CheckInternal::missingPercentCharacterError(const Token* tok, const std::string& pattern, const std::string& funcname)
{
reportError(tok, Severity::error, "missingPercentCharacter",
"Missing percent end character in Token::" + funcname + "() pattern: \"" + pattern + "\""
);
}

View File

@ -51,6 +51,7 @@ public:
checkInternal.checkTokenMatchPatterns();
checkInternal.checkTokenSimpleMatchPatterns();
checkInternal.checkMissingPercentCharacter();
}
/** @brief %Check if a simple pattern is used inside Token::Match or Token::findmatch */
@ -59,14 +60,19 @@ public:
/** @brief %Check if a complex pattern is used inside Token::simpleMatch or Token::findsimplematch */
void checkTokenSimpleMatchPatterns();
/** @brief %Check for missing % end character in Token::Match pattern */
void checkMissingPercentCharacter();
private:
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);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) {
CheckInternal c(0, settings, errorLogger);
c.simplePatternError(0, "class {", "Match");
c.complexPatternError(0, "%type% ( )", "Match");
c.missingPercentCharacterError(0, "%num", "Match");
}
std::string myName() const {
@ -76,7 +82,8 @@ private:
std::string classInfo() const {
return "Check for wrong or unsuitable internal API usage:\n"
"* Found simple pattern inside Token::Match() call: \"class {\"\n"
"* Found complex pattern inside Token::simpleMatch() call: \"%type\"\n";
"* Found complex pattern inside Token::simpleMatch() call: \"%type%\"\n"
"* Missing percent end character in Token::Match pattern: \"%num\"\n";
}
};
/// @}

View File

@ -36,6 +36,7 @@ private:
TEST_CASE(complexPatternInTokenSimpleMatch)
TEST_CASE(simplePatternSquareBrackets)
TEST_CASE(simplePatternAlternatives)
TEST_CASE(missingPercentCharacter);
}
void check(const std::string &code) {
@ -171,6 +172,61 @@ private:
"}");
ASSERT_EQUALS("", errout.str());
}
void missingPercentCharacter() {
check("void f() {\n"
" const Token *tok;\n"
" Token::Match(tok, \"%type%\");\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" const Token *tok;\n"
" Token::Match(tok, \"foo %type% bar\");\n"
"}");
ASSERT_EQUALS("", errout.str());
// Missing % at the end of string
check("void f() {\n"
" const Token *tok;\n"
" Token::Match(tok, \"%type\");\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"%type\"\n", errout.str());
// Missing % in the middle of a pattern
check("void f() {\n"
" 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());
// Bei quiet on single %
check("void f() {\n"
" const Token *tok;\n"
" Token::Match(tok, \"foo % %type% bar\");\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" 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());
// Find missing % also in 'alternatives' pattern
check("void f() {\n"
" 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());
// Make sure we don't take %or% for a broken %oror%
check("void f() {\n"
" const Token *tok;\n"
" Token::Match(tok, \"foo|%oror%|bar\");\n"
"}");
ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestInternal)