diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index b8742b687..e2c645161 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -17,6 +17,7 @@ */ #include "cppcheckexecutor.h" +#include "analyzerinfo.h" #include "cmdlineparser.h" #include "cppcheck.h" #include "filelister.h" @@ -803,11 +804,10 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha } if (!settings.buildDir.empty()) { - const std::string filename(settings.buildDir + "/files.txt"); - std::ofstream fout(filename.c_str()); - for (std::map::const_iterator f = _files.begin(); f != _files.end(); ++f) { - fout << f->first << '\n'; - } + std::list fileNames; + for (std::map::const_iterator i = _files.begin(); i != _files.end(); ++i) + fileNames.push_back(i->first); + AnalyzerInformation::writeFilesTxt(settings.buildDir, fileNames, settings.project.fileSettings); } unsigned int returnValue = 0; diff --git a/lib/analyzerinfo.cpp b/lib/analyzerinfo.cpp index 8c7027244..483e9a656 100644 --- a/lib/analyzerinfo.cpp +++ b/lib/analyzerinfo.cpp @@ -26,6 +26,39 @@ AnalyzerInformation::~AnalyzerInformation() close(); } +static std::string getFilename(const std::string &fullpath) { + std::string afile(fullpath); + std::string::size_type pos1 = fullpath.find_last_of("/\\"); + pos1 = (pos1 == std::string::npos) ? 0U : (pos1 + 1U); + std::string::size_type pos2 = fullpath.rfind('.'); + if (pos2 < pos1) + pos2 = std::string::npos; + if (pos2 != std::string::npos) + pos2 = pos2 - pos1; + return fullpath.substr(pos1,pos2); +} + +void AnalyzerInformation::writeFilesTxt(const std::string &buildDir, const std::list &sourcefiles, const std::list &fileSettings) +{ + std::map fileCount; + + const std::string filesTxt(buildDir + "/files.txt"); + std::ofstream fout(filesTxt.c_str()); + for (std::list::const_iterator f = sourcefiles.begin(); f != sourcefiles.end(); ++f) { + const std::string afile = getFilename(*f); + if (fileCount.find(afile) == fileCount.end()) + fileCount[afile] = 0; + fout << afile << ".a" << (++fileCount[afile]) << "::" << Path::fromNativeSeparators(*f) << '\n'; + } + + for (std::list::const_iterator fs = fileSettings.begin(); fs != fileSettings.end(); ++fs) { + const std::string afile = getFilename(fs->filename); + if (fileCount.find(afile) == fileCount.end()) + fileCount[afile] = 0; + fout << afile << ".a" << (++fileCount[afile]) << ":" << fs->cfg << ":" << Path::fromNativeSeparators(fs->filename) << std::endl; + } +} + void AnalyzerInformation::close() { analyzerInfoFile.clear(); @@ -58,20 +91,21 @@ 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 AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg) { const std::string files(buildDir + "/files.txt"); std::ifstream fin(files.c_str()); if (fin.is_open()) { - int id = 1; std::string line; + const std::string endsWith(':' + cfg + ':' + sourcefile); while (std::getline(fin,line)) { - if (line == sourcefile) { - std::ostringstream ostr; - ostr << buildDir << '/' << id << ".analyzeinfo"; - return ostr.str(); - } - id++; + if (line.size() <= endsWith.size() + 2U) + continue; + if (line.compare(line.size()-endsWith.size(), endsWith.size(), endsWith) != 0) + continue; + std::ostringstream ostr; + ostr << buildDir << '/' << line.substr(0,line.find(':')); + return ostr.str(); } } @@ -87,13 +121,13 @@ std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir return filename; } -bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, unsigned long long checksum, std::list *errors) +bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, unsigned long long checksum, std::list *errors) { if (buildDir.empty() || sourcefile.empty()) return true; close(); - analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile); + analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg); if (skipAnalysis(analyzerInfoFile, checksum, errors)) return false; diff --git a/lib/analyzerinfo.h b/lib/analyzerinfo.h index d50054c4d..b1f365293 100644 --- a/lib/analyzerinfo.h +++ b/lib/analyzerinfo.h @@ -23,6 +23,8 @@ #include "config.h" #include "errorlogger.h" +#include "importproject.h" +#include #include #include @@ -47,12 +49,14 @@ class CPPCHECKLIB AnalyzerInformation { public: ~AnalyzerInformation(); + static void writeFilesTxt(const std::string &buildDir, const std::list &sourcefiles, const std::list &fileSettings); + /** Close current TU.analyzerinfo file */ void close(); - bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, unsigned long long checksum, std::list *errors); + bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, unsigned long long checksum, std::list *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); + static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg); private: std::ofstream fout; std::string analyzerInfoFile; diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 6ddc26a55..19d0709c7 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -312,14 +312,23 @@ namespace { }; } -void CheckUnusedFunctions::analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir, const std::map &files) +void CheckUnusedFunctions::analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir) { std::map decls; std::set calls; - for (std::map::const_iterator it = files.begin(); it != files.end(); ++it) { - const std::string &sourcefile = it->first; - const std::string xmlfile = AnalyzerInformation::getAnalyzerInfoFile(buildDir, sourcefile); + const std::string filesTxt(buildDir + "/files.txt"); + std::ifstream fin(filesTxt.c_str()); + std::string filesTxtLine; + while (std::getline(fin, filesTxtLine)) { + const std::string::size_type firstColon = filesTxtLine.find(':'); + if (firstColon == std::string::npos) + continue; + const std::string::size_type lastColon = filesTxtLine.rfind(':'); + if (firstColon == lastColon) + continue; + const std::string xmlfile = filesTxtLine.substr(0,firstColon); + const std::string sourcefile = filesTxtLine.substr(lastColon+1); tinyxml2::XMLDocument doc; tinyxml2::XMLError error = doc.LoadFile(xmlfile.c_str()); diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index 55c567878..8f834c86e 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.h @@ -62,7 +62,7 @@ public: std::string analyzerInfo() const; /** @brief Combine and analyze all analyzerInfos for all TUs */ - static void analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir, const std::map &files); + static void analyseWholeProgram(ErrorLogger * const errorLogger, const std::string &buildDir); private: diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 16c497d94..352f7d412 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -153,7 +153,7 @@ unsigned int CppCheck::processFile(const std::string& filename, const std::strin // Calculate checksum so it can be compared with old checksum / future checksums const unsigned int checksum = preprocessor.calculateChecksum(tokens1, toolinfo); std::list errors; - if (!analyzerInformation.analyzeFile(_settings.buildDir, filename, checksum, &errors)) { + if (!analyzerInformation.analyzeFile(_settings.buildDir, filename, cfgname, checksum, &errors)) { while (!errors.empty()) { reportErr(errors.front()); errors.pop_front(); @@ -737,10 +737,11 @@ void CppCheck::analyseWholeProgram() void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::map &files) { + (void)files; if (buildDir.empty()) return; if (_settings.isEnabled("unusedFunction")) - CheckUnusedFunctions::analyseWholeProgram(this, buildDir, files); + CheckUnusedFunctions::analyseWholeProgram(this, buildDir); } bool CppCheck::isUnusedFunctionCheckEnabled() const