Skip to content

Commit e8f4dce

Browse files
committed
Added check to CheckInternal: detect invalid patterns like "%typ%"
Replaced some Token::Match by Token::simpleMatch (suggestions of internal checks)
1 parent 524df17 commit e8f4dce

7 files changed

Lines changed: 79 additions & 7 deletions

File tree

lib/checkclass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1511,7 +1511,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func)
15111511
else if (tok2->isName() && isMemberVar(scope, tok2))
15121512
return(false); // TODO: Only bailout if function takes argument as non-const reference
15131513
}
1514-
} else if (Token::Match(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) {
1514+
} else if (Token::simpleMatch(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) {
15151515
return(false);
15161516
} else if (Token::Match(tok1, "%var% . %var% (")) {
15171517
if (!isMemberVar(scope, tok1))

lib/checkinternal.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,51 @@ void CheckInternal::checkMissingPercentCharacter()
169169
}
170170
}
171171

172+
void CheckInternal::checkUnknownPattern()
173+
{
174+
static std::set<std::string> knownPatterns;
175+
if (knownPatterns.empty()) {
176+
knownPatterns.insert("%any%");
177+
knownPatterns.insert("%var%");
178+
knownPatterns.insert("%type%");
179+
knownPatterns.insert("%num%");
180+
knownPatterns.insert("%bool%");
181+
knownPatterns.insert("%str%");
182+
knownPatterns.insert("%varid%");
183+
knownPatterns.insert("%or%");
184+
knownPatterns.insert("%oror%");
185+
knownPatterns.insert("%op%");
186+
}
187+
188+
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
189+
if (!Token::simpleMatch(tok, "Token :: Match (") && !Token::simpleMatch(tok, "Token :: findmatch ("))
190+
continue;
191+
192+
// Get pattern string
193+
const Token *pattern_tok = tok->tokAt(4)->nextArgument();
194+
if (!pattern_tok || pattern_tok->type() != Token::eString)
195+
continue;
196+
197+
const std::string pattern = pattern_tok->strValue();
198+
bool inBrackets = false;
199+
200+
for (std::string::size_type i = 0; i < pattern.length()-1; i++) {
201+
if (pattern[i] == '[' && (i == 0 || pattern[i-1] == ' '))
202+
inBrackets = true;
203+
else if (pattern[i] == ']')
204+
inBrackets = false;
205+
else if (pattern[i] == '%' && pattern[i+1] != ' ' && pattern[i+1] != '|' && !inBrackets) {
206+
std::string::size_type end = pattern.find('%', i+1);
207+
if (end != std::string::npos) {
208+
std::string s = pattern.substr(i, end-i+1);
209+
if (knownPatterns.find(s) == knownPatterns.end())
210+
unknownPatternError(tok, s);
211+
}
212+
}
213+
}
214+
}
215+
}
216+
172217
void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
173218
{
174219
reportError(tok, Severity::warning, "simplePatternError",
@@ -190,4 +235,10 @@ void CheckInternal::missingPercentCharacterError(const Token* tok, const std::st
190235
);
191236
}
192237

238+
void CheckInternal::unknownPatternError(const Token* tok, const std::string& pattern)
239+
{
240+
reportError(tok, Severity::error, "unkownPattern",
241+
"Unkown pattern used: \"" + pattern + "\"");
242+
}
243+
193244
#endif // #ifndef NDEBUG

lib/checkinternal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class CPPCHECKLIB CheckInternal : public Check {
5353
checkInternal.checkTokenMatchPatterns();
5454
checkInternal.checkTokenSimpleMatchPatterns();
5555
checkInternal.checkMissingPercentCharacter();
56+
checkInternal.checkUnknownPattern();
5657
}
5758

5859
/** @brief %Check if a simple pattern is used inside Token::Match or Token::findmatch */
@@ -64,16 +65,21 @@ class CPPCHECKLIB CheckInternal : public Check {
6465
/** @brief %Check for missing % end character in Token::Match pattern */
6566
void checkMissingPercentCharacter();
6667

68+
/** @brief %Check for for unkown (invalid) complex patterns like "%typ%" */
69+
void checkUnknownPattern();
70+
6771
private:
6872
void simplePatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
6973
void complexPatternError(const Token *tok, const std::string &pattern, const std::string &funcname);
7074
void missingPercentCharacterError(const Token *tok, const std::string &pattern, const std::string &funcname);
75+
void unknownPatternError(const Token* tok, const std::string& pattern);
7176

7277
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
7378
CheckInternal c(0, settings, errorLogger);
7479
c.simplePatternError(0, "class {", "Match");
7580
c.complexPatternError(0, "%type% ( )", "Match");
7681
c.missingPercentCharacterError(0, "%num", "Match");
82+
c.unknownPatternError(0, "%typ");
7783
}
7884

7985
std::string myName() const {

lib/checkio.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void CheckIO::checkFileUsage()
102102
std::size_t varListSize = symbolDatabase->getVariableListSize();
103103
for (std::size_t i = 1; i < varListSize; ++i) {
104104
const Variable* var = symbolDatabase->getVariableFromVarId(i);
105-
if (!var || !var->varId() || !Token::Match(var->typeStartToken(), "FILE *"))
105+
if (!var || !var->varId() || !Token::simpleMatch(var->typeStartToken(), "FILE *"))
106106
continue;
107107

108108
if (var->isLocal()) {
@@ -153,7 +153,7 @@ void CheckIO::checkFileUsage()
153153
fileTok = tok->tokAt(-2);
154154
operation = Filepointer::OPEN;
155155
} else if (tok->str() == "rewind" || tok->str() == "fseek" || tok->str() == "fsetpos" || tok->str() == "fflush") {
156-
if (Token::Match(tok, "fflush ( stdin )"))
156+
if (Token::simpleMatch(tok, "fflush ( stdin )"))
157157
fflushOnInputStreamError(tok, tok->strAt(2));
158158
else {
159159
fileTok = tok->tokAt(2);

lib/checkother.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ void CheckOther::checkSizeofForPointerSize()
508508
variable = tok->next();
509509
tokVar = tok->tokAt(5)->nextArgument();
510510

511-
} else if (Token::Match(tok, "memset (")) {
511+
} else if (Token::simpleMatch(tok, "memset (")) {
512512
variable = tok->tokAt(2);
513513
tokVar = variable->tokAt(2)->nextArgument();
514514

lib/checkstl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,12 +1334,12 @@ void CheckStl::uselessCalls()
13341334
} else if (tok->varId() && Token::Match(tok, "%var% . swap ( %var% )") &&
13351335
tok->varId() == tok->tokAt(4)->varId()) {
13361336
uselessCallsSwapError(tok, tok->str());
1337-
} else if (Token::Match(tok, ". substr (")) {
1337+
} else if (Token::simpleMatch(tok, ". substr (")) {
13381338
if (Token::Match(tok->tokAt(3), "0| )"))
13391339
uselessCallsSubstrError(tok, false);
13401340
else if (tok->strAt(3) == "0" && tok->linkAt(2)->strAt(-1) == "npos")
13411341
uselessCallsSubstrError(tok, false);
1342-
else if (Token::Match(tok->linkAt(2)->tokAt(-2), ", 0 )"))
1342+
else if (Token::simpleMatch(tok->linkAt(2)->tokAt(-2), ", 0 )"))
13431343
uselessCallsSubstrError(tok, true);
13441344
}
13451345
}

test/testinternal.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class TestInternal : public TestFixture {
3737
TEST_CASE(simplePatternSquareBrackets)
3838
TEST_CASE(simplePatternAlternatives)
3939
TEST_CASE(missingPercentCharacter)
40+
TEST_CASE(unknownPattern)
4041
TEST_CASE(internalError)
4142
}
4243

@@ -212,7 +213,8 @@ class TestInternal : public TestFixture {
212213
" const Token *tok;\n"
213214
" Token::Match(tok, \"foo % %type % bar\");\n"
214215
"}");
215-
ASSERT_EQUALS("[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo % %type % bar\"\n", errout.str());
216+
ASSERT_EQUALS("[test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \"foo % %type % bar\"\n"
217+
"[test.cpp:3]: (error) Unkown pattern used: \"%type %\"\n", errout.str());
216218

217219
// Find missing % also in 'alternatives' pattern
218220
check("void f() {\n"
@@ -229,6 +231,19 @@ class TestInternal : public TestFixture {
229231
ASSERT_EQUALS("", errout.str());
230232
}
231233

234+
void unknownPattern() {
235+
check("void f() {\n"
236+
" Token::Match(tok, \"%typ%\");\n"
237+
"}");
238+
ASSERT_EQUALS("[test.cpp:2]: (error) Unkown pattern used: \"%typ%\"\n", errout.str());
239+
240+
// Make sure we don't take %or% for a broken %oror%
241+
check("void f() {\n"
242+
" Token::Match(tok, \"%type%\");\n"
243+
"}");
244+
ASSERT_EQUALS("", errout.str());
245+
}
246+
232247
void internalError() {
233248
// Make sure cppcheck does not raise an internal error of Token::Match ( Ticket #3727 )
234249
check("class DELPHICLASS X;\n"

0 commit comments

Comments
 (0)