Added some multipass checking for the uninitialized variables. It is still experimental. You can activate it with the '--test-2-pass' switch. Some more refactorings are needed to make it truly usable, the main thing is to make it thread safe.
This commit is contained in:
parent
4633979ff7
commit
75c9355e9a
14
lib/check.h
14
lib/check.h
|
@ -64,6 +64,20 @@ public:
|
|||
return _instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* analyse code - must be thread safe
|
||||
* @param tokens The tokens to analyse
|
||||
* @param result container where results are stored
|
||||
*/
|
||||
virtual void analyse(const Token * /*tokens*/, std::set<std::string> & /*result*/) const
|
||||
{
|
||||
}
|
||||
|
||||
/** Save analysis data - the caller ensures thread safety */
|
||||
virtual void saveAnalysisData(const std::set<std::string> & /*data*/) const
|
||||
{
|
||||
}
|
||||
|
||||
/** run checks, the token list is not simplified */
|
||||
virtual void runChecks(const Tokenizer *, const Settings *, ErrorLogger *)
|
||||
{ }
|
||||
|
|
|
@ -3208,7 +3208,7 @@ public:
|
|||
/** Functions that don't handle uninitialized variables well */
|
||||
static std::set<std::string> uvarFunctions;
|
||||
|
||||
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func, bool showAll)
|
||||
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func)
|
||||
{
|
||||
for (const Token *tok = tokens; tok; tok = tok->next())
|
||||
{
|
||||
|
@ -3262,18 +3262,6 @@ public:
|
|||
r = true;
|
||||
}
|
||||
|
||||
// --all
|
||||
else if (showAll)
|
||||
{
|
||||
if (!Token::simpleMatch(tok3->next(), "="))
|
||||
r = true;
|
||||
else
|
||||
{
|
||||
w = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
w = true;
|
||||
|
@ -3315,12 +3303,15 @@ std::set<std::string> CheckUninitVar::uvarFunctions;
|
|||
/// @}
|
||||
|
||||
|
||||
void CheckOther::analyseFunctions(const Token * const tokens, std::set<std::string> &func, bool showAll)
|
||||
void CheckOther::analyse(const Token * const tokens, std::set<std::string> &func) const
|
||||
{
|
||||
CheckUninitVar::analyseFunctions(tokens, func, showAll);
|
||||
CheckUninitVar::analyseFunctions(tokens, func);
|
||||
}
|
||||
|
||||
|
||||
void CheckOther::saveAnalysisData(const std::set<std::string> &data) const
|
||||
{
|
||||
CheckUninitVar::uvarFunctions.insert(data.begin(), data.end());
|
||||
}
|
||||
|
||||
void CheckOther::executionPaths()
|
||||
{
|
||||
|
@ -3334,7 +3325,7 @@ void CheckOther::executionPaths()
|
|||
{
|
||||
// no writing if multiple threads are used (TODO: thread safe analysis?)
|
||||
if (_settings->_jobs == 1)
|
||||
CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions, _settings->inconclusive);
|
||||
CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions);
|
||||
|
||||
CheckUninitVar c(this);
|
||||
checkExecutionPaths(_tokenizer->tokens(), &c);
|
||||
|
|
|
@ -91,7 +91,10 @@ public:
|
|||
* @param func [out] names of functions that don't handle uninitialized variables well. the function names are added to the set. No clearing is made.
|
||||
* @param showAll [in] enable --all checking
|
||||
*/
|
||||
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func, bool showAll);
|
||||
void analyse(const Token * const tokens, std::set<std::string> &func) const;
|
||||
|
||||
/** Save analysis results */
|
||||
void saveAnalysisData(const std::set<std::string> &data) const;
|
||||
|
||||
/** @brief Are there C-style pointer casts in a c++ file? */
|
||||
void warningOldStylePointerCast();
|
||||
|
|
|
@ -503,6 +503,13 @@ bool CppCheck::parseFromArgs(int argc, const char* const argv[])
|
|||
return true;
|
||||
}
|
||||
|
||||
// --test-2-pass Experimental 2-pass checking of files
|
||||
// This command line flag will be removed
|
||||
else if (strcmp(argv[i], "--test-2-pass") == 0)
|
||||
{
|
||||
_settings.test_2_pass = true;
|
||||
}
|
||||
|
||||
else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "--", 2) == 0)
|
||||
{
|
||||
reportOut("cppcheck: error: unrecognized command line option \"" + std::string(argv[i]) + "\"");
|
||||
|
@ -518,6 +525,12 @@ bool CppCheck::parseFromArgs(int argc, const char* const argv[])
|
|||
reportOut("unusedFunctions check can't be used with -j option, so it was disabled.");
|
||||
}
|
||||
|
||||
// FIXME: Make the _settings.test_2_pass thread safe
|
||||
if (_settings.test_2_pass && _settings._jobs > 1)
|
||||
{
|
||||
reportOut("--test-2-pass doesn't work with -j option yet.");
|
||||
}
|
||||
|
||||
if (!pathnames.empty())
|
||||
{
|
||||
// Execute recursiveAddFiles() to each given file parameter
|
||||
|
@ -613,6 +626,50 @@ unsigned int CppCheck::check()
|
|||
|
||||
_checkUnusedFunctions.setErrorLogger(this);
|
||||
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;
|
||||
|
||||
reportOut("Analysing " + fname + "..");
|
||||
|
||||
// Preprocess file..
|
||||
Preprocessor preprocessor(&_settings, this);
|
||||
std::list<std::string> configurations;
|
||||
std::string filedata = "";
|
||||
std::ifstream fin(fname.c_str());
|
||||
preprocessor.preprocess(fin, filedata, configurations, fname, _settings._includePaths);
|
||||
const std::string code = Preprocessor::getcode(filedata, "", fname, &_errorLogger);
|
||||
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&_settings, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, fname.c_str(), "");
|
||||
tokenizer.simplifyTokenList();
|
||||
|
||||
// Analyse the tokens..
|
||||
std::set<std::string> data;
|
||||
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it)
|
||||
{
|
||||
(*it)->analyse(tokenizer.tokens(), data);
|
||||
}
|
||||
|
||||
// Save analysis results..
|
||||
// TODO: This loop should be protected by a mutex or something like that
|
||||
// The saveAnalysisData must _not_ be called from many threads at the same time.
|
||||
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it)
|
||||
{
|
||||
(*it)->saveAnalysisData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; c < _filenames.size(); c++)
|
||||
{
|
||||
_errout.str("");
|
||||
|
|
|
@ -38,6 +38,7 @@ Settings::Settings()
|
|||
_append = "";
|
||||
_terminate = false;
|
||||
inconclusive = false;
|
||||
test_2_pass = false;
|
||||
}
|
||||
|
||||
bool Settings::Suppressions::parseFile(std::istream &istr)
|
||||
|
|
|
@ -166,6 +166,9 @@ public:
|
|||
|
||||
/** @brief defines given by the user */
|
||||
std::string userDefines;
|
||||
|
||||
/** @brief Experimentat 2 pass checking of files */
|
||||
bool test_2_pass;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -1940,7 +1940,8 @@ private:
|
|||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
std::set<std::string> f;
|
||||
CheckOther::analyseFunctions(tokenizer.tokens(), f, true);
|
||||
const CheckOther checkOther((const Tokenizer *)0, (const Settings *)0, (ErrorLogger *)0);
|
||||
checkOther.analyse(tokenizer.tokens(), f);
|
||||
|
||||
std::string ret;
|
||||
for (std::set<std::string>::const_iterator it = f.begin(); it != f.end(); ++it)
|
||||
|
|
Loading…
Reference in New Issue