From 9ff3e85899d86b44a4dd08adc994dc549f1bd25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 29 Oct 2016 12:18:11 +0200 Subject: [PATCH] Added --cppcheck-build-dir flag --- Makefile | 24 ++++---- cli/cmdlineparser.cpp | 6 ++ lib/analyzerinfo.cpp | 104 +++++++++++++++++++++++++++++++++++ lib/analyzerinfo.h | 63 +++++++++++++++++++++ lib/check.h | 3 + lib/checkbufferoverrun.cpp | 18 ++++++ lib/checkbufferoverrun.h | 2 + lib/checkunusedfunctions.cpp | 16 ++++++ lib/checkunusedfunctions.h | 6 +- lib/cppcheck.cpp | 22 +++++++- lib/cppcheck.h | 3 + lib/errorlogger.cpp | 17 ++++++ lib/errorlogger.h | 4 ++ lib/lib.pri | 4 +- lib/preprocessor.cpp | 17 ++++++ lib/preprocessor.h | 2 + lib/settings.h | 3 + 17 files changed, 299 insertions(+), 15 deletions(-) create mode 100644 lib/analyzerinfo.cpp create mode 100644 lib/analyzerinfo.h diff --git a/Makefile b/Makefile index 7c90b45d5..315709a12 100644 --- a/Makefile +++ b/Makefile @@ -128,7 +128,8 @@ MAN_SOURCE=man/cppcheck.1.xml ###### Object Files -LIBOBJ = $(SRCDIR)/astutils.o \ +LIBOBJ = $(SRCDIR)/analyzerinfo.o \ + $(SRCDIR)/astutils.o \ $(SRCDIR)/check.o \ $(SRCDIR)/check64bit.o \ $(SRCDIR)/checkassert.o \ @@ -299,6 +300,9 @@ endif ###### Build +$(SRCDIR)/analyzerinfo.o: lib/analyzerinfo.cpp lib/cxx11emu.h lib/analyzerinfo.h lib/config.h + $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/analyzerinfo.o $(SRCDIR)/analyzerinfo.cpp + $(SRCDIR)/astutils.o: lib/astutils.cpp lib/cxx11emu.h lib/astutils.h lib/symboldatabase.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/astutils.o $(SRCDIR)/astutils.cpp @@ -380,10 +384,10 @@ $(SRCDIR)/checkunusedvar.o: lib/checkunusedvar.cpp lib/cxx11emu.h lib/checkunuse $(SRCDIR)/checkvaarg.o: lib/checkvaarg.cpp lib/cxx11emu.h lib/checkvaarg.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/symboldatabase.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/checkvaarg.o $(SRCDIR)/checkvaarg.cpp -$(SRCDIR)/cppcheck.o: lib/cppcheck.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/preprocessor.h lib/path.h lib/version.h +$(SRCDIR)/cppcheck.o: lib/cppcheck.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h lib/preprocessor.h lib/path.h lib/version.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/cppcheck.o $(SRCDIR)/cppcheck.cpp -$(SRCDIR)/errorlogger.o: lib/errorlogger.cpp lib/cxx11emu.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/path.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/utils.h +$(SRCDIR)/errorlogger.o: lib/errorlogger.cpp lib/cxx11emu.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/path.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/errorlogger.o $(SRCDIR)/errorlogger.cpp $(SRCDIR)/importproject.o: lib/importproject.cpp lib/cxx11emu.h lib/importproject.h lib/config.h lib/platform.h lib/path.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h @@ -434,10 +438,10 @@ $(SRCDIR)/tokenlist.o: lib/tokenlist.cpp lib/cxx11emu.h lib/tokenlist.h lib/conf $(SRCDIR)/valueflow.o: lib/valueflow.cpp lib/cxx11emu.h lib/valueflow.h lib/config.h lib/astutils.h lib/errorlogger.h lib/suppressions.h lib/mathlib.h lib/settings.h lib/library.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/symboldatabase.h lib/token.h lib/tokenlist.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(SRCDIR)/valueflow.o $(SRCDIR)/valueflow.cpp -cli/cmdlineparser.o: cli/cmdlineparser.cpp lib/cxx11emu.h cli/cmdlineparser.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h cli/cppcheckexecutor.h cli/filelister.h lib/path.h cli/threadexecutor.h +cli/cmdlineparser.o: cli/cmdlineparser.cpp lib/cxx11emu.h cli/cmdlineparser.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h cli/cppcheckexecutor.h cli/filelister.h lib/path.h cli/threadexecutor.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cmdlineparser.o cli/cmdlineparser.cpp -cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp lib/cxx11emu.h cli/cppcheckexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h cli/cmdlineparser.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h cli/filelister.h lib/path.h lib/pathmatch.h lib/preprocessor.h cli/threadexecutor.h lib/utils.h +cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp lib/cxx11emu.h cli/cppcheckexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h cli/cmdlineparser.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h cli/filelister.h lib/path.h lib/pathmatch.h lib/preprocessor.h cli/threadexecutor.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cppcheckexecutor.o cli/cppcheckexecutor.cpp cli/filelister.o: cli/filelister.cpp lib/cxx11emu.h cli/filelister.h lib/path.h lib/config.h lib/pathmatch.h @@ -446,7 +450,7 @@ cli/filelister.o: cli/filelister.cpp lib/cxx11emu.h cli/filelister.h lib/path.h cli/main.o: cli/main.cpp lib/cxx11emu.h cli/cppcheckexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/main.o cli/main.cpp -cli/threadexecutor.o: cli/threadexecutor.cpp lib/cxx11emu.h cli/threadexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/importproject.h lib/platform.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h cli/cppcheckexecutor.h +cli/threadexecutor.o: cli/threadexecutor.cpp lib/cxx11emu.h cli/threadexecutor.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/importproject.h lib/platform.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h cli/cppcheckexecutor.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/threadexecutor.o cli/threadexecutor.cpp test/options.o: test/options.cpp lib/cxx11emu.h test/options.h @@ -488,10 +492,10 @@ test/testcondition.o: test/testcondition.cpp lib/cxx11emu.h lib/tokenize.h lib/e test/testconstructors.o: test/testconstructors.cpp lib/cxx11emu.h lib/tokenize.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenlist.h lib/checkclass.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testconstructors.o test/testconstructors.cpp -test/testcppcheck.o: test/testcppcheck.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h test/testsuite.h lib/path.h +test/testcppcheck.o: test/testcppcheck.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h test/testsuite.h lib/path.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testcppcheck.o test/testcppcheck.cpp -test/testerrorlogger.o: test/testerrorlogger.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h test/testsuite.h +test/testerrorlogger.o: test/testerrorlogger.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testerrorlogger.o test/testerrorlogger.cpp test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/cxx11emu.h lib/tokenize.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenlist.h lib/checkexceptionsafety.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/utils.h test/testsuite.h @@ -578,13 +582,13 @@ test/teststring.o: test/teststring.cpp lib/cxx11emu.h lib/tokenize.h lib/errorlo test/testsuite.o: test/testsuite.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/options.h test/redirect.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsuite.o test/testsuite.cpp -test/testsuppressions.o: test/testsuppressions.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h test/testsuite.h +test/testsuppressions.o: test/testsuppressions.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsuppressions.o test/testsuppressions.cpp test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/testutils.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/platform.h lib/importproject.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/symboldatabase.h lib/token.h lib/valueflow.h lib/utils.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsymboldatabase.o test/testsymboldatabase.cpp -test/testthreadexecutor.o: test/testthreadexecutor.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h test/testsuite.h +test/testthreadexecutor.o: test/testthreadexecutor.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.h lib/settings.h lib/library.h lib/mathlib.h lib/standards.h lib/errorlogger.h lib/suppressions.h lib/platform.h lib/importproject.h lib/timer.h lib/check.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/analyzerinfo.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testthreadexecutor.o test/testthreadexecutor.cpp test/testtimer.o: test/testtimer.cpp lib/cxx11emu.h lib/timer.h lib/config.h test/testsuite.h lib/errorlogger.h lib/suppressions.h diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index fc3527769..f8e618fa8 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -120,6 +120,9 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[]) return true; } + else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) + _settings->buildDir = argv[i] + 21; + // Flag used for various purposes during debugging else if (std::strcmp(argv[i], "--debug") == 0) _settings->debug = _settings->debugwarnings = true; @@ -797,6 +800,9 @@ void CmdLineParser::PrintHelp() "If a directory is given instead of a filename, *.cpp, *.cxx, *.cc, *.c++, *.c,\n" "*.tpp, and *.txx files are checked recursively from the given directory.\n\n" "Options:\n" + " --analyze-dir= Analysis output directory. Useful for various data.\n" + " Some possible usages are; whole program analysis,\n" + " incremental analysis, distributed analysis.\n" " --check-config Check cppcheck configuration. The normal code\n" " analysis is disabled by this flag.\n" " --check-library Show information messages when library files have\n" diff --git a/lib/analyzerinfo.cpp b/lib/analyzerinfo.cpp new file mode 100644 index 000000000..037526291 --- /dev/null +++ b/lib/analyzerinfo.cpp @@ -0,0 +1,104 @@ +/* +* Cppcheck - A tool for static C/C++ code analysis +* Copyright (C) 2007-2016 Cppcheck team. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "analyzerinfo.h" +#include "path.h" +#include + +AnalyzerInformation::AnalyzerInformation() {} +AnalyzerInformation::~AnalyzerInformation() +{ + close(); +} + +void AnalyzerInformation::close() +{ + analyzerInfoFile.clear(); + if (fout.is_open()) { + fout << "\n"; + fout.close(); + } +} + +static bool skipAnalysis(const std::string &analyzerInfoFile, std::size_t checksum, std::list *errors) +{ + tinyxml2::XMLDocument doc; + tinyxml2::XMLError error = doc.LoadFile(analyzerInfoFile.c_str()); + if (error != tinyxml2::XML_SUCCESS) + return false; + + const tinyxml2::XMLElement * const rootNode = doc.FirstChildElement(); + if (rootNode == nullptr) + return false; + + const char *attr = rootNode->Attribute("checksum"); + if (!attr || attr != std::to_string(checksum)) + return false; + + for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) { + if (std::strcmp(e->Name(), "error") == 0) + errors->push_back(ErrorLogger::ErrorMessage(e)); + } + + return true; +} + +bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, std::size_t checksum, std::list *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"; + + const std::string start = ""; + + if (skipAnalysis(analyzerInfoFile, checksum, errors)) { + return false; + } + + fout.open(analyzerInfoFile); + if (fout.is_open()) { + fout << "\n"; + fout << start << '\n'; + } else { + analyzerInfoFile.clear(); + } + + return true; +} + +void AnalyzerInformation::reportErr(const ErrorLogger::ErrorMessage &msg, bool verbose) +{ + if (fout.is_open()) + fout << msg.toXML(verbose,2) << '\n'; +} + +void AnalyzerInformation::setFileInfo(const std::string &check, const std::string &fileInfo) +{ + if (fout.is_open() && !fileInfo.empty()) + fout << " \n" << fileInfo << " \n"; +} diff --git a/lib/analyzerinfo.h b/lib/analyzerinfo.h new file mode 100644 index 000000000..ffaaf02b8 --- /dev/null +++ b/lib/analyzerinfo.h @@ -0,0 +1,63 @@ +/* +* Cppcheck - A tool for static C/C++ code analysis +* Copyright (C) 2007-2016 Cppcheck team. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +//--------------------------------------------------------------------------- +#ifndef analyzerinfoH +#define analyzerinfoH +//--------------------------------------------------------------------------- + +#include "config.h" +#include "errorlogger.h" +#include +#include + + +/// @addtogroup Core +/// @{ + +/** +* @brief Analyzer information +* +* Store various analysis information: +* - checksum +* - error messages +* - whole program analysis data +* +* The information can be used for various purposes. It allows: +* - 'make' - only analyze TUs that are changed and generate full report +* - should be possible to add distributed analysis later +* - multi-threaded whole program analysis +*/ +class CPPCHECKLIB AnalyzerInformation { +public: + AnalyzerInformation(); + ~AnalyzerInformation(); + + /** Close current TU.analyzerinfo file */ + void close(); + bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, std::size_t checksum, std::list *errors); + void reportErr(const ErrorLogger::ErrorMessage &msg, bool verbose); + void setFileInfo(const std::string &check, const std::string &fileInfo); +private: + std::ofstream fout; + std::string analyzerInfoFile; +}; + +/// @} +//--------------------------------------------------------------------------- +#endif // analyzerinfoH diff --git a/lib/check.h b/lib/check.h index 637616efc..7d0c35776 100644 --- a/lib/check.h +++ b/lib/check.h @@ -90,6 +90,9 @@ public: public: FileInfo() {} virtual ~FileInfo() {} + virtual std::string toString() const { + return std::string(); + } }; virtual FileInfo * getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const { diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index a7eaa5bb1..c1092da49 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1896,6 +1896,24 @@ void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::s "not be accessed if the index is out of limits.", CWE398, false); } +std::string CheckBufferOverrun::MyFileInfo::toString() const +{ + std::ostringstream ret; + for (std::map::const_iterator it = arrayUsage.begin(); it != arrayUsage.end(); ++it) { + ret << " first) << '\"' + << " index=\"" << it->second.index << '\"' + << " fileName=\"" << ErrorLogger::toxml(it->second.fileName) << '\"' + << " linenr=\"" << it->second.linenr << "\"/>\n"; + } + for (std::map::const_iterator it = arraySize.begin(); it != arraySize.end(); ++it) { + ret << " first) << '\"' + << " size=\"" << it->second << "\"/>\n"; + } + return ret.str(); +} + Check::FileInfo* CheckBufferOverrun::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const { (void)settings; diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index 45bc22297..571f89adc 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.h @@ -209,6 +209,8 @@ public: /* data for multifile checking */ class MyFileInfo : public Check::FileInfo { public: + std::string toString() const; + struct ArrayUsage { MathLib::bigint index; std::string fileName; diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 9cc3e1d17..653003483 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -272,3 +272,19 @@ void CheckUnusedFunctions::analyseWholeProgram(const std::list (void)fileInfo; check(&errorLogger, settings); } + +std::string CheckUnusedFunctions::analyzerInfo(const std::string &filename) const +{ + std::ostringstream ret; + for (std::map::const_iterator it = _functions.begin(); it != _functions.end(); ++it) { + if (it->second.filename != filename) + continue; + ret << " first) << '\"' + << " lineNumber=\"" << it->second.lineNumber << '\"' + << " usedSameFile=\"" << (it->second.usedSameFile?1:0) << '\"' + << " usedOtherFile=\"" << (it->second.usedOtherFile?1:0) << "\"/>\n"; + } + return ret.str(); +} + diff --git a/lib/checkunusedfunctions.h b/lib/checkunusedfunctions.h index 982511547..c5964aafd 100644 --- a/lib/checkunusedfunctions.h +++ b/lib/checkunusedfunctions.h @@ -55,6 +55,8 @@ public: static CheckUnusedFunctions instance; + std::string analyzerInfo(const std::string &filename) const; + private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { @@ -72,9 +74,7 @@ private: /** * 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() { return "Unused functions"; diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index a9cd09d8a..9410a0a56 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -24,6 +24,8 @@ #include "check.h" #include "path.h" +#include "checkunusedfunctions.h" + #include #include #include @@ -135,6 +137,18 @@ unsigned int CppCheck::processFile(const std::string& filename, const std::strin tokens1.removeComments(); preprocessor.removeComments(); + if (!_settings.buildDir.empty()) { + std::list errors; + unsigned int checksum = preprocessor.calculateChecksum(tokens1); + if (!analyzerInformation.analyzeFile(_settings.buildDir, filename, checksum, &errors)) { + while (!errors.empty()) { + reportErr(errors.front()); + errors.pop_front(); + } + return exitcode; // known results => no need to reanalyze file + } + } + // Get directives preprocessor.setDirectives(tokens1); @@ -343,6 +357,9 @@ unsigned int CppCheck::processFile(const std::string& filename, const std::strin exitcode=1; // e.g. reflect a syntax error } + analyzerInformation.setFileInfo("CheckUnusedFunctions", CheckUnusedFunctions::instance.analyzerInfo(filename)); + analyzerInformation.close(); + // In jointSuppressionReport mode, unmatched suppressions are // collected after all files are processed if (!_settings.jointSuppressionReport && (_settings.isEnabled("information") || _settings.checkConfiguration)) { @@ -411,8 +428,10 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer) // Analyse the tokens.. for (std::list::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) { Check::FileInfo *fi = (*it)->getFileInfo(&tokenizer, &_settings); - if (fi != nullptr) + if (fi != nullptr) { fileInfo.push_back(fi); + analyzerInformation.setFileInfo((*it)->name(), fi->toString()); + } } executeRules("normal", tokenizer); @@ -635,6 +654,7 @@ void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg) _errorList.push_back(errmsg); _errorLogger.reportErr(msg); + analyzerInformation.reportErr(msg, _settings.verbose); } void CppCheck::reportOut(const std::string &outmsg) diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 81e95fa03..dfb0e5ae4 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -25,6 +25,7 @@ #include "settings.h" #include "errorlogger.h" #include "check.h" +#include "analyzerinfo.h" #include #include @@ -214,6 +215,8 @@ private: /** File info used for whole program analysis */ std::list fileInfo; + + AnalyzerInformation analyzerInformation; }; /// @} diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index def486834..56317ff6b 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -111,6 +111,23 @@ ErrorLogger::ErrorMessage::ErrorMessage(const std::list& callstack setmsg(msg); } +ErrorLogger::ErrorMessage::ErrorMessage(const tinyxml2::XMLElement * const errmsg) : _cwe(0U) +{ + _id = errmsg->Attribute("id"); + _severity = Severity::fromString(errmsg->Attribute("severity")); + const char *attr = errmsg->Attribute("cwe"); + std::istringstream(attr ? attr : "0") >> _cwe.id; + attr = errmsg->Attribute("inconclusive"); + _inconclusive = attr && (std::strcmp(attr, "true") == 0); + _shortMessage = errmsg->Attribute("msg"); + _verboseMessage = errmsg->Attribute("verbose"); + for (const tinyxml2::XMLElement *e = errmsg->FirstChildElement(); e; e = e->NextSiblingElement()) { + if (std::strcmp(e->Name(),"location")==0) { + _callStack.push_back(ErrorLogger::ErrorMessage::FileLocation(e->Attribute("file"), std::atoi(e->Attribute("line")))); + } + } +} + void ErrorLogger::ErrorMessage::setmsg(const std::string &msg) { // If a message ends to a '\n' and contains only a one '\n' diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 82b7dcbaf..f82178a9b 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -40,6 +40,9 @@ struct CWE { class Token; class TokenList; +namespace tinyxml2 { + class XMLElement; +} /// @addtogroup Core /// @{ @@ -213,6 +216,7 @@ public: ErrorMessage(const std::list& callstack, const TokenList* list, Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive); ErrorMessage(const std::list& callstack, const TokenList* list, Severity::SeverityType severity, const std::string& id, const std::string& msg, const CWE &cwe, bool inconclusive); ErrorMessage(); + ErrorMessage(const tinyxml2::XMLElement * const errmsg); /** * Format the error message in XML format diff --git a/lib/lib.pri b/lib/lib.pri index 5e2bc2fe2..2b489f2d6 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -4,6 +4,7 @@ include($$PWD/pcrerules.pri) include($$PWD/../externals/externals.pri) INCLUDEPATH += $$PWD HEADERS += $${PWD}/check.h \ + $${PWD}/analyzerinfo.h \ $${PWD}/astutils.h \ $${PWD}/check.h \ $${PWD}/check64bit.h \ @@ -51,7 +52,8 @@ HEADERS += $${PWD}/check.h \ $${PWD}/valueflow.h \ -SOURCES += $${PWD}/astutils.cpp \ +SOURCES += $${PWD}/analyzerinfo.cpp \ + $${PWD}/astutils.cpp \ $${PWD}/check.cpp \ $${PWD}/check64bit.cpp \ $${PWD}/checkassert.cpp \ diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index a74813a36..add5b0549 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -24,6 +24,7 @@ #include "simplecpp.h" #include +#include #include #include #include @@ -806,3 +807,19 @@ void Preprocessor::dump(std::ostream &out) const } out << " " << std::endl; } + +std::size_t Preprocessor::calculateChecksum(const simplecpp::TokenList &tokens1) const +{ + std::ostringstream ostr; + for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) { + if (!tok->comment) + ostr << tok->str; + } + for (std::map::const_iterator it = tokenlists.begin(); it != tokenlists.end(); ++it) { + for (const simplecpp::Token *tok = it->second->cfront(); tok; tok = tok->next) { + if (!tok->comment) + ostr << tok->str; + } + } + return std::hash {}(ostr.str()); +} diff --git a/lib/preprocessor.h b/lib/preprocessor.h index 676c339d2..3c883d78d 100644 --- a/lib/preprocessor.h +++ b/lib/preprocessor.h @@ -160,6 +160,8 @@ public: bool validateCfg(const std::string &cfg, const std::list ¯oUsageList); void validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string ¯o); + std::size_t calculateChecksum(const simplecpp::TokenList &tokens1) const; + private: /** diff --git a/lib/settings.h b/lib/settings.h index 38407d89a..98ffa4fe4 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -56,6 +56,9 @@ private: public: Settings(); + /** @brief --cppcheck-build-dir */ + std::string buildDir; + /** @brief Is --debug given? */ bool debug;