Detect and purge duplicate configurations by calculating a checksum.
This commit is contained in:
parent
a632f68345
commit
bf2f76e70c
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue