Detect and purge duplicate configurations by calculating a checksum.

This commit is contained in:
PKEuS 2014-09-02 18:05:02 +02:00
parent a632f68345
commit bf2f76e70c
4 changed files with 79 additions and 15 deletions

View File

@ -82,8 +82,9 @@ void CppCheck::replaceAll(std::string& code, const std::string &from, const std:
bool CppCheck::findError(std::string code, const char FileName[])
{
std::set<unsigned long long> checksums;
// First make sure that error occurs with the original code
checkFile(code, FileName);
checkFile(code, FileName, checksums);
if (_errorList.empty()) {
// Error does not occur with this code
return false;
@ -102,7 +103,8 @@ bool CppCheck::findError(std::string code, const char FileName[])
// is still there.
code = previousCode.substr(found+9);
_errorList.clear();
checkFile(code, FileName);
checksums.clear();
checkFile(code, FileName, checksums);
}
if (_errorList.empty()) {
@ -199,6 +201,7 @@ unsigned int CppCheck::processFile(const std::string& filename, const std::strin
}
}
std::set<unsigned long long> checksums;
unsigned int checkCount = 0;
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
// Check only a few configurations (default 12), after that bail out, unless --force
@ -232,7 +235,10 @@ unsigned int CppCheck::processFile(const std::string& filename, const std::strin
return exitcode;
}
} else {
checkFile(codeWithoutCfg + appendCode, filename.c_str());
if (!checkFile(codeWithoutCfg + appendCode, filename.c_str(), checksums)) {
if (_settings.isEnabled("information") && (_settings.debug || _settings._verbose))
purgedConfigurationMessage(filename, cfg);
}
}
}
} catch (const std::runtime_error &e) {
@ -325,11 +331,10 @@ void CppCheck::analyseFile(std::istream &fin, const std::string &filename)
//---------------------------------------------------------------------------
// CppCheck - A function that checks a specified file
//---------------------------------------------------------------------------
void CppCheck::checkFile(const std::string &code, const char FileName[])
bool CppCheck::checkFile(const std::string &code, const char FileName[], std::set<unsigned long long>& checksums)
{
if (_settings.terminated() || _settings.checkConfiguration)
return;
return true;
Tokenizer _tokenizer(&_settings, this);
if (_settings._showtime != SHOWTIME_NONE)
@ -354,9 +359,15 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
Timer timer("Tokenizer::tokenize", _settings._showtime, &S_timerResults);
result = _tokenizer.tokenize(istr, FileName, cfg);
timer.Stop();
unsigned long long checksum = _tokenizer.list.calculateChecksum();
if (checksums.find(checksum) != checksums.end())
return false;
checksums.insert(checksum);
if (!result) {
// File had syntax errors, abort
return;
return true;
}
// dump
@ -369,13 +380,13 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
_tokenizer.dump(fdump);
fdump << "</dump>" << std::endl;
}
return;
return true;
}
// call all "runChecks" in all registered Check classes
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
if (_settings.terminated())
return;
return true;
Timer timerRunChecks((*it)->name() + "::runChecks", _settings._showtime, &S_timerResults);
(*it)->runChecks(&_tokenizer, &_settings, this);
@ -387,30 +398,30 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
executeRules("normal", _tokenizer);
if (!_simplify)
return;
return true;
Timer timer3("Tokenizer::simplifyTokenList2", _settings._showtime, &S_timerResults);
result = _tokenizer.simplifyTokenList2();
timer3.Stop();
if (!result)
return;
return true;
// call all "runSimplifiedChecks" in all registered Check classes
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
if (_settings.terminated())
return;
return true;
Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", _settings._showtime, &S_timerResults);
(*it)->runSimplifiedChecks(&_tokenizer, &_settings, this);
}
if (_settings.terminated())
return;
return true;
executeRules("simple", _tokenizer);
if (_settings.terminated())
return;
return true;
} catch (const InternalError &e) {
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc;
@ -433,6 +444,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
_errorLogger.reportErr(errmsg);
}
return true;
}
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer)
@ -567,6 +579,30 @@ void CppCheck::tooManyConfigsError(const std::string &file, const std::size_t nu
reportErr(errmsg);
}
void CppCheck::purgedConfigurationMessage(const std::string &file, const std::string& configuration)
{
tooManyConfigs = false;
if (_settings.isEnabled("information") && file.empty())
return;
std::list<ErrorLogger::ErrorMessage::FileLocation> loclist;
if (!file.empty()) {
ErrorLogger::ErrorMessage::FileLocation location;
location.setfile(file);
loclist.push_back(location);
}
ErrorLogger::ErrorMessage errmsg(loclist,
Severity::information,
"The configuration '" + configuration + "' was not checked because its code equals another one.",
"toomanyconfigs",
false);
reportErr(errmsg);
}
//---------------------------------------------------------------------------
void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg)

View File

@ -128,6 +128,7 @@ public:
void analyseFile(std::istream &f, const std::string &filename);
void tooManyConfigsError(const std::string &file, const std::size_t numberOfConfigurations);
void purgedConfigurationMessage(const std::string &file, const std::string& configuration);
void dontSimplify() {
_simplify = false;
@ -147,7 +148,7 @@ private:
unsigned int processFile(const std::string& filename, const std::string& fileContent);
/** @brief Check file */
void checkFile(const std::string &code, const char FileName[]);
bool checkFile(const std::string &code, const char FileName[], std::set<unsigned long long>& checksums);
/**
* @brief Execute rules, if any

View File

@ -394,6 +394,27 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0)
return true;
}
//---------------------------------------------------------------------------
unsigned long long TokenList::calculateChecksum() const
{
unsigned long long checksum = 0;
for (const Token* tok = front(); tok; tok = tok->next()) {
unsigned int subchecksum1 = tok->flags() + tok->varId() + static_cast<unsigned int>(tok->type());
unsigned int subchecksum2 = 0;
for (std::size_t i = 0; i < tok->str().size(); i++)
subchecksum2 += (unsigned int)tok->str()[i];
if (!tok->originalName().empty()) {
for (std::size_t i = 0; i < tok->originalName().size(); i++)
subchecksum2 += (unsigned int) tok->originalName()[i];
}
checksum ^= ((static_cast<unsigned long long>(subchecksum1) << 32) | subchecksum2);
}
return checksum;
}
//---------------------------------------------------------------------------
struct AST_state {

View File

@ -120,6 +120,12 @@ public:
*/
std::string fileLine(const Token *tok) const;
/**
* Calculates a 64-bit checksum of the token list used to compare
* multiple token lists with each other as quickly as possible.
*/
unsigned long long calculateChecksum() const;
void createAst();
private: