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();
|
returnValue = executor.check();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cppcheck.analyseWholeProgram(_settings->buildDir, _files);
|
||||||
|
|
||||||
if (settings.isEnabled("information") || settings.checkConfiguration) {
|
if (settings.isEnabled("information") || settings.checkConfiguration) {
|
||||||
const bool enableUnusedFunctionCheck = cppcheck.isUnusedFunctionCheckEnabled();
|
const bool enableUnusedFunctionCheck = cppcheck.isUnusedFunctionCheckEnabled();
|
||||||
|
|
||||||
|
|
|
@ -58,21 +58,27 @@ static bool skipAnalysis(const std::string &analyzerInfoFile, unsigned long long
|
||||||
return true;
|
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)
|
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())
|
if (buildDir.empty() || sourcefile.empty())
|
||||||
return true;
|
return true;
|
||||||
close();
|
close();
|
||||||
|
|
||||||
analyzerInfoFile = Path::fromNativeSeparators(buildDir);
|
analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile);
|
||||||
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";
|
|
||||||
|
|
||||||
const std::string start = "<analyzerinfo checksum=\"" + std::to_string(checksum) + "\">";
|
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);
|
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 reportErr(const ErrorLogger::ErrorMessage &msg, bool verbose);
|
||||||
void setFileInfo(const std::string &check, const std::string &fileInfo);
|
void setFileInfo(const std::string &check, const std::string &fileInfo);
|
||||||
|
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile);
|
||||||
private:
|
private:
|
||||||
std::ofstream fout;
|
std::ofstream fout;
|
||||||
std::string analyzerInfoFile;
|
std::string analyzerInfoFile;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "symboldatabase.h"
|
#include "symboldatabase.h"
|
||||||
|
#include "analyzerinfo.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -303,25 +304,56 @@ std::string CheckUnusedFunctions::analyzerInfo() const
|
||||||
return ret.str();
|
return ret.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
void CheckUnusedFunctions::clear()
|
struct Location {
|
||||||
{
|
Location() : fileName(""), lineNumber(0) {}
|
||||||
instance._functions.clear();
|
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()) {
|
std::map<std::string, Location> decls;
|
||||||
if (std::strcmp(e->Name(), "functiondecl")==0) {
|
std::set<std::string> calls;
|
||||||
FunctionUsage &func = _functions[e->Attribute("functionName")];
|
|
||||||
func.filename = filename;
|
for (std::map<std::string, std::size_t>::const_iterator it = files.begin(); it != files.end(); ++it) {
|
||||||
func.lineNumber = std::atoi(e->Attribute("lineNumber"));
|
const std::string &sourcefile = it->first;
|
||||||
} else if (std::strcmp(e->Name(), "functioncall")==0) {
|
const std::string xmlfile = AnalyzerInformation::getAnalyzerInfoFile(buildDir, sourcefile);
|
||||||
FunctionUsage &func = _functions[e->Attribute("functionName")];
|
|
||||||
if (func.filename == filename)
|
tinyxml2::XMLDocument doc;
|
||||||
func.usedSameFile = true;
|
tinyxml2::XMLError error = doc.LoadFile(xmlfile.c_str());
|
||||||
else
|
if (error != tinyxml2::XML_SUCCESS)
|
||||||
func.usedOtherFile = true;
|
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;
|
std::string analyzerInfo() const;
|
||||||
|
|
||||||
/** @brief Combine and analyze all analyzerInfos for all TUs */
|
/** @brief Combine and analyze all analyzerInfos for all TUs */
|
||||||
void clear();
|
void analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir, const std::map<std::string, std::size_t> &files);
|
||||||
void loadInfo(const tinyxml2::XMLElement *info, const std::string &filename);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -729,6 +729,14 @@ void CppCheck::analyseWholeProgram()
|
||||||
(*it)->analyseWholeProgram(fileInfo, _settings, *this);
|
(*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
|
bool CppCheck::isUnusedFunctionCheckEnabled() const
|
||||||
{
|
{
|
||||||
return ((_settings.jobs == 1 || !_settings.buildDir.empty()) && _settings.isEnabled("unusedFunction"));
|
return ((_settings.jobs == 1 || !_settings.buildDir.empty()) && _settings.isEnabled("unusedFunction"));
|
||||||
|
|
|
@ -126,9 +126,15 @@ public:
|
||||||
_simplify = false;
|
_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();
|
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
|
/** Check if the user wants to check for unused functions
|
||||||
* and if it's possible at all */
|
* and if it's possible at all */
|
||||||
bool isUnusedFunctionCheckEnabled() const;
|
bool isUnusedFunctionCheckEnabled() const;
|
||||||
|
|
Loading…
Reference in New Issue