Modify the Cppcheck class to check one file at a time.
Unify usage and API of CppCheck class. Allow only one file checked at a time, instead of list of files. Clients can then handle file lists more naturally and as they see fit. Also clients have better knowledge of how checking status should be handled. The single-threaded CLI checking was only one using the file list. Other clients were giving files (to list) one file at a time.
This commit is contained in:
parent
903769a388
commit
f240574107
|
@ -148,10 +148,7 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
|
|||
// Single process
|
||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||
{
|
||||
cppCheck.addFile(_filenames[c]);
|
||||
returnValue += cppCheck.check();
|
||||
cppCheck.clearFiles();
|
||||
|
||||
returnValue += cppCheck.check(_filenames[c]);
|
||||
reportStatus(c + 1, _filenames.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,19 +177,19 @@ unsigned int ThreadExecutor::check()
|
|||
|
||||
CppCheck fileChecker(*this, false);
|
||||
fileChecker.settings(_settings);
|
||||
unsigned int resultOfCheck = 0;
|
||||
|
||||
if (_fileContents.size() > 0 && _fileContents.find(_filenames[i]) != _fileContents.end())
|
||||
{
|
||||
// File content was given as a string
|
||||
fileChecker.addFile(_filenames[i], _fileContents[ _filenames[i] ]);
|
||||
resultOfCheck = fileChecker.check(_filenames[i], _fileContents[ _filenames[i] ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read file from a file
|
||||
fileChecker.addFile(_filenames[i]);
|
||||
resultOfCheck = fileChecker.check(_filenames[i]);
|
||||
}
|
||||
|
||||
unsigned int resultOfCheck = fileChecker.check();
|
||||
std::ostringstream oss;
|
||||
oss << resultOfCheck;
|
||||
writeToPipe('3', oss.str());
|
||||
|
|
|
@ -50,9 +50,7 @@ void CheckThread::run()
|
|||
while (!file.isEmpty() && mState == Running)
|
||||
{
|
||||
qDebug() << "Checking file" << file;
|
||||
mCppcheck.addFile(file.toStdString());
|
||||
mCppcheck.check();
|
||||
mCppcheck.clearFiles();
|
||||
mCppcheck.check(file.toStdString());
|
||||
emit FileChecked(file);
|
||||
|
||||
if (mState == Running)
|
||||
|
|
250
lib/cppcheck.cpp
250
lib/cppcheck.cpp
|
@ -54,155 +54,138 @@ void CppCheck::settings(const Settings ¤tSettings)
|
|||
_settings = currentSettings;
|
||||
}
|
||||
|
||||
void CppCheck::addFile(const std::string &filepath)
|
||||
{
|
||||
_filenames.push_back(Path::fromNativeSeparators(filepath));
|
||||
}
|
||||
|
||||
void CppCheck::addFile(const std::string &path, const std::string &content)
|
||||
{
|
||||
_filenames.push_back(Path::fromNativeSeparators(path));
|
||||
_fileContents[ path ] = content;
|
||||
}
|
||||
|
||||
void CppCheck::clearFiles()
|
||||
{
|
||||
_filenames.clear();
|
||||
_fileContents.clear();
|
||||
}
|
||||
|
||||
const char * CppCheck::version()
|
||||
{
|
||||
return "1.48";
|
||||
}
|
||||
|
||||
unsigned int CppCheck::check()
|
||||
unsigned int CppCheck::check(const std::string &path)
|
||||
{
|
||||
_filename = path;
|
||||
return processFile();
|
||||
}
|
||||
|
||||
unsigned int CppCheck::check(const std::string &path, const std::string &content)
|
||||
{
|
||||
_filename = path;
|
||||
_fileContent = content;
|
||||
const unsigned int retval = processFile();
|
||||
_fileContent.clear();
|
||||
return retval;
|
||||
}
|
||||
|
||||
unsigned int CppCheck::processFile()
|
||||
{
|
||||
exitcode = 0;
|
||||
|
||||
std::sort(_filenames.begin(), _filenames.end());
|
||||
|
||||
// TODO: Should this be moved out to its own function so all the files can be
|
||||
// analysed before any files are checked?
|
||||
if (_settings.test_2_pass && _settings._jobs == 1)
|
||||
{
|
||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||
{
|
||||
const std::string fname = _filenames[c];
|
||||
if (_settings.terminated())
|
||||
break;
|
||||
const std::string printname = Path::toNativeSeparators(_filename);
|
||||
reportOut("Analysing " + printname + "...");
|
||||
|
||||
std::string fixedname = Path::toNativeSeparators(fname);
|
||||
reportOut("Analysing " + fixedname + "..");
|
||||
|
||||
std::ifstream f(fname.c_str());
|
||||
analyseFile(f, fname);
|
||||
}
|
||||
std::ifstream f(_filename.c_str());
|
||||
analyseFile(f, _filename);
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||
_errout.str("");
|
||||
|
||||
if (_settings.terminated())
|
||||
return exitcode;
|
||||
|
||||
if (_settings._errorsOnly == false)
|
||||
{
|
||||
_errout.str("");
|
||||
const std::string fname = _filenames[c];
|
||||
|
||||
if (_settings.terminated())
|
||||
break;
|
||||
|
||||
if (_settings._errorsOnly == false)
|
||||
{
|
||||
std::string fixedpath(fname);
|
||||
fixedpath = Path::simplifyPath(fixedpath.c_str());
|
||||
fixedpath = Path::toNativeSeparators(fixedpath);
|
||||
_errorLogger.reportOut(std::string("Checking ") + fixedpath + std::string("..."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Preprocessor preprocessor(&_settings, this);
|
||||
std::list<std::string> configurations;
|
||||
std::string filedata = "";
|
||||
|
||||
if ((!_fileContents.empty()) && (_fileContents.find(_filenames[c]) != _fileContents.end()))
|
||||
{
|
||||
// File content was given as a string
|
||||
std::istringstream iss(_fileContents[ _filenames[c] ]);
|
||||
preprocessor.preprocess(iss, filedata, configurations, fname, _settings._includePaths);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only file name was given, read the content from file
|
||||
std::ifstream fin(fname.c_str());
|
||||
Timer t("Preprocessor::preprocess", _settings._showtime, &S_timerResults);
|
||||
preprocessor.preprocess(fin, filedata, configurations, fname, _settings._includePaths);
|
||||
}
|
||||
|
||||
_settings.ifcfg = bool(configurations.size() > 1);
|
||||
|
||||
if (!_settings.userDefines.empty())
|
||||
{
|
||||
configurations.clear();
|
||||
configurations.push_back(_settings.userDefines);
|
||||
}
|
||||
|
||||
int checkCount = 0;
|
||||
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it)
|
||||
{
|
||||
// Check only 12 first configurations, after that bail out, unless --force
|
||||
// was used.
|
||||
if (!_settings._force && checkCount > 11)
|
||||
{
|
||||
const std::string fixedpath = Path::toNativeSeparators(fname);
|
||||
ErrorLogger::ErrorMessage::FileLocation location;
|
||||
location.setfile(fixedpath);
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> loclist;
|
||||
loclist.push_back(location);
|
||||
const std::string msg("Interrupted checking because of too many #ifdef configurations.\n"
|
||||
"The checking of the file was interrupted because there were too many "
|
||||
"#ifdef configurations. Checking of all #ifdef configurations can be forced "
|
||||
"by --force command line option or from GUI preferences. However that may "
|
||||
"increase the checking time.");
|
||||
ErrorLogger::ErrorMessage errmsg(loclist,
|
||||
Severity::information,
|
||||
msg,
|
||||
"toomanyconfigs",
|
||||
false);
|
||||
_errorLogger.reportErr(errmsg);
|
||||
break;
|
||||
}
|
||||
|
||||
cfg = *it;
|
||||
Timer t("Preprocessor::getcode", _settings._showtime, &S_timerResults);
|
||||
const std::string codeWithoutCfg = Preprocessor::getcode(filedata, *it, fname, &_settings, &_errorLogger);
|
||||
t.Stop();
|
||||
|
||||
// If only errors are printed, print filename after the check
|
||||
if (_settings._errorsOnly == false && it != configurations.begin())
|
||||
{
|
||||
std::string fixedpath = Path::simplifyPath(fname.c_str());
|
||||
fixedpath = Path::toNativeSeparators(fixedpath);
|
||||
_errorLogger.reportOut(std::string("Checking ") + fixedpath + ": " + cfg + std::string("..."));
|
||||
}
|
||||
|
||||
std::string appendCode = _settings.append();
|
||||
if (!appendCode.empty())
|
||||
Preprocessor::preprocessWhitespaces(appendCode);
|
||||
|
||||
checkFile(codeWithoutCfg + appendCode, _filenames[c].c_str());
|
||||
++checkCount;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
// Exception was thrown when checking this file..
|
||||
const std::string fixedpath = Path::toNativeSeparators(fname);
|
||||
_errorLogger.reportOut("Bailing out from checking " + fixedpath + ": " + e.what());
|
||||
}
|
||||
|
||||
reportUnmatchedSuppressions(_settings.nomsg.getUnmatchedLocalSuppressions(fname));
|
||||
|
||||
_errorLogger.reportStatus(c + 1, (unsigned int)_filenames.size());
|
||||
std::string fixedpath(_filename);
|
||||
fixedpath = Path::simplifyPath(fixedpath.c_str());
|
||||
fixedpath = Path::toNativeSeparators(fixedpath);
|
||||
_errorLogger.reportOut(std::string("Checking ") + fixedpath + std::string("..."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Preprocessor preprocessor(&_settings, this);
|
||||
std::list<std::string> configurations;
|
||||
std::string filedata = "";
|
||||
|
||||
if (!_fileContent.empty())
|
||||
{
|
||||
// File content was given as a string
|
||||
std::istringstream iss(_fileContent);
|
||||
preprocessor.preprocess(iss, filedata, configurations, _filename, _settings._includePaths);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only file name was given, read the content from file
|
||||
std::ifstream fin(_filename.c_str());
|
||||
Timer t("Preprocessor::preprocess", _settings._showtime, &S_timerResults);
|
||||
preprocessor.preprocess(fin, filedata, configurations, _filename, _settings._includePaths);
|
||||
}
|
||||
|
||||
_settings.ifcfg = bool(configurations.size() > 1);
|
||||
|
||||
if (!_settings.userDefines.empty())
|
||||
{
|
||||
configurations.clear();
|
||||
configurations.push_back(_settings.userDefines);
|
||||
}
|
||||
|
||||
int checkCount = 0;
|
||||
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it)
|
||||
{
|
||||
// Check only 12 first configurations, after that bail out, unless --force
|
||||
// was used.
|
||||
if (!_settings._force && checkCount > 11)
|
||||
{
|
||||
const std::string fixedpath = Path::toNativeSeparators(_filename);
|
||||
ErrorLogger::ErrorMessage::FileLocation location;
|
||||
location.setfile(fixedpath);
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> loclist;
|
||||
loclist.push_back(location);
|
||||
const std::string msg("Interrupted checking because of too many #ifdef configurations.\n"
|
||||
"The checking of the file was interrupted because there were too many "
|
||||
"#ifdef configurations. Checking of all #ifdef configurations can be forced "
|
||||
"by --force command line option or from GUI preferences. However that may "
|
||||
"increase the checking time.");
|
||||
ErrorLogger::ErrorMessage errmsg(loclist,
|
||||
Severity::information,
|
||||
msg,
|
||||
"toomanyconfigs",
|
||||
false);
|
||||
_errorLogger.reportErr(errmsg);
|
||||
break;
|
||||
}
|
||||
|
||||
cfg = *it;
|
||||
Timer t("Preprocessor::getcode", _settings._showtime, &S_timerResults);
|
||||
const std::string codeWithoutCfg = Preprocessor::getcode(filedata, *it, _filename, &_settings, &_errorLogger);
|
||||
t.Stop();
|
||||
|
||||
// If only errors are printed, print filename after the check
|
||||
if (_settings._errorsOnly == false && it != configurations.begin())
|
||||
{
|
||||
std::string fixedpath = Path::simplifyPath(_filename.c_str());
|
||||
fixedpath = Path::toNativeSeparators(fixedpath);
|
||||
_errorLogger.reportOut(std::string("Checking ") + fixedpath + ": " + cfg + std::string("..."));
|
||||
}
|
||||
|
||||
std::string appendCode = _settings.append();
|
||||
if (!appendCode.empty())
|
||||
Preprocessor::preprocessWhitespaces(appendCode);
|
||||
|
||||
checkFile(codeWithoutCfg + appendCode, _filename.c_str());
|
||||
++checkCount;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
// Exception was thrown when checking this file..
|
||||
const std::string fixedpath = Path::toNativeSeparators(_filename);
|
||||
_errorLogger.reportOut("Bailing out from checking " + fixedpath + ": " + e.what());
|
||||
}
|
||||
|
||||
reportUnmatchedSuppressions(_settings.nomsg.getUnmatchedLocalSuppressions(_filename));
|
||||
|
||||
// This generates false positives - especially for libraries
|
||||
const bool verbose_orig = _settings._verbose;
|
||||
_settings._verbose = false;
|
||||
|
@ -445,11 +428,6 @@ void CppCheck::reportOut(const std::string &outmsg)
|
|||
_errorLogger.reportOut(outmsg);
|
||||
}
|
||||
|
||||
const std::vector<std::string> &CppCheck::filenames() const
|
||||
{
|
||||
return _filenames;
|
||||
}
|
||||
|
||||
void CppCheck::reportProgress(const std::string &filename, const char stage[], const unsigned int value)
|
||||
{
|
||||
_errorLogger.reportProgress(filename, stage, value);
|
||||
|
|
|
@ -55,7 +55,29 @@ public:
|
|||
* parseFromArgs() or settings() and addFile() before calling this.
|
||||
* @return amount of errors found or 0 if none were found.
|
||||
*/
|
||||
unsigned int check();
|
||||
|
||||
/**
|
||||
* @brief Check the file.
|
||||
* This function checks one given file for errors.
|
||||
* @param path Path to the file to check.
|
||||
* @return amount of errors found or 0 if none were found.
|
||||
* @note You must set settings before calling this function (by calling
|
||||
* settings()).
|
||||
*/
|
||||
unsigned int check(const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Check the file.
|
||||
* This function checks one "virtual" file. The file is not read from
|
||||
* the disk but the content is given in @p content. In errors the @p path
|
||||
* is used as a filename.
|
||||
* @param path Path to the file to check.
|
||||
* @param content File content as a string.
|
||||
* @return amount of errors found or 0 if none were found.
|
||||
* @note You must set settings before calling this function (by calling
|
||||
* settings()).
|
||||
*/
|
||||
unsigned int check(const std::string &path, const std::string &content);
|
||||
|
||||
/**
|
||||
* @brief Adjust the settings before doing the check. E.g. show only
|
||||
|
@ -71,37 +93,12 @@ public:
|
|||
*/
|
||||
Settings &settings();
|
||||
|
||||
/**
|
||||
* @brief Add new file to be checked.
|
||||
*
|
||||
* @param filepath Relative or absolute path to the file to be checked,
|
||||
* e.g. "cppcheck.cpp". Note that only source files (.c, .cc or .cpp)
|
||||
* should be added to the list. Include files are gathered automatically.
|
||||
*/
|
||||
void addFile(const std::string &filepath);
|
||||
|
||||
/**
|
||||
* @brief Add new unreal file to be checked.
|
||||
*
|
||||
* @param path File name (used for error reporting).
|
||||
* @param content If the file would be a real file, this should be
|
||||
* the content of the file.
|
||||
*/
|
||||
void addFile(const std::string &path, const std::string &content);
|
||||
|
||||
/**
|
||||
* @brief Remove all files added with addFile() and parseFromArgs().
|
||||
*/
|
||||
void clearFiles();
|
||||
|
||||
/**
|
||||
* @brief Returns current version number as a string.
|
||||
* @return version, e.g. "1.38"
|
||||
*/
|
||||
static const char * version();
|
||||
|
||||
const std::vector<std::string> &filenames() const;
|
||||
|
||||
virtual void reportStatus(unsigned int index, unsigned int max);
|
||||
|
||||
/**
|
||||
|
@ -124,6 +121,10 @@ public:
|
|||
void analyseFile(std::istream &f, const std::string &filename);
|
||||
|
||||
private:
|
||||
|
||||
/** @brief Process one file. */
|
||||
unsigned int processFile();
|
||||
|
||||
/** @brief Check file */
|
||||
void checkFile(const std::string &code, const char FileName[]);
|
||||
|
||||
|
@ -148,13 +149,11 @@ private:
|
|||
std::ostringstream _errout;
|
||||
Settings _settings;
|
||||
bool _useGlobalSuppressions;
|
||||
std::vector<std::string> _filenames;
|
||||
std::string _filename;
|
||||
std::string _fileContent;
|
||||
|
||||
void reportProgress(const std::string &filename, const char stage[], const unsigned int value);
|
||||
|
||||
/** @brief Key is file name, and value is the content of the file */
|
||||
std::map<std::string, std::string> _fileContents;
|
||||
|
||||
CheckUnusedFunctions _checkUnusedFunctions;
|
||||
ErrorLogger &_errorLogger;
|
||||
|
||||
|
|
|
@ -55,8 +55,7 @@ private:
|
|||
|
||||
CppCheck cppCheck(*this, true);
|
||||
cppCheck.settings(settings);
|
||||
cppCheck.addFile("test.cpp", code);
|
||||
cppCheck.check();
|
||||
cppCheck.check("test.cpp", code);
|
||||
|
||||
reportUnmatchedSuppressions(cppCheck.settings().nomsg.getUnmatchedGlobalSuppressions());
|
||||
}
|
||||
|
@ -105,8 +104,7 @@ private:
|
|||
CppCheck cppCheck(*this, true);
|
||||
cppCheck.settings(settings);
|
||||
for (int i = 0; names[i] != NULL; ++i)
|
||||
cppCheck.addFile(names[i], codes[i]);
|
||||
cppCheck.check();
|
||||
cppCheck.check(names[i], codes[i]);
|
||||
|
||||
reportUnmatchedSuppressions(cppCheck.settings().nomsg.getUnmatchedGlobalSuppressions());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue