Added check to CheckInternal: detect invalid patterns like "%typ%"

Replaced some Token::Match by Token::simpleMatch (suggestions of internal checks)
This commit is contained in:
PKEuS 2012-07-11 08:45:16 -07:00
parent 524df179af
commit e8f4dce25f
7 changed files with 79 additions and 7 deletions

View File

@ -1511,7 +1511,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func)
else if (tok2->isName() && isMemberVar(scope, tok2))
return(false); // TODO: Only bailout if function takes argument as non-const reference
}
} else if (Token::Match(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) {
} else if (Token::simpleMatch(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) {
return(false);
} else if (Token::Match(tok1, "%var% . %var% (")) {
if (!isMemberVar(scope, tok1))

View File

@ -169,6 +169,51 @@ void CheckInternal::checkMissingPercentCharacter()
}
}
void CheckInternal::checkUnknownPattern()
{
static std::set<std::string> knownPatterns;
if (knownPatterns.empty()) {
knownPatterns.insert("%any%");
knownPatterns.insert("%var%");
knownPatterns.insert("%type%");
knownPatterns.insert("%num%");
knownPatterns.insert("%bool%");
knownPatterns.insert("%str%");
knownPatterns.insert("%varid%");
knownPatterns.insert("%or%");
knownPatterns.insert("%oror%");
knownPatterns.insert("%op%");
}
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (!Token::simpleMatch(tok, "Token :: Match (") && !Token::simpleMatch(tok, "Token :: findmatch ("))
continue;
// Get pattern string
const Token *pattern_tok = tok->tokAt(4)->nextArgument();
if (!pattern_tok || pattern_tok->type() != Token::eString)
continue;
const std::string pattern = pattern_tok->strValue();
bool inBrackets = false;
for (std::string::size_type i = 0; i < pattern.length()-1; i++) {
if (pattern[i] == '[' && (i == 0 || pattern[i-1] == ' '))
inBrackets = true;
else if (pattern[i] == ']')
inBrackets = false;
else if (pattern[i] == '%' && pattern[i+1] != ' ' && pattern[i+1] != '|' && !inBrackets) {
std::string::size_type end = pattern.find('%', i+1);
if (end != std::string::npos) {
std::string s = pattern.substr(i, end-i+1);
if (knownPatterns.find(s) == knownPatterns.end())
unknownPatternError(tok, s);
}
}
}
}
}
void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
{
reportError(tok, Severity::warning, "simplePatternError",
@ -190,4 +235,10 @@ void CheckInternal::missingPercentCharacterError(const Token* tok, const std::st
);
}
void CheckInternal::unknownPatternError(const Token* tok, const std::string& pattern)
{
reportError(tok, Severity::error, "unkownPattern",
"Unkown pattern used: \"" + pattern + "\"");
}
#endif // #ifndef NDEBUG

View File

@ -53,6 +53,7 @@ public:
checkInternal.checkTokenMatchPatterns();
checkInternal.checkTokenSimpleMatchPatterns();
checkInternal.checkMissingPercentCharacter();
checkInternal.checkUnknownPattern();
}
/** @brief %Check if a simple pattern is used inside Token::Match or Token::findmatch */
@ -64,16 +65,21 @@ public:
/** @brief %Check for missing % end character in Token::Match pattern */
void checkMissingPercentCharacter();
/** @brief %Check for for unkown (invalid) complex patterns like "%typ%" */
void checkUnknownPattern();
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 unknownPatternError(const Token* tok, const std::string& pattern);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckInternal c(0, settings, errorLogger);
c.simplePatternError(0, "class {", "Match");
c.complexPatternError(0, "%type% ( )", "Match");
c.missingPercentCharacterError(0, "%num", "Match");
c.unknownPatternError(0, "%typ");
}
std::string myName() const {

View File

@ -102,7 +102,7 @@ void CheckIO::checkFileUsage()
std::size_t varListSize = symbolDatabase->getVariableListSize();
for (std::size_t i = 1; i < varListSize; ++i) {
const Variable* var = symbolDatabase->getVariableFromVarId(i);
if (!var || !var->varId() || !Token::Match(var->typeStartToken(), "FILE *"))
if (!var || !var->varId() || !Token::simpleMatch(var->typeStartToken(), "FILE *"))
continue;
if (var->isLocal()) {
@ -153,7 +153,7 @@ void CheckIO::checkFileUsage()
fileTok = tok->tokAt(-2);
operation = Filepointer::OPEN;
} else if (tok->str() == "rewind" || tok->str() == "fseek" || tok->str() == "fsetpos" || tok->str() == "fflush") {
if (Token::Match(tok, "fflush ( stdin )"))
if (Token::simpleMatch(tok, "fflush ( stdin )"))
fflushOnInputStreamError(tok, tok->strAt(2));
else {
fileTok = tok->tokAt(2);

View File

@ -508,7 +508,7 @@ void CheckOther::checkSizeofForPointerSize()
variable = tok->next();
tokVar = tok->tokAt(5)->nextArgument();
} else if (Token::Match(tok, "memset (")) {
} else if (Token::simpleMatch(tok, "memset (")) {
variable = tok->tokAt(2);
tokVar = variable->tokAt(2)->nextArgument();

View File

@ -1334,12 +1334,12 @@ void CheckStl::uselessCalls()
} else if (tok->varId() && Token::Match(tok, "%var% . swap ( %var% )") &&
tok->varId() == tok->tokAt(4)->varId()) {
uselessCallsSwapError(tok, tok->str());
} else if (Token::Match(tok, ". substr (")) {
} else if (Token::simpleMatch(tok, ". substr (")) {
if (Token::Match(tok->tokAt(3), "0| )"))
uselessCallsSubstrError(tok, false);
else if (tok->strAt(3) == "0" && tok->linkAt(2)->strAt(-1) == "npos")
uselessCallsSubstrError(tok, false);
else if (Token::Match(tok->linkAt(2)->tokAt(-2), ", 0 )"))
else if (Token::simpleMatch(tok->linkAt(2)->tokAt(-2), ", 0 )"))
uselessCallsSubstrError(tok, true);
}
}

View File

@ -37,6 +37,7 @@ private:
TEST_CASE(simplePatternSquareBrackets)
TEST_CASE(simplePatternAlternatives)
TEST_CASE(missingPercentCharacter)
TEST_CASE(unknownPattern)
TEST_CASE(internalError)
}
@ -212,7 +213,8 @@ 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) Missing percent end character in Token::Match() pattern: \"foo % %type % bar\"\n"
"[test.cpp:3]: (error) Unkown pattern used: \"%type %\"\n", errout.str());
// Find missing % also in 'alternatives' pattern
check("void f() {\n"
@ -229,6 +231,19 @@ private:
ASSERT_EQUALS("", errout.str());
}
void unknownPattern() {
check("void f() {\n"
" Token::Match(tok, \"%typ%\");\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Unkown pattern used: \"%typ%\"\n", errout.str());
// Make sure we don't take %or% for a broken %oror%
check("void f() {\n"
" Token::Match(tok, \"%type%\");\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void internalError() {
// Make sure cppcheck does not raise an internal error of Token::Match ( Ticket #3727 )
check("class DELPHICLASS X;\n"