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[])
|
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
|
// First make sure that error occurs with the original code
|
||||||
checkFile(code, FileName);
|
checkFile(code, FileName, checksums);
|
||||||
if (_errorList.empty()) {
|
if (_errorList.empty()) {
|
||||||
// Error does not occur with this code
|
// Error does not occur with this code
|
||||||
return false;
|
return false;
|
||||||
|
@ -102,7 +103,8 @@ bool CppCheck::findError(std::string code, const char FileName[])
|
||||||
// is still there.
|
// is still there.
|
||||||
code = previousCode.substr(found+9);
|
code = previousCode.substr(found+9);
|
||||||
_errorList.clear();
|
_errorList.clear();
|
||||||
checkFile(code, FileName);
|
checksums.clear();
|
||||||
|
checkFile(code, FileName, checksums);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_errorList.empty()) {
|
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;
|
unsigned int checkCount = 0;
|
||||||
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
|
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
|
// 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;
|
return exitcode;
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
} 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
|
// CppCheck - A function that checks a specified file
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
bool CppCheck::checkFile(const std::string &code, const char FileName[], std::set<unsigned long long>& checksums)
|
||||||
void CppCheck::checkFile(const std::string &code, const char FileName[])
|
|
||||||
{
|
{
|
||||||
if (_settings.terminated() || _settings.checkConfiguration)
|
if (_settings.terminated() || _settings.checkConfiguration)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
Tokenizer _tokenizer(&_settings, this);
|
Tokenizer _tokenizer(&_settings, this);
|
||||||
if (_settings._showtime != SHOWTIME_NONE)
|
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);
|
Timer timer("Tokenizer::tokenize", _settings._showtime, &S_timerResults);
|
||||||
result = _tokenizer.tokenize(istr, FileName, cfg);
|
result = _tokenizer.tokenize(istr, FileName, cfg);
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
|
|
||||||
|
unsigned long long checksum = _tokenizer.list.calculateChecksum();
|
||||||
|
if (checksums.find(checksum) != checksums.end())
|
||||||
|
return false;
|
||||||
|
checksums.insert(checksum);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// File had syntax errors, abort
|
// File had syntax errors, abort
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump
|
// dump
|
||||||
|
@ -369,13 +380,13 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||||
_tokenizer.dump(fdump);
|
_tokenizer.dump(fdump);
|
||||||
fdump << "</dump>" << std::endl;
|
fdump << "</dump>" << std::endl;
|
||||||
}
|
}
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call all "runChecks" in all registered Check classes
|
// call all "runChecks" in all registered Check classes
|
||||||
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
||||||
if (_settings.terminated())
|
if (_settings.terminated())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
Timer timerRunChecks((*it)->name() + "::runChecks", _settings._showtime, &S_timerResults);
|
Timer timerRunChecks((*it)->name() + "::runChecks", _settings._showtime, &S_timerResults);
|
||||||
(*it)->runChecks(&_tokenizer, &_settings, this);
|
(*it)->runChecks(&_tokenizer, &_settings, this);
|
||||||
|
@ -387,30 +398,30 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||||
executeRules("normal", _tokenizer);
|
executeRules("normal", _tokenizer);
|
||||||
|
|
||||||
if (!_simplify)
|
if (!_simplify)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
Timer timer3("Tokenizer::simplifyTokenList2", _settings._showtime, &S_timerResults);
|
Timer timer3("Tokenizer::simplifyTokenList2", _settings._showtime, &S_timerResults);
|
||||||
result = _tokenizer.simplifyTokenList2();
|
result = _tokenizer.simplifyTokenList2();
|
||||||
timer3.Stop();
|
timer3.Stop();
|
||||||
if (!result)
|
if (!result)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
// call all "runSimplifiedChecks" in all registered Check classes
|
// call all "runSimplifiedChecks" in all registered Check classes
|
||||||
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
||||||
if (_settings.terminated())
|
if (_settings.terminated())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", _settings._showtime, &S_timerResults);
|
Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", _settings._showtime, &S_timerResults);
|
||||||
(*it)->runSimplifiedChecks(&_tokenizer, &_settings, this);
|
(*it)->runSimplifiedChecks(&_tokenizer, &_settings, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings.terminated())
|
if (_settings.terminated())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
executeRules("simple", _tokenizer);
|
executeRules("simple", _tokenizer);
|
||||||
|
|
||||||
if (_settings.terminated())
|
if (_settings.terminated())
|
||||||
return;
|
return true;
|
||||||
} catch (const InternalError &e) {
|
} catch (const InternalError &e) {
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||||
ErrorLogger::ErrorMessage::FileLocation loc;
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
||||||
|
@ -433,6 +444,7 @@ void CppCheck::checkFile(const std::string &code, const char FileName[])
|
||||||
|
|
||||||
_errorLogger.reportErr(errmsg);
|
_errorLogger.reportErr(errmsg);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer)
|
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);
|
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)
|
void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg)
|
||||||
|
|
|
@ -128,6 +128,7 @@ public:
|
||||||
void analyseFile(std::istream &f, const std::string &filename);
|
void analyseFile(std::istream &f, const std::string &filename);
|
||||||
|
|
||||||
void tooManyConfigsError(const std::string &file, const std::size_t numberOfConfigurations);
|
void tooManyConfigsError(const std::string &file, const std::size_t numberOfConfigurations);
|
||||||
|
void purgedConfigurationMessage(const std::string &file, const std::string& configuration);
|
||||||
|
|
||||||
void dontSimplify() {
|
void dontSimplify() {
|
||||||
_simplify = false;
|
_simplify = false;
|
||||||
|
@ -147,7 +148,7 @@ private:
|
||||||
unsigned int processFile(const std::string& filename, const std::string& fileContent);
|
unsigned int processFile(const std::string& filename, const std::string& fileContent);
|
||||||
|
|
||||||
/** @brief Check file */
|
/** @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
|
* @brief Execute rules, if any
|
||||||
|
|
|
@ -394,6 +394,27 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0)
|
||||||
return true;
|
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 {
|
struct AST_state {
|
||||||
|
|
|
@ -120,6 +120,12 @@ public:
|
||||||
*/
|
*/
|
||||||
std::string fileLine(const Token *tok) const;
|
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();
|
void createAst();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue