UnusedFunctions: Perform checking using analyzeinfo
This commit is contained in:
parent
da956a5278
commit
350e5a7142
|
@ -854,6 +854,8 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
|
|||
returnValue = executor.check();
|
||||
}
|
||||
|
||||
cppcheck.analyseWholeProgram(_settings->buildDir, _files);
|
||||
|
||||
if (settings.isEnabled("information") || settings.checkConfiguration) {
|
||||
const bool enableUnusedFunctionCheck = cppcheck.isUnusedFunctionCheckEnabled();
|
||||
|
||||
|
|
|
@ -58,21 +58,27 @@ static bool skipAnalysis(const std::string &analyzerInfoFile, unsigned long long
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile)
|
||||
{
|
||||
std::string filename = Path::fromNativeSeparators(buildDir);
|
||||
if (filename.back() != '/')
|
||||
filename += '/';
|
||||
const std::string::size_type pos = sourcefile.rfind("/");
|
||||
if (pos == std::string::npos)
|
||||
filename += sourcefile;
|
||||
else
|
||||
filename += sourcefile.substr(pos+1);
|
||||
filename += ".analyzerinfo";
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, unsigned long long checksum, std::list<ErrorLogger::ErrorMessage> *errors)
|
||||
{
|
||||
if (buildDir.empty() || sourcefile.empty())
|
||||
return true;
|
||||
close();
|
||||
|
||||
analyzerInfoFile = Path::fromNativeSeparators(buildDir);
|
||||
if (analyzerInfoFile.back() != '/')
|
||||
analyzerInfoFile += '/';
|
||||
const std::string::size_type pos = sourcefile.rfind("/");
|
||||
if (pos == std::string::npos)
|
||||
analyzerInfoFile += sourcefile;
|
||||
else
|
||||
analyzerInfoFile += sourcefile.substr(pos+1);
|
||||
analyzerInfoFile += ".analyzerinfo";
|
||||
analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile);
|
||||
|
||||
const std::string start = "<analyzerinfo checksum=\"" + std::to_string(checksum) + "\">";
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, unsigned long long checksum, std::list<ErrorLogger::ErrorMessage> *errors);
|
||||
void reportErr(const ErrorLogger::ErrorMessage &msg, bool verbose);
|
||||
void setFileInfo(const std::string &check, const std::string &fileInfo);
|
||||
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile);
|
||||
private:
|
||||
std::ofstream fout;
|
||||
std::string analyzerInfoFile;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "tokenize.h"
|
||||
#include "token.h"
|
||||
#include "symboldatabase.h"
|
||||
#include "analyzerinfo.h"
|
||||
#include <cctype>
|
||||
#include <tinyxml2.h>
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -303,25 +304,56 @@ std::string CheckUnusedFunctions::analyzerInfo() const
|
|||
return ret.str();
|
||||
}
|
||||
|
||||
|
||||
void CheckUnusedFunctions::clear()
|
||||
{
|
||||
instance._functions.clear();
|
||||
namespace {
|
||||
struct Location {
|
||||
Location() : fileName(""), lineNumber(0) {}
|
||||
Location(std::string f, int l) : fileName(f), lineNumber(l) {}
|
||||
std::string fileName;
|
||||
int lineNumber;
|
||||
};
|
||||
}
|
||||
|
||||
void CheckUnusedFunctions::loadInfo(const tinyxml2::XMLElement *info, const std::string &filename)
|
||||
void CheckUnusedFunctions::analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir, const std::map<std::string, std::size_t> &files)
|
||||
{
|
||||
for (const tinyxml2::XMLElement *e = info->FirstChildElement(); e; e = e->NextSiblingElement()) {
|
||||
if (std::strcmp(e->Name(), "functiondecl")==0) {
|
||||
FunctionUsage &func = _functions[e->Attribute("functionName")];
|
||||
func.filename = filename;
|
||||
func.lineNumber = std::atoi(e->Attribute("lineNumber"));
|
||||
} else if (std::strcmp(e->Name(), "functioncall")==0) {
|
||||
FunctionUsage &func = _functions[e->Attribute("functionName")];
|
||||
if (func.filename == filename)
|
||||
func.usedSameFile = true;
|
||||
else
|
||||
func.usedOtherFile = true;
|
||||
std::map<std::string, Location> decls;
|
||||
std::set<std::string> calls;
|
||||
|
||||
for (std::map<std::string, std::size_t>::const_iterator it = files.begin(); it != files.end(); ++it) {
|
||||
const std::string &sourcefile = it->first;
|
||||
const std::string xmlfile = AnalyzerInformation::getAnalyzerInfoFile(buildDir, sourcefile);
|
||||
|
||||
tinyxml2::XMLDocument doc;
|
||||
tinyxml2::XMLError error = doc.LoadFile(xmlfile.c_str());
|
||||
if (error != tinyxml2::XML_SUCCESS)
|
||||
continue;
|
||||
|
||||
const tinyxml2::XMLElement * const rootNode = doc.FirstChildElement();
|
||||
if (rootNode == nullptr)
|
||||
continue;
|
||||
|
||||
for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
|
||||
if (std::strcmp(e->Name(), "FileInfo") == 0) {
|
||||
const char *checkattr = e->Attribute("check");
|
||||
if (checkattr && std::strcmp(checkattr,"CheckUnusedFunctions")==0) {
|
||||
for (const tinyxml2::XMLElement *e2 = e->FirstChildElement(); e2; e2 = e2->NextSiblingElement()) {
|
||||
if (!e2->Attribute("functionName"))
|
||||
continue;
|
||||
if (std::strcmp(e2->Name(),"functiondecl")==0 && e2->Attribute("lineNumber")) {
|
||||
decls[e2->Attribute("functionName")] = Location(sourcefile, std::atoi(e2->Attribute("lineNumber")));
|
||||
} else if (std::strcmp(e2->Name(),"functioncall")==0) {
|
||||
calls.insert(e2->Attribute("functionName"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, Location>::const_iterator decl = decls.begin(); decl != decls.end(); ++decl) {
|
||||
const std::string &functionName = decl->first;
|
||||
if (calls.find(functionName) == calls.end()) {
|
||||
const Location &loc = decl->second;
|
||||
unusedFunctionError(errorLogger, loc.fileName, loc.lineNumber, functionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,8 +62,7 @@ public:
|
|||
std::string analyzerInfo() const;
|
||||
|
||||
/** @brief Combine and analyze all analyzerInfos for all TUs */
|
||||
void clear();
|
||||
void loadInfo(const tinyxml2::XMLElement *info, const std::string &filename);
|
||||
void analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir, const std::map<std::string, std::size_t> &files);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -729,6 +729,14 @@ void CppCheck::analyseWholeProgram()
|
|||
(*it)->analyseWholeProgram(fileInfo, _settings, *this);
|
||||
}
|
||||
|
||||
void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::map<std::string, std::size_t> &files)
|
||||
{
|
||||
if (buildDir.empty())
|
||||
return;
|
||||
if (_settings.isEnabled("unusedFunctions"))
|
||||
CheckUnusedFunctions::instance.analyseWholeProgram(this, buildDir, files);
|
||||
}
|
||||
|
||||
bool CppCheck::isUnusedFunctionCheckEnabled() const
|
||||
{
|
||||
return ((_settings.jobs == 1 || !_settings.buildDir.empty()) && _settings.isEnabled("unusedFunction"));
|
||||
|
|
|
@ -126,9 +126,15 @@ public:
|
|||
_simplify = false;
|
||||
}
|
||||
|
||||
/** analyse whole program, run this after all TUs has been scanned. */
|
||||
/** Analyse whole program, run this after all TUs has been scanned.
|
||||
* This is deprecated and the plan is to remove this when
|
||||
* .analyzeinfo is good enough
|
||||
*/
|
||||
void analyseWholeProgram();
|
||||
|
||||
/** analyse whole program use .analyzeinfo files */
|
||||
void analyseWholeProgram(const std::string &buildDir, const std::map<std::string, std::size_t> &files);
|
||||
|
||||
/** Check if the user wants to check for unused functions
|
||||
* and if it's possible at all */
|
||||
bool isUnusedFunctionCheckEnabled() const;
|
||||
|
|
Loading…
Reference in New Issue