Skip to content

Commit 537166c

Browse files
committed
Rules: Make it possible run a rule on the 'normal' token list
1 parent 964b6cb commit 537166c

4 files changed

Lines changed: 101 additions & 70 deletions

File tree

cli/cmdlineparser.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,10 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
598598
for (; node && strcmp(node->Value(), "rule") == 0; node = node->NextSiblingElement()) {
599599
Settings::Rule rule;
600600

601+
tinyxml2::XMLElement *tokenlist = node->FirstChildElement("tokenlist");
602+
if (tokenlist)
603+
rule.tokenlist = tokenlist->GetText();
604+
601605
tinyxml2::XMLElement *pattern = node->FirstChildElement("pattern");
602606
if (pattern) {
603607
rule.pattern = pattern->GetText();

lib/cppcheck.cpp

Lines changed: 87 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
344344
if (_settings.isEnabled("unusedFunction") && _settings._jobs == 1)
345345
_checkUnusedFunctions.parseTokens(_tokenizer);
346346

347+
executeRules("normal", _tokenizer);
348+
347349
if (!_simplify)
348350
return;
349351

@@ -362,75 +364,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
362364
(*it)->runSimplifiedChecks(&_tokenizer, &_settings, this);
363365
}
364366

365-
#ifdef HAVE_RULES
366-
// Are there extra rules?
367-
if (!_settings.rules.empty()) {
368-
std::ostringstream ostr;
369-
for (const Token *tok = _tokenizer.tokens(); tok; tok = tok->next())
370-
ostr << " " << tok->str();
371-
const std::string str(ostr.str());
372-
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
373-
const Settings::Rule &rule = *it;
374-
if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty())
375-
continue;
376-
377-
const char *error = 0;
378-
int erroffset = 0;
379-
pcre *re = pcre_compile(rule.pattern.c_str(),0,&error,&erroffset,NULL);
380-
if (!re && error) {
381-
ErrorLogger::ErrorMessage errmsg(std::list<ErrorLogger::ErrorMessage::FileLocation>(),
382-
Severity::error,
383-
error,
384-
"pcre_compile",
385-
false);
386-
387-
reportErr(errmsg);
388-
}
389-
if (!re)
390-
continue;
391-
392-
int pos = 0;
393-
int ovector[30];
394-
while (0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) {
395-
unsigned int pos1 = (unsigned int)ovector[0];
396-
unsigned int pos2 = (unsigned int)ovector[1];
397-
398-
// jump to the end of the match for the next pcre_exec
399-
pos = (int)pos2;
400-
401-
// determine location..
402-
ErrorLogger::ErrorMessage::FileLocation loc;
403-
loc.setfile(_tokenizer.getSourceFilePath());
404-
loc.line = 0;
405-
406-
unsigned int len = 0;
407-
for (const Token *tok = _tokenizer.tokens(); tok; tok = tok->next()) {
408-
len = len + 1 + tok->str().size();
409-
if (len > pos1) {
410-
loc.setfile(_tokenizer.list.getFiles().at(tok->fileIndex()));
411-
loc.line = tok->linenr();
412-
break;
413-
}
414-
}
415-
416-
const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc);
417-
418-
// Create error message
419-
std::string summary;
420-
if (rule.summary.empty())
421-
summary = "found '" + str.substr(pos1, pos2 - pos1) + "'";
422-
else
423-
summary = rule.summary;
424-
const ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id, false);
425-
426-
// Report error
427-
reportErr(errmsg);
428-
}
429-
430-
pcre_free(re);
431-
}
432-
}
433-
#endif
367+
executeRules("simple", _tokenizer);
434368
} catch (const InternalError &e) {
435369
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
436370
ErrorLogger::ErrorMessage::FileLocation loc2;
@@ -455,6 +389,90 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
455389
}
456390
}
457391

392+
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer)
393+
{
394+
// Are there rules to execute?
395+
bool isrule = false;
396+
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
397+
if (it->tokenlist == tokenlist)
398+
isrule = true;
399+
}
400+
401+
// There is no rule to execute
402+
if (isrule == false)
403+
return;
404+
405+
// Write all tokens in a string that can be parsed by pcre
406+
std::ostringstream ostr;
407+
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
408+
ostr << " " << tok->str();
409+
const std::string str(ostr.str());
410+
411+
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
412+
const Settings::Rule &rule = *it;
413+
if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty() || rule.tokenlist != tokenlist)
414+
continue;
415+
416+
#ifdef HAVE_RULES
417+
const char *error = 0;
418+
int erroffset = 0;
419+
pcre *re = pcre_compile(rule.pattern.c_str(),0,&error,&erroffset,NULL);
420+
if (!re) {
421+
if (error) {
422+
ErrorLogger::ErrorMessage errmsg(std::list<ErrorLogger::ErrorMessage::FileLocation>(),
423+
Severity::error,
424+
error,
425+
"pcre_compile",
426+
false);
427+
428+
reportErr(errmsg);
429+
}
430+
continue;
431+
}
432+
433+
int pos = 0;
434+
int ovector[30];
435+
while (pos < (int)str.size() && 0 <= pcre_exec(re, NULL, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) {
436+
unsigned int pos1 = (unsigned int)ovector[0];
437+
unsigned int pos2 = (unsigned int)ovector[1];
438+
439+
// jump to the end of the match for the next pcre_exec
440+
pos = (int)pos2;
441+
442+
// determine location..
443+
ErrorLogger::ErrorMessage::FileLocation loc;
444+
loc.setfile(tokenizer.getSourceFilePath());
445+
loc.line = 0;
446+
447+
std::size_t len = 0;
448+
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
449+
len = len + 1U + tok->str().size();
450+
if (len > pos1) {
451+
loc.setfile(tokenizer.list.getFiles().at(tok->fileIndex()));
452+
loc.line = tok->linenr();
453+
break;
454+
}
455+
}
456+
457+
const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc);
458+
459+
// Create error message
460+
std::string summary;
461+
if (rule.summary.empty())
462+
summary = "found '" + str.substr(pos1, pos2 - pos1) + "'";
463+
else
464+
summary = rule.summary;
465+
const ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id, false);
466+
467+
// Report error
468+
reportErr(errmsg);
469+
}
470+
471+
pcre_free(re);
472+
#endif
473+
}
474+
}
475+
458476
Settings &CppCheck::settings()
459477
{
460478
return _settings;

lib/cppcheck.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ class CPPCHECKLIB CppCheck : ErrorLogger {
148148
/** @brief Check file */
149149
void checkFile(const std::string &code, const char FileName[]);
150150

151+
/**
152+
* @brief Execute rules, if any
153+
* @param tokenlist token list to use (normal / simple)
154+
* @param tokenizer tokenizer
155+
*/
156+
void executeRules(const std::string &tokenlist, const Tokenizer &tokenizer);
157+
151158
/**
152159
* @brief Errors and warnings are directed here.
153160
*

lib/settings.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,12 @@ class CPPCHECKLIB Settings {
178178
class CPPCHECKLIB Rule {
179179
public:
180180
Rule()
181-
: id("rule") // default id
181+
: tokenlist("simple") // use simple tokenlist
182+
, id("rule") // default id
182183
, severity("style") { // default severity
183184
}
184185

186+
std::string tokenlist;
185187
std::string pattern;
186188
std::string id;
187189
std::string severity;

0 commit comments

Comments
 (0)