Reverted refactoring 828417c for now. It caused a major slowdown in the unused functions checking.

This commit is contained in:
Daniel Marjamäki 2014-11-24 06:37:08 +01:00
parent 298021af1f
commit a002654c47
11 changed files with 71 additions and 84 deletions

View File

@ -791,6 +791,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
} }
} }
cppcheck.checkFunctionUsage();
cppcheck.analyseWholeProgram(); cppcheck.analyseWholeProgram();
} else if (!ThreadExecutor::isEnabled()) { } else if (!ThreadExecutor::isEnabled()) {
std::cout << "No thread support yet implemented for this platform." << std::endl; std::cout << "No thread support yet implemented for this platform." << std::endl;

View File

@ -94,9 +94,8 @@ public:
virtual ~FileInfo() {} virtual ~FileInfo() {}
}; };
virtual FileInfo * getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const { virtual FileInfo * getFileInfo(const Tokenizer *tokenizer) const {
(void)tokenizer; (void)tokenizer;
(void)settings;
return nullptr; return nullptr;
} }

View File

@ -1805,10 +1805,8 @@ void CheckBufferOverrun::writeOutsideBufferSizeError(const Token *tok, const std
" Please check the second and the third parameter of the function '"+strFunctionName+"'."); " Please check the second and the third parameter of the function '"+strFunctionName+"'.");
} }
Check::FileInfo* CheckBufferOverrun::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const Check::FileInfo* CheckBufferOverrun::getFileInfo(const Tokenizer *tokenizer) const
{ {
(void)settings;
MyFileInfo *fileInfo = new MyFileInfo; MyFileInfo *fileInfo = new MyFileInfo;
// Array usage.. // Array usage..

View File

@ -220,7 +220,7 @@ public:
}; };
/** @brief Parse current TU and extract file info */ /** @brief Parse current TU and extract file info */
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const; Check::FileInfo *getFileInfo(const Tokenizer *tokenizer) const;
/** @brief Analyse all file infos for all TU */ /** @brief Analyse all file infos for all TU */
virtual void analyseWholeProgram(const std::list<Check::FileInfo*> &fileInfo, ErrorLogger &errorLogger); virtual void analyseWholeProgram(const std::list<Check::FileInfo*> &fileInfo, ErrorLogger &errorLogger);

View File

@ -1013,9 +1013,8 @@ public:
/// @} /// @}
Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer) const
{ {
(void)settings;
MyFileInfo * mfi = new MyFileInfo; MyFileInfo * mfi = new MyFileInfo;
analyseFunctions(tokenizer, mfi->uvarFunctions); analyseFunctions(tokenizer, mfi->uvarFunctions);
// TODO: add suspicious function calls // TODO: add suspicious function calls

View File

@ -80,7 +80,7 @@ public:
}; };
/** @brief Parse current TU and extract file info */ /** @brief Parse current TU and extract file info */
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const; Check::FileInfo *getFileInfo(const Tokenizer *tokenizer) const;
/** @brief Analyse all file infos for all TU */ /** @brief Analyse all file infos for all TU */
virtual void analyseWholeProgram(const std::list<Check::FileInfo*> &fileInfo, ErrorLogger &errorLogger); virtual void analyseWholeProgram(const std::list<Check::FileInfo*> &fileInfo, ErrorLogger &errorLogger);

View File

@ -25,25 +25,19 @@
#include <cctype> #include <cctype>
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Register this check class // Register this check class
namespace { CheckUnusedFunctions CheckUnusedFunctions::instance;
CheckUnusedFunctions instance;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// FUNCTION USAGE - Check for unused functions etc // FUNCTION USAGE - Check for unused functions etc
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings)
{ {
if (!settings->isEnabled("unusedFunction")) const SymbolDatabase* symbolDatabase = tokenizer.getSymbolDatabase();
return nullptr;
const SymbolDatabase* symbolDatabase = tokenizer->getSymbolDatabase();
MyFileInfo *fileInfo = new MyFileInfo;
const std::string FileName = tokenizer->list.getFiles().front();
// Function declarations.. // Function declarations..
for (std::size_t i = 0; i < symbolDatabase->functionScopes.size(); i++) { for (std::size_t i = 0; i < symbolDatabase->functionScopes.size(); i++) {
@ -60,24 +54,24 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
if (func->retDef->str() == "template") if (func->retDef->str() == "template")
continue; continue;
FunctionUsage &usage = fileInfo->_functions[func->name()]; FunctionUsage &usage = _functions[func->name()];
if (!usage.lineNumber) if (!usage.lineNumber)
usage.lineNumber = func->token->linenr(); usage.lineNumber = func->token->linenr();
// No filename set yet.. // No filename set yet..
if (usage.filename.empty()) { if (usage.filename.empty()) {
usage.filename = tokenizer->list.getSourceFilePath(); usage.filename = tokenizer.list.getSourceFilePath();
} }
// Multiple files => filename = "+" // Multiple files => filename = "+"
else if (usage.filename != tokenizer->list.getSourceFilePath()) { else if (usage.filename != tokenizer.list.getSourceFilePath()) {
//func.filename = "+"; //func.filename = "+";
usage.usedOtherFile |= usage.usedSameFile; usage.usedOtherFile |= usage.usedSameFile;
} }
} }
// Function usage.. // Function usage..
for (const Token *tok = tokenizer->tokens(); tok; tok = tok->next()) { for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
// parsing of library code to find called functions // parsing of library code to find called functions
if (settings->library.isexecutableblock(FileName, tok->str())) { if (settings->library.isexecutableblock(FileName, tok->str())) {
@ -94,11 +88,11 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
} else if (markupVarToken->str() == settings->library.blockend(FileName)) } else if (markupVarToken->str() == settings->library.blockend(FileName))
scope--; scope--;
else if (!settings->library.iskeyword(FileName, markupVarToken->str())) { else if (!settings->library.iskeyword(FileName, markupVarToken->str())) {
if (fileInfo->_functions.find(markupVarToken->str()) != fileInfo->_functions.end()) if (_functions.find(markupVarToken->str()) != _functions.end())
fileInfo->_functions[markupVarToken->str()].usedOtherFile = true; _functions[markupVarToken->str()].usedOtherFile = true;
else if (markupVarToken->next()->str() == "(") { else if (markupVarToken->next()->str() == "(") {
FunctionUsage &func = fileInfo->_functions[markupVarToken->str()]; FunctionUsage &func = _functions[markupVarToken->str()];
func.filename = tokenizer->list.getSourceFilePath(); func.filename = tokenizer.list.getSourceFilePath();
if (func.filename.empty() || func.filename == "+") if (func.filename.empty() || func.filename == "+")
func.usedOtherFile = true; func.usedOtherFile = true;
else else
@ -116,15 +110,15 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
if (settings->library.isexportedprefix(tok->str(), propToken->str())) { if (settings->library.isexportedprefix(tok->str(), propToken->str())) {
const Token* nextPropToken = propToken->next(); const Token* nextPropToken = propToken->next();
const std::string& value = nextPropToken->str(); const std::string& value = nextPropToken->str();
if (fileInfo->_functions.find(value) != fileInfo->_functions.end()) { if (_functions.find(value) != _functions.end()) {
fileInfo->_functions[value].usedOtherFile = true; _functions[value].usedOtherFile = true;
} }
} }
if (settings->library.isexportedsuffix(tok->str(), propToken->str())) { if (settings->library.isexportedsuffix(tok->str(), propToken->str())) {
const Token* prevPropToken = propToken->previous(); const Token* prevPropToken = propToken->previous();
const std::string& value = prevPropToken->str(); const std::string& value = prevPropToken->str();
if (value != ")" && fileInfo->_functions.find(value) != fileInfo->_functions.end()) { if (value != ")" && _functions.find(value) != _functions.end()) {
fileInfo->_functions[value].usedOtherFile = true; _functions[value].usedOtherFile = true;
} }
} }
propToken = propToken->next(); propToken = propToken->next();
@ -139,7 +133,7 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
while (propToken && propToken->str() != ")") { while (propToken && propToken->str() != ")") {
const std::string& value = propToken->str(); const std::string& value = propToken->str();
if (!value.empty()) { if (!value.empty()) {
fileInfo->_functions[value].usedOtherFile = true; _functions[value].usedOtherFile = true;
break; break;
} }
propToken = propToken->next(); propToken = propToken->next();
@ -164,7 +158,7 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
} }
if (index == argIndex) { if (index == argIndex) {
value = value.substr(1, value.length() - 2); value = value.substr(1, value.length() - 2);
fileInfo->_functions[value].usedOtherFile = true; _functions[value].usedOtherFile = true;
} }
} }
} }
@ -208,7 +202,7 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
} }
if (funcname) { if (funcname) {
FunctionUsage &func = fileInfo->_functions[ funcname->str()]; FunctionUsage &func = _functions[ funcname->str()];
if (func.filename.empty() || func.filename == "+") if (func.filename.empty() || func.filename == "+")
func.usedOtherFile = true; func.usedOtherFile = true;
@ -216,33 +210,13 @@ Check::FileInfo *CheckUnusedFunctions::getFileInfo(const Tokenizer *tokenizer, c
func.usedSameFile = true; func.usedSameFile = true;
} }
} }
return fileInfo;
} }
void CheckUnusedFunctions::analyseWholeProgram(const std::list<Check::FileInfo*> &fileInfo, ErrorLogger &errorLogger)
{
std::map<std::string, FunctionUsage> _functions;
for (std::list<Check::FileInfo*>::const_iterator it = fileInfo.begin(); it != fileInfo.end(); ++it) {
const MyFileInfo *f = dynamic_cast<MyFileInfo*>(*it);
if (f) {
for (std::map<std::string, FunctionUsage>::const_iterator it2 = f->_functions.begin(); it2 != f->_functions.end(); ++it2) {
std::map<std::string, FunctionUsage>::iterator it3 = _functions.find(it2->first);
if (it3 == _functions.end())
_functions[it2->first] = it2->second;
else {
if (it3->second.filename.empty()) {
it3->second.filename = it2->second.filename;
it3->second.lineNumber = it2->second.lineNumber;
}
it3->second.usedOtherFile |= it2->second.usedOtherFile;
}
}
}
}
void CheckUnusedFunctions::check(ErrorLogger * const errorLogger)
{
for (std::map<std::string, FunctionUsage>::const_iterator it = _functions.begin(); it != _functions.end(); ++it) { for (std::map<std::string, FunctionUsage>::const_iterator it = _functions.begin(); it != _functions.end(); ++it) {
const FunctionUsage &func = it->second; const FunctionUsage &func = it->second;
if (func.usedOtherFile || func.filename.empty()) if (func.usedOtherFile || func.filename.empty())
@ -259,7 +233,7 @@ void CheckUnusedFunctions::analyseWholeProgram(const std::list<Check::FileInfo*>
filename = ""; filename = "";
else else
filename = func.filename; filename = func.filename;
CheckUnusedFunctions::unusedFunctionError(&errorLogger, filename, func.lineNumber, it->first); unusedFunctionError(errorLogger, filename, func.lineNumber, it->first);
} else if (! func.usedOtherFile) { } else if (! func.usedOtherFile) {
/** @todo add error message "function is only used in <file> it can be static" */ /** @todo add error message "function is only used in <file> it can be static" */
/* /*

View File

@ -43,12 +43,11 @@ public:
// Parse current tokens and determine.. // Parse current tokens and determine..
// * Check what functions are used // * Check what functions are used
// * What functions are declared // * What functions are declared
void parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings);
/** @brief Parse current TU and extract file info */ void check(ErrorLogger * const errorLogger);
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const;
/** @brief Analyse all file infos for all TU */ static CheckUnusedFunctions instance;
virtual void analyseWholeProgram(const std::list<Check::FileInfo*> &fileInfo, ErrorLogger &errorLogger);
private: private:
@ -67,7 +66,9 @@ private:
/** /**
* Dummy implementation, just to provide error for --errorlist * Dummy implementation, just to provide error for --errorlist
*/ */
void runSimplifiedChecks(const Tokenizer *, const Settings *, ErrorLogger *) {} void runSimplifiedChecks(const Tokenizer *, const Settings *, ErrorLogger *) {
}
static std::string myName() { static std::string myName() {
return "Unused functions"; return "Unused functions";
@ -77,7 +78,7 @@ private:
return "Check for functions that are never called\n"; return "Check for functions that are never called\n";
} }
class FunctionUsage { class CPPCHECKLIB FunctionUsage {
public: public:
FunctionUsage() : lineNumber(0), usedSameFile(false), usedOtherFile(false) { FunctionUsage() : lineNumber(0), usedSameFile(false), usedOtherFile(false) {
} }
@ -88,10 +89,7 @@ private:
bool usedOtherFile; bool usedOtherFile;
}; };
class MyFileInfo : public Check::FileInfo { std::map<std::string, FunctionUsage> _functions;
public:
std::map<std::string, FunctionUsage> _functions;
};
}; };
/// @} /// @}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -19,6 +19,7 @@
#include "preprocessor.h" // Preprocessor #include "preprocessor.h" // Preprocessor
#include "tokenize.h" // Tokenizer #include "tokenize.h" // Tokenizer
#include "checkunusedfunctions.h"
#include "check.h" #include "check.h"
#include "path.h" #include "path.h"
@ -277,6 +278,23 @@ void CppCheck::internalError(const std::string &filename, const std::string &msg
} }
} }
void CppCheck::checkFunctionUsage()
{
// This generates false positives - especially for libraries
if (_settings.isEnabled("unusedFunction") && _settings._jobs == 1) {
const bool verbose_orig = _settings._verbose;
_settings._verbose = false;
if (_settings._errorsOnly == false)
_errorLogger.reportOut("Checking usage of global functions..");
CheckUnusedFunctions::instance.check(this);
_settings._verbose = verbose_orig;
}
}
void CppCheck::analyseFile(std::istream &fin, const std::string &filename) void CppCheck::analyseFile(std::istream &fin, const std::string &filename)
{ {
// Preprocess file.. // Preprocess file..
@ -361,6 +379,9 @@ bool CppCheck::checkFile(const std::string &code, const char FileName[], std::se
(*it)->runChecks(&_tokenizer, &_settings, this); (*it)->runChecks(&_tokenizer, &_settings, this);
} }
if (_settings.isEnabled("unusedFunction") && _settings._jobs == 1)
CheckUnusedFunctions::instance.parseTokens(_tokenizer, FileName, &_settings);
executeRules("normal", _tokenizer); executeRules("normal", _tokenizer);
if (!_simplify) if (!_simplify)
@ -383,7 +404,7 @@ bool CppCheck::checkFile(const std::string &code, const char FileName[], std::se
// Analyse the tokens.. // Analyse the tokens..
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) {
Check::FileInfo *fi = (*it)->getFileInfo(&_tokenizer, &_settings); Check::FileInfo *fi = (*it)->getFileInfo(&_tokenizer);
if (fi != nullptr) if (fi != nullptr)
fileInfo.push_back(fi); fileInfo.push_back(fi);
} }

View File

@ -82,6 +82,12 @@ public:
*/ */
unsigned int check(const std::string &path, const std::string &content); unsigned int check(const std::string &path, const std::string &content);
/**
* @brief Check function usage.
* @note Call this after all files has been checked
*/
void checkFunctionUsage();
/** /**
* @brief Get reference to current settings. * @brief Get reference to current settings.
* @return a reference to current settings * @return a reference to current settings

View File

@ -65,7 +65,7 @@ private:
errout.str(""); errout.str("");
Settings settings; Settings settings;
settings.addEnabled("unusedFunction"); settings.addEnabled("style");
// Tokenize.. // Tokenize..
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
@ -74,10 +74,8 @@ private:
// Check for unused functions.. // Check for unused functions..
CheckUnusedFunctions checkUnusedFunctions(&tokenizer, &settings, this); CheckUnusedFunctions checkUnusedFunctions(&tokenizer, &settings, this);
std::list<Check::FileInfo*> fileInfo; checkUnusedFunctions.parseTokens(tokenizer, "someFile.c", &settings);
fileInfo.push_back(checkUnusedFunctions.getFileInfo(&tokenizer, &settings)); checkUnusedFunctions.check(this);
checkUnusedFunctions.analyseWholeProgram(fileInfo,*this);
delete fileInfo.back();
} }
void incondition() { void incondition() {
@ -328,8 +326,6 @@ private:
const char code[] = "static void f() { }"; const char code[] = "static void f() { }";
std::list<Check::FileInfo*> fileInfo;
for (int i = 1; i <= 2; ++i) { for (int i = 1; i <= 2; ++i) {
std::ostringstream fname; std::ostringstream fname;
fname << "test" << i << ".cpp"; fname << "test" << i << ".cpp";
@ -338,21 +334,16 @@ private:
errout.str(""); errout.str("");
Settings settings; Settings settings;
settings.addEnabled("unusedFunction");
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.tokenize(istr, fname.str().c_str()); tokenizer.tokenize(istr, fname.str().c_str());
fileInfo.push_back(c.getFileInfo(&tokenizer, &settings)); c.parseTokens(tokenizer, "someFile.c", &settings);
} }
// Check for unused functions.. // Check for unused functions..
c.analyseWholeProgram(fileInfo,*this); c.check(this);
while (!fileInfo.empty()) {
delete fileInfo.back();
fileInfo.pop_back();
}
ASSERT_EQUALS("[test1.cpp:1]: (style) The function 'f' is never used.\n", errout.str()); ASSERT_EQUALS("[test1.cpp:1]: (style) The function 'f' is never used.\n", errout.str());
} }