From 8f10eefbf7292b8d4c805c010c5a01fd355855f2 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Thu, 15 Dec 2022 13:28:42 -0600 Subject: [PATCH 01/46] Refactor XML output through the new `XMLAnalysisReport` class. Currently, for XML output, the XML generation is tightly-coupled with the `ErrorMessage` class, which makes it harder to implement other formats (e.g. SARIF) that may need to see all of the errors/findings at once. Furthermore, implementing the serialization in the `ErrorMessage` class as individual methods (e.g. `toXML`) does not scale very well when using multiple formats. This approach uses the `AnalysisReport` abstract class to sub-class the different serialization formats. --- Makefile | 6 +++++- cli/analysisreport.h | 44 +++++++++++++++++++++++++++++++++++++++ cli/cppcheckexecutor.cpp | 20 +++++++++--------- cli/cppcheckexecutor.h | 6 ++++++ cli/xmlanalysisreport.cpp | 32 ++++++++++++++++++++++++++++ cli/xmlanalysisreport.h | 39 ++++++++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 cli/analysisreport.h create mode 100644 cli/xmlanalysisreport.cpp create mode 100644 cli/xmlanalysisreport.h diff --git a/Makefile b/Makefile index 4ef48391d42..637285fe619 100644 --- a/Makefile +++ b/Makefile @@ -260,7 +260,8 @@ CLIOBJ = cli/cmdlineparser.o \ cli/main.o \ cli/processexecutor.o \ cli/stacktrace.o \ - cli/threadexecutor.o + cli/threadexecutor.o \ + cli/xmlanalysisreport.o TESTOBJ = test/options.o \ test/test64bit.o \ @@ -651,6 +652,9 @@ cli/stacktrace.o: cli/stacktrace.cpp cli/stacktrace.h lib/config.h lib/utils.h cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/threadexecutor.cpp +cli/xmlanalysisreport.o: cli/xmlanalysisreport.cpp cli/analysisreport.h + $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/xmlanalysisreport.cpp + test/options.o: test/options.cpp test/options.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp diff --git a/cli/analysisreport.h b/cli/analysisreport.h new file mode 100644 index 00000000000..1ffa6699d9e --- /dev/null +++ b/cli/analysisreport.h @@ -0,0 +1,44 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 ANALYSIS_REPORT_H +#define ANALYSIS_REPORT_H + +#include "errorlogger.h" + +#include + +/** + * @brief The AnalysisReport class is an abstract class meant to be sub-classed + * by others classes that will contain the results of a CppCheck analysis, and + * output those results in a particular format. + */ +class AnalysisReport { +public: + /** + * Submit a CppCheck result for inclusion into the report. + */ + virtual void add_finding(const ErrorMessage &msg) = 0; + + /** + * Output the results as a string. + */ + virtual std::string emit() = 0; +}; + +#endif // ANALYSIS_REPORT_H \ No newline at end of file diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 4a61b37bac6..fac19ba65a0 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -34,6 +34,7 @@ #include "suppressions.h" #include "utils.h" #include "checkunusedfunctions.h" +#include "xmlanalysisreport.h" #if defined(THREADING_MODEL_THREAD) #include "threadexecutor.h" @@ -69,7 +70,7 @@ /*static*/ FILE* CppCheckExecutor::mExceptionOutput = stdout; CppCheckExecutor::CppCheckExecutor() - : mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mShowAllErrors(false) + : mSettings(nullptr), mReport(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mShowAllErrors(false) {} CppCheckExecutor::~CppCheckExecutor() @@ -99,9 +100,8 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c if (parser.getShowErrorMessages()) { mShowAllErrors = true; - std::cout << ErrorMessage::getXMLHeader(settings.cppcheckCfgProductName); cppcheck->getErrorMessages(); - std::cout << ErrorMessage::getXMLFooter() << std::endl; + std::cout << mReport->emit() << std::endl; } if (parser.exitAfterPrinting()) { @@ -206,6 +206,8 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) const Settings& settings = cppCheck.settings(); mSettings = &settings; + mReport = (AnalysisReport*) new XMLAnalysisReport(settings.cppcheckCfgProductName); + if (!parseFromArgs(&cppCheck, argc, argv)) { mSettings = nullptr; return EXIT_FAILURE; @@ -222,6 +224,8 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) else ret = check_internal(cppCheck); + free(mReport); + mReport = nullptr; mSettings = nullptr; return ret; } @@ -303,10 +307,6 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) mErrorOutput = new std::ofstream(settings.outputFile); } - if (settings.xml) { - reportErr(ErrorMessage::getXMLHeader(settings.cppcheckCfgProductName)); - } - if (!settings.buildDir.empty()) { settings.loadSummaries(); @@ -409,7 +409,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) } if (settings.xml) { - reportErr(ErrorMessage::getXMLFooter()); + reportErr(mReport->emit()); } mSettings = nullptr; @@ -499,7 +499,7 @@ void CppCheckExecutor::reportStatus(std::size_t fileindex, std::size_t filecount void CppCheckExecutor::reportErr(const ErrorMessage &msg) { if (mShowAllErrors) { - reportOut(msg.toXML()); + mReport->add_finding(msg); return; } @@ -508,7 +508,7 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) return; if (mSettings->xml) - reportErr(msg.toXML()); + mReport->add_finding(msg); else reportErr(msg.toString(mSettings->verbose, mSettings->templateFormat, mSettings->templateLocation)); } diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index 2750187e424..31c9b9c63e3 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -19,6 +19,7 @@ #ifndef CPPCHECKEXECUTOR_H #define CPPCHECKEXECUTOR_H +#include "analysisreport.h" #include "color.h" #include "errorlogger.h" @@ -170,6 +171,11 @@ class CppCheckExecutor : public ErrorLogger { */ const Settings* mSettings; + /** + * Reporting object for storing and serializing the results. + */ + AnalysisReport *mReport; + /** * Used to filter out duplicate error messages. */ diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp new file mode 100644 index 00000000000..40dde1d9fc1 --- /dev/null +++ b/cli/xmlanalysisreport.cpp @@ -0,0 +1,32 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 "xmlanalysisreport.h" + +XMLAnalysisReport::XMLAnalysisReport(const std::string& productName) { + mBuffer << ErrorMessage::getXMLHeader(productName); +} + +void XMLAnalysisReport::add_finding(const ErrorMessage &msg) { + mBuffer << msg.toXML(); +} + +std::string XMLAnalysisReport::emit() { + mBuffer << ErrorMessage::getXMLFooter(); + return mBuffer.str(); +} \ No newline at end of file diff --git a/cli/xmlanalysisreport.h b/cli/xmlanalysisreport.h new file mode 100644 index 00000000000..c7b080e2210 --- /dev/null +++ b/cli/xmlanalysisreport.h @@ -0,0 +1,39 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 XML_ANALYSIS_REPORT_H +#define XML_ANALYSIS_REPORT_H + +#include "analysisreport.h" + +#include + +/** + * @brief The XMLAnalysisReport class is used to contain the results of a CppCheck analysis + * and output the results in the XML format. + */ +class XMLAnalysisReport : public AnalysisReport { +public: + explicit XMLAnalysisReport(const std::string&); + void add_finding(const ErrorMessage &) override; + std::string emit() override; +private: + std::stringstream mBuffer; +}; + +#endif //XML_ANALYSIS_REPORT_H From 6f0b5f008ff87a809fe0bbd85601062d7049acd0 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 06:37:27 -0600 Subject: [PATCH 02/46] Refactor out CLI error messages into the new class `CLIAnalysisReport`. This treats the CLI output as just another format (default) for the findings/report. --- Makefile | 6 +++++- cli/clianalysisreport.cpp | 30 ++++++++++++++++++++++++++++++ cli/clianalysisreport.h | 38 ++++++++++++++++++++++++++++++++++++++ cli/cppcheckexecutor.cpp | 14 ++++++++------ 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 cli/clianalysisreport.cpp create mode 100644 cli/clianalysisreport.h diff --git a/Makefile b/Makefile index 637285fe619..9d86fb6361f 100644 --- a/Makefile +++ b/Makefile @@ -261,7 +261,8 @@ CLIOBJ = cli/cmdlineparser.o \ cli/processexecutor.o \ cli/stacktrace.o \ cli/threadexecutor.o \ - cli/xmlanalysisreport.o + cli/xmlanalysisreport.o \ + cli/clianalysisreport.o TESTOBJ = test/options.o \ test/test64bit.o \ @@ -655,6 +656,9 @@ cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/executor cli/xmlanalysisreport.o: cli/xmlanalysisreport.cpp cli/analysisreport.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/xmlanalysisreport.cpp +cli/clianalysisreport.o: cli/clianalysisreport.cpp cli/analysisreport.h + $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/clianalysisreport.cpp + test/options.o: test/options.cpp test/options.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp new file mode 100644 index 00000000000..117d0bb24cc --- /dev/null +++ b/cli/clianalysisreport.cpp @@ -0,0 +1,30 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 "clianalysisreport.h" + +CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation) +: mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)) {} + +void CLIAnalysisReport::add_finding(const ErrorMessage &msg) { + mBuffer << msg.toString(mVerbose, mTemplateFormat, mTemplateLocation); +} + +std::string CLIAnalysisReport::emit() { + return mBuffer.str(); +} \ No newline at end of file diff --git a/cli/clianalysisreport.h b/cli/clianalysisreport.h new file mode 100644 index 00000000000..a78ef19a111 --- /dev/null +++ b/cli/clianalysisreport.h @@ -0,0 +1,38 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 CLI_ANALYSIS_REPORT_H +#define CLI_ANALYSIS_REPORT_H + +#include "analysisreport.h" + +#include + +class CLIAnalysisReport : public AnalysisReport { +public: + CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation); + void add_finding(const ErrorMessage &msg) override; + std::string emit() override; +private: + bool mVerbose; + std::string mTemplateFormat; + std::string mTemplateLocation; + std::stringstream mBuffer; +}; + +#endif //CLI_ANALYSIS_REPORT_H diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index fac19ba65a0..a44278b4b05 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -35,6 +35,7 @@ #include "utils.h" #include "checkunusedfunctions.h" #include "xmlanalysisreport.h" +#include "clianalysisreport.h" #if defined(THREADING_MODEL_THREAD) #include "threadexecutor.h" @@ -206,8 +207,6 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) const Settings& settings = cppCheck.settings(); mSettings = &settings; - mReport = (AnalysisReport*) new XMLAnalysisReport(settings.cppcheckCfgProductName); - if (!parseFromArgs(&cppCheck, argc, argv)) { mSettings = nullptr; return EXIT_FAILURE; @@ -217,6 +216,11 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) return EXIT_SUCCESS; } + if (settings.xml) + mReport = (AnalysisReport*) new XMLAnalysisReport(settings.cppcheckCfgProductName); + else + mReport = (AnalysisReport*) new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation); + int ret; if (cppCheck.settings().exceptionHandling) @@ -408,9 +412,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) } } - if (settings.xml) { - reportErr(mReport->emit()); - } + reportErr(mReport->emit()); mSettings = nullptr; if (returnValue) @@ -510,7 +512,7 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) if (mSettings->xml) mReport->add_finding(msg); else - reportErr(msg.toString(mSettings->verbose, mSettings->templateFormat, mSettings->templateLocation)); + mReport->add_finding(msg); } void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) From e736e598c09b265d802865cd857c17284009df70 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 07:19:07 -0600 Subject: [PATCH 03/46] Change snake-cased `add_finding` to camelCased `addFinding`. This should look and feel like the rest of the CppCheck code. --- cli/analysisreport.h | 2 +- cli/clianalysisreport.cpp | 2 +- cli/clianalysisreport.h | 2 +- cli/cppcheckexecutor.cpp | 6 +++--- cli/xmlanalysisreport.cpp | 2 +- cli/xmlanalysisreport.h | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cli/analysisreport.h b/cli/analysisreport.h index 1ffa6699d9e..616cb6b9eeb 100644 --- a/cli/analysisreport.h +++ b/cli/analysisreport.h @@ -33,7 +33,7 @@ class AnalysisReport { /** * Submit a CppCheck result for inclusion into the report. */ - virtual void add_finding(const ErrorMessage &msg) = 0; + virtual void addFinding(const ErrorMessage &msg) = 0; /** * Output the results as a string. diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp index 117d0bb24cc..132f04fc971 100644 --- a/cli/clianalysisreport.cpp +++ b/cli/clianalysisreport.cpp @@ -21,7 +21,7 @@ CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation) : mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)) {} -void CLIAnalysisReport::add_finding(const ErrorMessage &msg) { +void CLIAnalysisReport::addFinding(const ErrorMessage &msg) { mBuffer << msg.toString(mVerbose, mTemplateFormat, mTemplateLocation); } diff --git a/cli/clianalysisreport.h b/cli/clianalysisreport.h index a78ef19a111..a8267e0f988 100644 --- a/cli/clianalysisreport.h +++ b/cli/clianalysisreport.h @@ -26,7 +26,7 @@ class CLIAnalysisReport : public AnalysisReport { public: CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation); - void add_finding(const ErrorMessage &msg) override; + void addFinding(const ErrorMessage &msg) override; std::string emit() override; private: bool mVerbose; diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index a44278b4b05..f5f036f3e4b 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -501,7 +501,7 @@ void CppCheckExecutor::reportStatus(std::size_t fileindex, std::size_t filecount void CppCheckExecutor::reportErr(const ErrorMessage &msg) { if (mShowAllErrors) { - mReport->add_finding(msg); + mReport->addFinding(msg); return; } @@ -510,9 +510,9 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) return; if (mSettings->xml) - mReport->add_finding(msg); + mReport->addFinding(msg); else - mReport->add_finding(msg); + mReport->addFinding(msg); } void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp index 40dde1d9fc1..5dedfde6fd2 100644 --- a/cli/xmlanalysisreport.cpp +++ b/cli/xmlanalysisreport.cpp @@ -22,7 +22,7 @@ XMLAnalysisReport::XMLAnalysisReport(const std::string& productName) { mBuffer << ErrorMessage::getXMLHeader(productName); } -void XMLAnalysisReport::add_finding(const ErrorMessage &msg) { +void XMLAnalysisReport::addFinding(const ErrorMessage &msg) { mBuffer << msg.toXML(); } diff --git a/cli/xmlanalysisreport.h b/cli/xmlanalysisreport.h index c7b080e2210..52550775e16 100644 --- a/cli/xmlanalysisreport.h +++ b/cli/xmlanalysisreport.h @@ -30,7 +30,7 @@ class XMLAnalysisReport : public AnalysisReport { public: explicit XMLAnalysisReport(const std::string&); - void add_finding(const ErrorMessage &) override; + void addFinding(const ErrorMessage &) override; std::string emit() override; private: std::stringstream mBuffer; From 963267b6c411b1f7c9641487cb7f0876af7db4b1 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 16:13:23 -0600 Subject: [PATCH 04/46] Add SARIF output format with the new `SARIFAnalysisReport` class. This is a good start, but it still needs some work. In particular, I need to fix the startLine/endLine/startColumn/endColumn part. Right now, I am using placeholder values ("1") instead of the real line/column numbers. --- Makefile | 6 +- cli/cmdlineparser.cpp | 4 + cli/cppcheckexecutor.cpp | 3 + cli/sarifanalysisreport.cpp | 142 ++++++++++++++++++++++++++++++++++++ cli/sarifanalysisreport.h | 38 ++++++++++ lib/settings.h | 3 + 6 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 cli/sarifanalysisreport.cpp create mode 100644 cli/sarifanalysisreport.h diff --git a/Makefile b/Makefile index 9d86fb6361f..cfc98843223 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,8 @@ CLIOBJ = cli/cmdlineparser.o \ cli/stacktrace.o \ cli/threadexecutor.o \ cli/xmlanalysisreport.o \ - cli/clianalysisreport.o + cli/clianalysisreport.o \ + cli/sarifanalysisreport.o TESTOBJ = test/options.o \ test/test64bit.o \ @@ -659,6 +660,9 @@ cli/xmlanalysisreport.o: cli/xmlanalysisreport.cpp cli/analysisreport.h cli/clianalysisreport.o: cli/clianalysisreport.cpp cli/analysisreport.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/clianalysisreport.cpp +cli/sarifanalysisreport.o: cli/sarifanalysisreport.cpp cli/analysisreport.h + $(CXX) ${INCLUDE_FOR_CLI} -isystem externals/picojson $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/sarifanalysisreport.cpp + test/options.o: test/options.cpp test/options.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 31aec423d1c..8b0781deb57 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -964,6 +964,10 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings->xml = true; } + // Write results in SARIF format. + else if (std::strcmp(argv[i], "--sarif") == 0) + mSettings->sarif = true; + else { std::string message("unrecognized command line option: \""); message += argv[i]; diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index f5f036f3e4b..2d0db382f29 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -36,6 +36,7 @@ #include "checkunusedfunctions.h" #include "xmlanalysisreport.h" #include "clianalysisreport.h" +#include "sarifanalysisreport.h" #if defined(THREADING_MODEL_THREAD) #include "threadexecutor.h" @@ -218,6 +219,8 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) if (settings.xml) mReport = (AnalysisReport*) new XMLAnalysisReport(settings.cppcheckCfgProductName); + else if (settings.sarif) + mReport = (AnalysisReport*) new SARIFAnalysisReport(cppCheck.version()); else mReport = (AnalysisReport*) new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation); diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp new file mode 100644 index 00000000000..75b3af8bd5a --- /dev/null +++ b/cli/sarifanalysisreport.cpp @@ -0,0 +1,142 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 "sarifanalysisreport.h" + +#include + +SARIFAnalysisReport::SARIFAnalysisReport( std::string versionNumber) +: mVersionNumber(std::move(versionNumber)) {} + +void SARIFAnalysisReport::addFinding(const ErrorMessage &msg) { + std::map>::iterator it = mFindings.insert(mFindings.begin(), {msg.id, std::vector()}); + it->second.push_back(msg); +} + +static std::map text(const std::string& s) { + std::map m = {{ "text", picojson::value(s) }}; + return m; +} + +// SARIFAnalysisReport::emit() constructs a SARIF log object, according to the SARIF 2.1.0 specification. +// The complete specification is at +// but GitHub provides an easier document to read (albeit with different requirements): +// . +std::string SARIFAnalysisReport::emit() { + picojson::object sarifLog; + picojson::object run; + picojson::object tool; + picojson::object toolComponent; + picojson::array results; + picojson::array rules; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317480 + sarifLog["version"] = picojson::value("2.1.0"); + + // While not required, the SARIF standard recommends adding the "$schema" property. + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317481 + sarifLog["$schema"] = picojson::value("https://json.schemastore.org/sarif-2.1.0.json"); + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317541 + toolComponent["name"] = picojson::value("CppCheck"); + + // While the "version" property isn't required, it's useful information to supply. + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317546 + toolComponent["version"] = picojson::value(mVersionNumber); + + for (std::map>::iterator it = mFindings.begin(); it != mFindings.end(); ++it) { + const ErrorMessage rule = it->second[0]; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836 + picojson::object reportingDescriptor = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317839 + { "id", picojson::value(rule.id) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317843 + { "name", picojson::value(rule.shortMessage()) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317845 + { "shortDescription", picojson::value(text(rule.shortMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317846 + { "fullDescription", picojson::value(text(rule.verboseMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317849 + { "help", picojson::value(text(rule.verboseMessage())) }, + }; + rules.emplace_back(reportingDescriptor); + + for (const ErrorMessage& err : it->second) { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427 + picojson::object artifactLocation = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317430 + { "uri", picojson::value(err.file0) } + }; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317685 + picojson::object region = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317690 + { "startLine", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317691 + { "startColumn", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317692 + { "endLine", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317693 + { "endColumn", picojson::value(1.0) }, + }; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 + picojson::object physicalLocation = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317681 + { "artifactLocation", picojson::value(artifactLocation) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317682 + { "region", picojson::value(region) }, + }; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317670 + picojson::object location = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 + { "physicalLocation", picojson::value(physicalLocation) }, + }; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638 + picojson::object result = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317643 + { "ruleId", picojson::value(err.id) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317649 + { "message", picojson::value(text(err.shortMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317650 + { "locations", picojson::value(location) }, + }; + results.emplace_back(result); + } + } + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317556 + toolComponent["rules"] = picojson::value(rules); + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317531 + tool["driver"] = picojson::value(toolComponent); + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317490 + run["tool"] = picojson::value(tool); + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317507 + run["results"] = picojson::value(results); + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317482 + sarifLog["runs"] = picojson::value({run}); + + return static_cast(sarifLog).serialize(true); +} \ No newline at end of file diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h new file mode 100644 index 00000000000..f9354cd170a --- /dev/null +++ b/cli/sarifanalysisreport.h @@ -0,0 +1,38 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 SARIF_ANALYSIS_REPORT_H +#define SARIF_ANALYSIS_REPORT_H + +#include "analysisreport.h" + +#include +#include +#include + +class SARIFAnalysisReport : public AnalysisReport { +public: + explicit SARIFAnalysisReport(std::string versionNumber); + void addFinding(const ErrorMessage& msg) override; + std::string emit() override; +private: + std::string mVersionNumber; + std::map> mFindings; +}; + +#endif //SARIF_ANALYSIS_REPORT_H diff --git a/lib/settings.h b/lib/settings.h index db31f7a5595..d1a156985e1 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -363,6 +363,9 @@ class CPPCHECKLIB Settings : public cppcheck::Platform { /** @brief XML version (--xml-version=..) */ int xml_version; + /** @brief write SARIF results (--sarif) */ + bool sarif; + /** * @brief return true if a included file is to be excluded in Preprocessor::getConfigs * @return true for the file to be excluded. From b495ccdacf304b3426aafa131d12511dcf86629c Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 16:57:36 -0600 Subject: [PATCH 05/46] Reformat files to fix warnings. --- cli/analysisreport.h | 4 +-- cli/clianalysisreport.cpp | 4 +-- cli/sarifanalysisreport.cpp | 68 ++++++++++++++++++------------------- cli/xmlanalysisreport.cpp | 2 +- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/cli/analysisreport.h b/cli/analysisreport.h index 616cb6b9eeb..d0dbf12f514 100644 --- a/cli/analysisreport.h +++ b/cli/analysisreport.h @@ -38,7 +38,7 @@ class AnalysisReport { /** * Output the results as a string. */ - virtual std::string emit() = 0; + virtual std::string emit() = 0; }; -#endif // ANALYSIS_REPORT_H \ No newline at end of file +#endif // ANALYSIS_REPORT_H diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp index 132f04fc971..83aacd77ed1 100644 --- a/cli/clianalysisreport.cpp +++ b/cli/clianalysisreport.cpp @@ -19,7 +19,7 @@ #include "clianalysisreport.h" CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation) -: mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)) {} + : mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)) {} void CLIAnalysisReport::addFinding(const ErrorMessage &msg) { mBuffer << msg.toString(mVerbose, mTemplateFormat, mTemplateLocation); @@ -27,4 +27,4 @@ void CLIAnalysisReport::addFinding(const ErrorMessage &msg) { std::string CLIAnalysisReport::emit() { return mBuffer.str(); -} \ No newline at end of file +} diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 75b3af8bd5a..10b719ecbc8 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -21,7 +21,7 @@ #include SARIFAnalysisReport::SARIFAnalysisReport( std::string versionNumber) -: mVersionNumber(std::move(versionNumber)) {} + : mVersionNumber(std::move(versionNumber)) {} void SARIFAnalysisReport::addFinding(const ErrorMessage &msg) { std::map>::iterator it = mFindings.insert(mFindings.begin(), {msg.id, std::vector()}); @@ -64,60 +64,60 @@ std::string SARIFAnalysisReport::emit() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836 picojson::object reportingDescriptor = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317839 - { "id", picojson::value(rule.id) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317843 - { "name", picojson::value(rule.shortMessage()) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317845 - { "shortDescription", picojson::value(text(rule.shortMessage())) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317846 - { "fullDescription", picojson::value(text(rule.verboseMessage())) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317849 - { "help", picojson::value(text(rule.verboseMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317839 + { "id", picojson::value(rule.id) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317843 + { "name", picojson::value(rule.shortMessage()) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317845 + { "shortDescription", picojson::value(text(rule.shortMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317846 + { "fullDescription", picojson::value(text(rule.verboseMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317849 + { "help", picojson::value(text(rule.verboseMessage())) }, }; rules.emplace_back(reportingDescriptor); for (const ErrorMessage& err : it->second) { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427 picojson::object artifactLocation = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317430 - { "uri", picojson::value(err.file0) } + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317430 + { "uri", picojson::value(err.file0) } }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317685 picojson::object region = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317690 - { "startLine", picojson::value(1.0) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317691 - { "startColumn", picojson::value(1.0) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317692 - { "endLine", picojson::value(1.0) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317693 - { "endColumn", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317690 + { "startLine", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317691 + { "startColumn", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317692 + { "endLine", picojson::value(1.0) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317693 + { "endColumn", picojson::value(1.0) }, }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 picojson::object physicalLocation = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317681 - { "artifactLocation", picojson::value(artifactLocation) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317682 - { "region", picojson::value(region) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317681 + { "artifactLocation", picojson::value(artifactLocation) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317682 + { "region", picojson::value(region) }, }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317670 picojson::object location = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 - { "physicalLocation", picojson::value(physicalLocation) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 + { "physicalLocation", picojson::value(physicalLocation) }, }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638 picojson::object result = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317643 - { "ruleId", picojson::value(err.id) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317649 - { "message", picojson::value(text(err.shortMessage())) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317650 - { "locations", picojson::value(location) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317643 + { "ruleId", picojson::value(err.id) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317649 + { "message", picojson::value(text(err.shortMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317650 + { "locations", picojson::value(location) }, }; results.emplace_back(result); } @@ -139,4 +139,4 @@ std::string SARIFAnalysisReport::emit() { sarifLog["runs"] = picojson::value({run}); return static_cast(sarifLog).serialize(true); -} \ No newline at end of file +} diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp index 5dedfde6fd2..5de12954fec 100644 --- a/cli/xmlanalysisreport.cpp +++ b/cli/xmlanalysisreport.cpp @@ -29,4 +29,4 @@ void XMLAnalysisReport::addFinding(const ErrorMessage &msg) { std::string XMLAnalysisReport::emit() { mBuffer << ErrorMessage::getXMLFooter(); return mBuffer.str(); -} \ No newline at end of file +} From 44ea25844784a345626cb222822ab8405c49bfdb Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 21:14:56 -0600 Subject: [PATCH 06/46] Include externals/picojson for building cppcheck CLI with cmake. --- cli/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index fa1cbad50e6..116502a31a0 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -11,6 +11,7 @@ else() target_include_directories(cli_objs SYSTEM PRIVATE ${tinyxml2_INCLUDE_DIRS}) endif() target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/simplecpp/) +target_include_directories(cli_objs PRIVATE ${PROJECT_SOURCE_DIR}/externals/picojson/) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) # false positive warning in up to Clang 13 - caused by FD_ZERO macro From 918d9cf43a839707fb7bcf3335d84af416157887 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 21:04:59 -0600 Subject: [PATCH 07/46] Abstract classes must implement a destructor, even if its virtual. --- cli/analysisreport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/analysisreport.h b/cli/analysisreport.h index d0dbf12f514..83dfd317f4d 100644 --- a/cli/analysisreport.h +++ b/cli/analysisreport.h @@ -39,6 +39,8 @@ class AnalysisReport { * Output the results as a string. */ virtual std::string emit() = 0; + + virtual ~AnalysisReport() = default; }; #endif // ANALYSIS_REPORT_H From f92e1fd5fcf8e8802fb0b9e9865116827c240da5 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Fri, 16 Dec 2022 21:27:59 -0600 Subject: [PATCH 08/46] Add a parameter name to the XMLAnalysisReport method. This matches the other AnalysisReport classes, and it's what clang-tidy recommends. --- cli/xmlanalysisreport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/xmlanalysisreport.h b/cli/xmlanalysisreport.h index 52550775e16..fb400ba583a 100644 --- a/cli/xmlanalysisreport.h +++ b/cli/xmlanalysisreport.h @@ -30,7 +30,7 @@ class XMLAnalysisReport : public AnalysisReport { public: explicit XMLAnalysisReport(const std::string&); - void addFinding(const ErrorMessage &) override; + void addFinding(const ErrorMessage &msg) override; std::string emit() override; private: std::stringstream mBuffer; From a5298d3236ba533192d9ffdf1ee6e299a11eb65c Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 10:42:13 -0600 Subject: [PATCH 09/46] Use std::unique_ptr instead of new/free. --- cli/cppcheckexecutor.cpp | 8 +++----- cli/cppcheckexecutor.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 2d0db382f29..2630e17c051 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -218,11 +218,11 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) } if (settings.xml) - mReport = (AnalysisReport*) new XMLAnalysisReport(settings.cppcheckCfgProductName); + mReport = std::unique_ptr(new XMLAnalysisReport(settings.cppcheckCfgProductName)); else if (settings.sarif) - mReport = (AnalysisReport*) new SARIFAnalysisReport(cppCheck.version()); + mReport = std::unique_ptr(new SARIFAnalysisReport(cppCheck.version())); else - mReport = (AnalysisReport*) new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation); + mReport = std::unique_ptr(new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation)); int ret; @@ -231,8 +231,6 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) else ret = check_internal(cppCheck); - free(mReport); - mReport = nullptr; mSettings = nullptr; return ret; } diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index 31c9b9c63e3..dd58d714bc6 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -174,7 +174,7 @@ class CppCheckExecutor : public ErrorLogger { /** * Reporting object for storing and serializing the results. */ - AnalysisReport *mReport; + std::unique_ptr mReport; /** * Used to filter out duplicate error messages. From a1f442d6a1e6ebb6c0dac3850eaf5e70feeb7bc6 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 11:16:26 -0600 Subject: [PATCH 10/46] Output severity in SARIF report. --- cli/sarifanalysisreport.cpp | 21 +++++++++++++++++++++ cli/sarifanalysisreport.h | 1 + 2 files changed, 22 insertions(+) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 10b719ecbc8..ebc31d3e0ab 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -33,6 +33,11 @@ static std::map text(const std::string& s) { return m; } +static std::map level(const std::string& s) { + std::map m = {{ "level", picojson::value(s) }}; + return m; +} + // SARIFAnalysisReport::emit() constructs a SARIF log object, according to the SARIF 2.1.0 specification. // The complete specification is at // but GitHub provides an easier document to read (albeit with different requirements): @@ -74,6 +79,8 @@ std::string SARIFAnalysisReport::emit() { { "fullDescription", picojson::value(text(rule.verboseMessage())) }, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317849 { "help", picojson::value(text(rule.verboseMessage())) }, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317850 + { "defaultConfiguration", picojson::value(level(sarifSeverity(rule.severity))) }, }; rules.emplace_back(reportingDescriptor); @@ -140,3 +147,17 @@ std::string SARIFAnalysisReport::emit() { return static_cast(sarifLog).serialize(true); } + +std::string SARIFAnalysisReport::sarifSeverity(Severity::SeverityType severity) { + switch (severity) { + case Severity::SeverityType::error: + return "error"; + case Severity::SeverityType::warning: + return "warning"; + // SARIF only recognizes three severities: error, warning, and note. CppCheck + // has a few others (style, performance, portability, information), which + // means they will get lumped into "note" when converted to SARIF. + default: + return "note"; + } +} diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h index f9354cd170a..a9060cf1b0e 100644 --- a/cli/sarifanalysisreport.h +++ b/cli/sarifanalysisreport.h @@ -30,6 +30,7 @@ class SARIFAnalysisReport : public AnalysisReport { explicit SARIFAnalysisReport(std::string versionNumber); void addFinding(const ErrorMessage& msg) override; std::string emit() override; + static std::string sarifSeverity(Severity::SeverityType severity); private: std::string mVersionNumber; std::map> mFindings; From 349dc0bf63a40b41a7ca46366c4ec3b150b941e8 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 11:50:58 -0600 Subject: [PATCH 11/46] Output precision in SARIF report. SARIF's precision property maps to Cppcheck's certainty, which is essentially the confidence level. --- cli/sarifanalysisreport.cpp | 20 ++++++++++++++++++++ cli/sarifanalysisreport.h | 1 + 2 files changed, 21 insertions(+) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index ebc31d3e0ab..ee958cfd2f0 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -67,6 +67,11 @@ std::string SARIFAnalysisReport::emit() { for (std::map>::iterator it = mFindings.begin(); it != mFindings.end(); ++it) { const ErrorMessage rule = it->second[0]; + // https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#reportingdescriptor-object + picojson::object properties = { + { "precision", picojson::value(sarifPrecision(rule.certainty)) }, + }; + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836 picojson::object reportingDescriptor = { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317839 @@ -81,6 +86,7 @@ std::string SARIFAnalysisReport::emit() { { "help", picojson::value(text(rule.verboseMessage())) }, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317850 { "defaultConfiguration", picojson::value(level(sarifSeverity(rule.severity))) }, + { "properties", picojson::value(properties) }, }; rules.emplace_back(reportingDescriptor); @@ -161,3 +167,17 @@ std::string SARIFAnalysisReport::sarifSeverity(Severity::SeverityType severity) return "note"; } } + +std::string SARIFAnalysisReport::sarifPrecision(Certainty::CertaintyLevel certainty) { + switch (certainty) { + case Certainty::CertaintyLevel::safe: + return "very-high"; + case Certainty::CertaintyLevel::normal: + return "high"; + case Certainty::CertaintyLevel::experimental: + return "medium"; + case Certainty::CertaintyLevel::inconclusive: + default: + return "low"; + } +} \ No newline at end of file diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h index a9060cf1b0e..0ed1763d197 100644 --- a/cli/sarifanalysisreport.h +++ b/cli/sarifanalysisreport.h @@ -31,6 +31,7 @@ class SARIFAnalysisReport : public AnalysisReport { void addFinding(const ErrorMessage& msg) override; std::string emit() override; static std::string sarifSeverity(Severity::SeverityType severity); + static std::string sarifPrecision(Certainty::CertaintyLevel certainty); private: std::string mVersionNumber; std::map> mFindings; From c501cddb83e722d942e2e81382bcd9cc6531e3de Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 12:21:27 -0600 Subject: [PATCH 12/46] Output line/column numbers in SARIF report. --- cli/sarifanalysisreport.cpp | 66 ++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index ee958cfd2f0..1ce1d082dbb 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -91,37 +91,43 @@ std::string SARIFAnalysisReport::emit() { rules.emplace_back(reportingDescriptor); for (const ErrorMessage& err : it->second) { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427 - picojson::object artifactLocation = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317430 - { "uri", picojson::value(err.file0) } - }; - - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317685 - picojson::object region = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317690 - { "startLine", picojson::value(1.0) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317691 - { "startColumn", picojson::value(1.0) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317692 - { "endLine", picojson::value(1.0) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317693 - { "endColumn", picojson::value(1.0) }, - }; + picojson::array locations; + + for (std::list::const_iterator loc = err.callStack.begin(); loc != err.callStack.end(); ++loc) { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427 + picojson::object artifactLocation = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317430 + {"uri", picojson::value(loc->getfile())} + }; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317685 + picojson::object region = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317690 + {"startLine", picojson::value(double(loc->line))}, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317691 + {"startColumn", picojson::value(double(loc->column))}, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317692 + {"endLine", picojson::value(double(loc->line))}, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317693 + {"endColumn", picojson::value(double(loc->column))}, + }; - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 - picojson::object physicalLocation = { - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317681 - { "artifactLocation", picojson::value(artifactLocation) }, - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317682 - { "region", picojson::value(region) }, - }; - - // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317670 - picojson::object location = { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 - { "physicalLocation", picojson::value(physicalLocation) }, - }; + picojson::object physicalLocation = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317681 + {"artifactLocation", picojson::value(artifactLocation)}, + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317682 + {"region", picojson::value(region)}, + }; + + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317670 + picojson::object location = { + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 + {"physicalLocation", picojson::value(physicalLocation)}, + }; + + locations.emplace_back(location); + } // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638 picojson::object result = { @@ -130,7 +136,7 @@ std::string SARIFAnalysisReport::emit() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317649 { "message", picojson::value(text(err.shortMessage())) }, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317650 - { "locations", picojson::value(location) }, + { "locations", picojson::value(locations) }, }; results.emplace_back(result); } From ca7214ff0130cc1398111e75fd5184c8f2a788fd Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 12:22:56 -0600 Subject: [PATCH 13/46] Unify spacing and alignment in std::map literal. --- cli/sarifanalysisreport.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 1ce1d082dbb..9d29e45181f 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -88,6 +88,7 @@ std::string SARIFAnalysisReport::emit() { { "defaultConfiguration", picojson::value(level(sarifSeverity(rule.severity))) }, { "properties", picojson::value(properties) }, }; + rules.emplace_back(reportingDescriptor); for (const ErrorMessage& err : it->second) { @@ -132,12 +133,13 @@ std::string SARIFAnalysisReport::emit() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638 picojson::object result = { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317643 - { "ruleId", picojson::value(err.id) }, + {"ruleId", picojson::value(err.id)}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317649 - { "message", picojson::value(text(err.shortMessage())) }, + {"message", picojson::value(text(err.shortMessage()))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317650 - { "locations", picojson::value(locations) }, + {"locations", picojson::value(locations)}, }; + results.emplace_back(result); } } From b81988ed68bcd3537317fca50146576c5497d791 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 12:46:12 -0600 Subject: [PATCH 14/46] Unify spacing around std::map literals. --- cli/sarifanalysisreport.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 9d29e45181f..007965e8cd8 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -69,24 +69,24 @@ std::string SARIFAnalysisReport::emit() { // https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#reportingdescriptor-object picojson::object properties = { - { "precision", picojson::value(sarifPrecision(rule.certainty)) }, + {"precision", picojson::value(sarifPrecision(rule.certainty))}, }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836 picojson::object reportingDescriptor = { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317839 - { "id", picojson::value(rule.id) }, + {"id", picojson::value(rule.id)}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317843 - { "name", picojson::value(rule.shortMessage()) }, + {"name", picojson::value(rule.shortMessage())}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317845 - { "shortDescription", picojson::value(text(rule.shortMessage())) }, + {"shortDescription", picojson::value(text(rule.shortMessage()))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317846 - { "fullDescription", picojson::value(text(rule.verboseMessage())) }, + {"fullDescription", picojson::value(text(rule.verboseMessage()))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317849 - { "help", picojson::value(text(rule.verboseMessage())) }, + {"help", picojson::value(text(rule.verboseMessage()))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317850 - { "defaultConfiguration", picojson::value(level(sarifSeverity(rule.severity))) }, - { "properties", picojson::value(properties) }, + {"defaultConfiguration", picojson::value(level(sarifSeverity(rule.severity)))}, + {"properties", picojson::value(properties)}, }; rules.emplace_back(reportingDescriptor); From df790fde4ac7f81989bc14068074d2e0a07d53f3 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 17:08:57 -0600 Subject: [PATCH 15/46] Change static methods to static functions. --- cli/sarifanalysisreport.cpp | 56 ++++++++++++++++++------------------- cli/sarifanalysisreport.h | 2 -- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 007965e8cd8..5a09eb330c8 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -38,6 +38,34 @@ static std::map level(const std::string& s) { return m; } +static std::string sarifSeverity(Severity::SeverityType severity) { + switch (severity) { + case Severity::SeverityType::error: + return "error"; + case Severity::SeverityType::warning: + return "warning"; + // SARIF only recognizes three severities: error, warning, and note. CppCheck + // has a few others (style, performance, portability, information), which + // means they will get lumped into "note" when converted to SARIF. + default: + return "note"; + } +} + +static std::string sarifPrecision(Certainty::CertaintyLevel certainty) { + switch (certainty) { + case Certainty::CertaintyLevel::safe: + return "very-high"; + case Certainty::CertaintyLevel::normal: + return "high"; + case Certainty::CertaintyLevel::experimental: + return "medium"; + case Certainty::CertaintyLevel::inconclusive: + default: + return "low"; + } +} + // SARIFAnalysisReport::emit() constructs a SARIF log object, according to the SARIF 2.1.0 specification. // The complete specification is at // but GitHub provides an easier document to read (albeit with different requirements): @@ -161,31 +189,3 @@ std::string SARIFAnalysisReport::emit() { return static_cast(sarifLog).serialize(true); } - -std::string SARIFAnalysisReport::sarifSeverity(Severity::SeverityType severity) { - switch (severity) { - case Severity::SeverityType::error: - return "error"; - case Severity::SeverityType::warning: - return "warning"; - // SARIF only recognizes three severities: error, warning, and note. CppCheck - // has a few others (style, performance, portability, information), which - // means they will get lumped into "note" when converted to SARIF. - default: - return "note"; - } -} - -std::string SARIFAnalysisReport::sarifPrecision(Certainty::CertaintyLevel certainty) { - switch (certainty) { - case Certainty::CertaintyLevel::safe: - return "very-high"; - case Certainty::CertaintyLevel::normal: - return "high"; - case Certainty::CertaintyLevel::experimental: - return "medium"; - case Certainty::CertaintyLevel::inconclusive: - default: - return "low"; - } -} \ No newline at end of file diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h index 0ed1763d197..f9354cd170a 100644 --- a/cli/sarifanalysisreport.h +++ b/cli/sarifanalysisreport.h @@ -30,8 +30,6 @@ class SARIFAnalysisReport : public AnalysisReport { explicit SARIFAnalysisReport(std::string versionNumber); void addFinding(const ErrorMessage& msg) override; std::string emit() override; - static std::string sarifSeverity(Severity::SeverityType severity); - static std::string sarifPrecision(Certainty::CertaintyLevel certainty); private: std::string mVersionNumber; std::map> mFindings; From b1b72396590c1f4d631e61f773dc050ece112082 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 19:08:52 -0600 Subject: [PATCH 16/46] Fix SARIF report by making `runs` property an array. --- cli/sarifanalysisreport.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 5a09eb330c8..b33fa799b70 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -77,6 +77,7 @@ std::string SARIFAnalysisReport::emit() { picojson::object toolComponent; picojson::array results; picojson::array rules; + picojson::array runs; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317480 sarifLog["version"] = picojson::value("2.1.0"); @@ -183,9 +184,10 @@ std::string SARIFAnalysisReport::emit() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317507 run["results"] = picojson::value(results); + runs.emplace_back(run); // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317482 - sarifLog["runs"] = picojson::value({run}); + sarifLog["runs"] = picojson::value(runs); return static_cast(sarifLog).serialize(true); } From 6835c6a71810f3dbaca52dbb86c2b39d9f81345b Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sat, 17 Dec 2022 19:12:17 -0600 Subject: [PATCH 17/46] Include Cppcheck homepage URL to SARIF report. --- cli/sarifanalysisreport.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index b33fa799b70..61a76f6e3ff 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -89,10 +89,12 @@ std::string SARIFAnalysisReport::emit() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317541 toolComponent["name"] = picojson::value("CppCheck"); - // While the "version" property isn't required, it's useful information to supply. // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317546 toolComponent["version"] = picojson::value(mVersionNumber); + // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317550 + toolComponent["informationUri"] = picojson::value("http://cppcheck.net"); + for (std::map>::iterator it = mFindings.begin(); it != mFindings.end(); ++it) { const ErrorMessage rule = it->second[0]; From d92b72b146f54679eb9aab404a8347c2e079339b Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Sun, 18 Dec 2022 09:36:00 -0600 Subject: [PATCH 18/46] Add SARIFAnalysisReport documentation as comment. --- cli/sarifanalysisreport.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h index f9354cd170a..0b79463aead 100644 --- a/cli/sarifanalysisreport.h +++ b/cli/sarifanalysisreport.h @@ -25,6 +25,10 @@ #include #include +/** + * @brief The SARIFAnalysisReport class is used to collect and export findings of a + * CppCheck analysis in the open Static Analysis Results Interchange Format (S.A.R.I.F.). + */ class SARIFAnalysisReport : public AnalysisReport { public: explicit SARIFAnalysisReport(std::string versionNumber); From 551f7edae34f69b11f006c83fa0f129c7a15b997 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 11:25:50 -0600 Subject: [PATCH 19/46] Add missing include to use `std::unique_ptr`. --- cli/cppcheckexecutor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index dd58d714bc6..ff865058861 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -30,6 +30,7 @@ #include #include #include +#include class CppCheck; class Library; From 5f13e121c566eb57d0cb85634ed004208eb4044b Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 11:30:36 -0600 Subject: [PATCH 20/46] Fix `switch`/`case` alignment to please uncrustify. --- cli/sarifanalysisreport.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 61a76f6e3ff..316449ab231 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -40,29 +40,29 @@ static std::map level(const std::string& s) { static std::string sarifSeverity(Severity::SeverityType severity) { switch (severity) { - case Severity::SeverityType::error: - return "error"; - case Severity::SeverityType::warning: - return "warning"; - // SARIF only recognizes three severities: error, warning, and note. CppCheck - // has a few others (style, performance, portability, information), which - // means they will get lumped into "note" when converted to SARIF. - default: - return "note"; + case Severity::SeverityType::error: + return "error"; + case Severity::SeverityType::warning: + return "warning"; + // SARIF only recognizes three severities: error, warning, and note. CppCheck + // has a few others (style, performance, portability, information), which + // means they will get lumped into "note" when converted to SARIF. + default: + return "note"; } } static std::string sarifPrecision(Certainty::CertaintyLevel certainty) { switch (certainty) { - case Certainty::CertaintyLevel::safe: - return "very-high"; - case Certainty::CertaintyLevel::normal: - return "high"; - case Certainty::CertaintyLevel::experimental: - return "medium"; - case Certainty::CertaintyLevel::inconclusive: - default: - return "low"; + case Certainty::CertaintyLevel::safe: + return "very-high"; + case Certainty::CertaintyLevel::normal: + return "high"; + case Certainty::CertaintyLevel::experimental: + return "medium"; + case Certainty::CertaintyLevel::inconclusive: + default: + return "low"; } } From 9a73d59af0ae9bab71098a8314a1bc822730f5ac Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 11:56:28 -0600 Subject: [PATCH 21/46] Fix clang-tidy findings. * All parameters should be named in a function. * static member access through instance. --- cli/cppcheckexecutor.cpp | 2 +- cli/xmlanalysisreport.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 2630e17c051..6835083dd63 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -220,7 +220,7 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) if (settings.xml) mReport = std::unique_ptr(new XMLAnalysisReport(settings.cppcheckCfgProductName)); else if (settings.sarif) - mReport = std::unique_ptr(new SARIFAnalysisReport(cppCheck.version())); + mReport = std::unique_ptr(new SARIFAnalysisReport(CppCheck::version())); else mReport = std::unique_ptr(new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation)); diff --git a/cli/xmlanalysisreport.h b/cli/xmlanalysisreport.h index fb400ba583a..bf2dfadf95f 100644 --- a/cli/xmlanalysisreport.h +++ b/cli/xmlanalysisreport.h @@ -29,7 +29,7 @@ */ class XMLAnalysisReport : public AnalysisReport { public: - explicit XMLAnalysisReport(const std::string&); + explicit XMLAnalysisReport(const std::string& productName); void addFinding(const ErrorMessage &msg) override; std::string emit() override; private: From 9b5310f00b6186508f831a12eef05738c7a465e8 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 13:36:29 -0600 Subject: [PATCH 22/46] Add analysis report objects to Makefile's testrunner target. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cfc98843223..c0424d9c3cc 100644 --- a/Makefile +++ b/Makefile @@ -341,7 +341,7 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ) all: cppcheck testrunner -testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o +testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o cli/clianalysisreport.o cli/xmlanalysisreport.o cli/sarifanalysisreport.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC) test: all From c7a9611390f34fe4f0717bac9f43f1e603de64ce Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 14:30:25 -0600 Subject: [PATCH 23/46] Fix --errorlist by hoisting mReport assignment earlier in the code. I didn't realize --errorlist happens in the arg-parsing stage, which was before the CLI/XML/SARIF report assignment. --- cli/cppcheckexecutor.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 6835083dd63..ceb4c721a0d 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -100,6 +100,13 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c } } + if (settings.xml) + mReport = std::unique_ptr(new XMLAnalysisReport(settings.cppcheckCfgProductName)); + else if (settings.sarif) + mReport = std::unique_ptr(new SARIFAnalysisReport(CppCheck::version())); + else + mReport = std::unique_ptr(new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation)); + if (parser.getShowErrorMessages()) { mShowAllErrors = true; cppcheck->getErrorMessages(); @@ -217,13 +224,6 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) return EXIT_SUCCESS; } - if (settings.xml) - mReport = std::unique_ptr(new XMLAnalysisReport(settings.cppcheckCfgProductName)); - else if (settings.sarif) - mReport = std::unique_ptr(new SARIFAnalysisReport(CppCheck::version())); - else - mReport = std::unique_ptr(new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation)); - int ret; if (cppCheck.settings().exceptionHandling) From b4058cad2e0a9ed7480fa4a540589ec5febeda19 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 14:30:57 -0600 Subject: [PATCH 24/46] Check (and error) if XML and SARIF outputs are both specified. --- cli/cmdlineparser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 8b0781deb57..260637a1ee5 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1026,6 +1026,11 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) if (mSettings->basePaths.empty() && mSettings->relativePaths) mSettings->basePaths = mPathNames; + if (mSettings->xml && mSettings->sarif) { + printError("output format cannot be both XML and SARIF."); + return false; + } + return true; } From 915d9fbae5452b5443b7f90f1a1bfd5ee9874195 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 15:02:05 -0600 Subject: [PATCH 25/46] Fix XML pretty-print by appending new-line to XML error message. --- cli/xmlanalysisreport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp index 5de12954fec..5ef2428e673 100644 --- a/cli/xmlanalysisreport.cpp +++ b/cli/xmlanalysisreport.cpp @@ -23,7 +23,7 @@ XMLAnalysisReport::XMLAnalysisReport(const std::string& productName) { } void XMLAnalysisReport::addFinding(const ErrorMessage &msg) { - mBuffer << msg.toXML(); + mBuffer << msg.toXML() << std::endl; } std::string XMLAnalysisReport::emit() { From 455ab5febef9b27485b3b266389680e6f7bce76e Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 16:03:32 -0600 Subject: [PATCH 26/46] Add CLI system test to test that the SARIF file has expected structure/properties. --- test/cli/sarif/main.c | 6 ++++ test/cli/test-sarif.py | 71 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 test/cli/sarif/main.c create mode 100644 test/cli/test-sarif.py diff --git a/test/cli/sarif/main.c b/test/cli/sarif/main.c new file mode 100644 index 00000000000..ff0da33c2ac --- /dev/null +++ b/test/cli/sarif/main.c @@ -0,0 +1,6 @@ +int main() +{ + char a[10]; + a[10] = 0; + return 0; +} diff --git a/test/cli/test-sarif.py b/test/cli/test-sarif.py new file mode 100644 index 00000000000..907b8ddca79 --- /dev/null +++ b/test/cli/test-sarif.py @@ -0,0 +1,71 @@ + +# python -m pytest test-sarif.py + +import os +import json + +from testutils import cppcheck + +# Run Cppcheck from project path +def cppcheck_local(): + cwd = os.getcwd() + os.chdir('sarif') + ret, stdout, stderr = cppcheck(['--sarif', 'main.c']) + os.chdir(cwd) + return ret, stdout, stderr + +def test_for_sarif_metadata(): + ret, stdout, stderr = cppcheck_local() + sarif = json.loads(stderr) + assert ret == 0, stdout + assert sarif.get('version') != '' + assert sarif.get('$schema') != '' + +def test_for_cppcheck(): + ret, stdout, stderr = cppcheck_local() + sarif = json.loads(stderr) + assert ret == 0, stdout + assert sarif['runs'][0]['tool']['driver'].get('name') == 'CppCheck' + assert sarif['runs'][0]['tool']['driver'].get('version') != '' + assert sarif['runs'][0]['tool']['driver'].get('informationUri') != '' + +def test_for_finding(): + ret, stdout, stderr = cppcheck_local() + sarif = json.loads(stderr) + assert ret == 0, stdout + assert len(sarif['runs']) == 1 + assert len(sarif['runs'][0]['results']) >= 1 + +def test_for_arrayIndexOutOfBounds_result(): + ret, stdout, stderr = cppcheck_local() + sarif = json.loads(stderr) + assert ret == 0, stdout + for run in sarif['runs']: + for result in run['results']: + if result['ruleId'] == 'arrayIndexOutOfBounds': + assert result['locations'][0]['physicalLocation']['artifactLocation']['uri'] == 'main.c' + assert result['locations'][0]['physicalLocation']['region']['startLine'] == 4 + assert result['locations'][0]['physicalLocation']['region']['endLine'] == 4 + assert result['locations'][0]['physicalLocation']['region']['startColumn'] == 6 + assert result['locations'][0]['physicalLocation']['region']['endColumn'] == 6 + assert result['message']['text'] != '' + return + else: + assert 'arrayIndexOutOfBounds result missing.' + +def test_for_arrayIndexOutOfBounds_rule(): + ret, stdout, stderr = cppcheck_local() + sarif = json.loads(stderr) + assert ret == 0, stdout + assert len(sarif['runs'][0]['tool']['driver']['rules']) >= 1 + for rule in sarif['runs'][0]['tool']['driver']['rules']: + if rule['id'] == 'arrayIndexOutOfBounds': + assert rule['defaultConfiguration']['level'] == 'error' + assert rule['fullDescription']['text'] != '' + assert rule['help']['text'] != '' + assert rule['name'] != '' + assert rule['properties']['precision'] == 'high' + assert rule['shortDescription']['text'] != '' + return + else: + assert 'arrayIndexOutOfBounds result missing.' \ No newline at end of file From a4671e537ba11a8e4f37ce5b0092417ec2d1259c Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Mon, 19 Dec 2022 16:14:16 -0600 Subject: [PATCH 27/46] Rename *AnalysisReport::emit() to serialize(). I think this conveys the purpose of the method better, and it is more normal language for returning strings. --- cli/analysisreport.h | 2 +- cli/clianalysisreport.cpp | 2 +- cli/clianalysisreport.h | 2 +- cli/cppcheckexecutor.cpp | 4 ++-- cli/sarifanalysisreport.cpp | 2 +- cli/sarifanalysisreport.h | 2 +- cli/xmlanalysisreport.cpp | 2 +- cli/xmlanalysisreport.h | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cli/analysisreport.h b/cli/analysisreport.h index 83dfd317f4d..bb94c7a2281 100644 --- a/cli/analysisreport.h +++ b/cli/analysisreport.h @@ -38,7 +38,7 @@ class AnalysisReport { /** * Output the results as a string. */ - virtual std::string emit() = 0; + virtual std::string serialize() = 0; virtual ~AnalysisReport() = default; }; diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp index 83aacd77ed1..2e8c08e5a52 100644 --- a/cli/clianalysisreport.cpp +++ b/cli/clianalysisreport.cpp @@ -25,6 +25,6 @@ void CLIAnalysisReport::addFinding(const ErrorMessage &msg) { mBuffer << msg.toString(mVerbose, mTemplateFormat, mTemplateLocation); } -std::string CLIAnalysisReport::emit() { +std::string CLIAnalysisReport::serialize() { return mBuffer.str(); } diff --git a/cli/clianalysisreport.h b/cli/clianalysisreport.h index a8267e0f988..6cc285bcf29 100644 --- a/cli/clianalysisreport.h +++ b/cli/clianalysisreport.h @@ -27,7 +27,7 @@ class CLIAnalysisReport : public AnalysisReport { public: CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation); void addFinding(const ErrorMessage &msg) override; - std::string emit() override; + std::string serialize() override; private: bool mVerbose; std::string mTemplateFormat; diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index ceb4c721a0d..6d6b3ce693c 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -110,7 +110,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c if (parser.getShowErrorMessages()) { mShowAllErrors = true; cppcheck->getErrorMessages(); - std::cout << mReport->emit() << std::endl; + std::cout << mReport->serialize() << std::endl; } if (parser.exitAfterPrinting()) { @@ -413,7 +413,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) } } - reportErr(mReport->emit()); + reportErr(mReport->serialize()); mSettings = nullptr; if (returnValue) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 316449ab231..7d00ff87d3b 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -70,7 +70,7 @@ static std::string sarifPrecision(Certainty::CertaintyLevel certainty) { // The complete specification is at // but GitHub provides an easier document to read (albeit with different requirements): // . -std::string SARIFAnalysisReport::emit() { +std::string SARIFAnalysisReport::serialize() { picojson::object sarifLog; picojson::object run; picojson::object tool; diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h index 0b79463aead..76de3871244 100644 --- a/cli/sarifanalysisreport.h +++ b/cli/sarifanalysisreport.h @@ -33,7 +33,7 @@ class SARIFAnalysisReport : public AnalysisReport { public: explicit SARIFAnalysisReport(std::string versionNumber); void addFinding(const ErrorMessage& msg) override; - std::string emit() override; + std::string serialize() override; private: std::string mVersionNumber; std::map> mFindings; diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp index 5ef2428e673..49899562ce5 100644 --- a/cli/xmlanalysisreport.cpp +++ b/cli/xmlanalysisreport.cpp @@ -26,7 +26,7 @@ void XMLAnalysisReport::addFinding(const ErrorMessage &msg) { mBuffer << msg.toXML() << std::endl; } -std::string XMLAnalysisReport::emit() { +std::string XMLAnalysisReport::serialize() { mBuffer << ErrorMessage::getXMLFooter(); return mBuffer.str(); } diff --git a/cli/xmlanalysisreport.h b/cli/xmlanalysisreport.h index bf2dfadf95f..8a9e6959716 100644 --- a/cli/xmlanalysisreport.h +++ b/cli/xmlanalysisreport.h @@ -31,7 +31,7 @@ class XMLAnalysisReport : public AnalysisReport { public: explicit XMLAnalysisReport(const std::string& productName); void addFinding(const ErrorMessage &msg) override; - std::string emit() override; + std::string serialize() override; private: std::stringstream mBuffer; }; From 2e88265e926e4c21e985de6587026979267cb02a Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 20 Dec 2022 10:29:48 -0600 Subject: [PATCH 28/46] Fix forgotten `sarif` field initialization in settings.cpp. --- lib/settings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index f2b6191add1..4b12aa98646 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -69,7 +69,8 @@ Settings::Settings() valueFlowMaxIterations(4), verbose(false), xml(false), - xml_version(2) + xml_version(2), + sarif(false) { severity.setEnabled(Severity::error, true); certainty.setEnabled(Certainty::normal, true); From 3a647e55cf0bc48772e8fc12bb2d7298b58dd3a3 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 20 Dec 2022 11:14:24 -0600 Subject: [PATCH 29/46] Refactor duplicate-branch conditional statement. This was caught by cppcheck(!) during a self-host check. --- cli/cppcheckexecutor.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 6d6b3ce693c..54f5aae5526 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -510,10 +510,7 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) if (!mShownErrors.insert(msg.toString(mSettings->verbose)).second) return; - if (mSettings->xml) - mReport->addFinding(msg); - else - mReport->addFinding(msg); + mReport->addFinding(msg); } void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) From 4ecafeec49ee8ffa4694c03efa11f34b3e599630 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 20 Dec 2022 16:08:17 -0600 Subject: [PATCH 30/46] Put `sarif` property in alphabetical order of other properties. --- lib/settings.cpp | 4 ++-- lib/settings.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index 4b12aa98646..0304d9240e2 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -65,12 +65,12 @@ Settings::Settings() quiet(false), relativePaths(false), reportProgress(false), + sarif(false), showtime(SHOWTIME_MODES::SHOWTIME_NONE), valueFlowMaxIterations(4), verbose(false), xml(false), - xml_version(2), - sarif(false) + xml_version(2) { severity.setEnabled(Severity::error, true); certainty.setEnabled(Certainty::normal, true); diff --git a/lib/settings.h b/lib/settings.h index d1a156985e1..15f54c2ac02 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -328,6 +328,9 @@ class CPPCHECKLIB Settings : public cppcheck::Platform { SimpleEnableGroup certainty; SimpleEnableGroup checks; + /** @brief write SARIF results (--sarif) */ + bool sarif; + /** @brief show timing information (--showtime=file|summary|top5) */ SHOWTIME_MODES showtime; @@ -363,9 +366,6 @@ class CPPCHECKLIB Settings : public cppcheck::Platform { /** @brief XML version (--xml-version=..) */ int xml_version; - /** @brief write SARIF results (--sarif) */ - bool sarif; - /** * @brief return true if a included file is to be excluded in Preprocessor::getConfigs * @return true for the file to be excluded. From a22a1ac3637127256ea3f3c4bcfcfb537b1e7904 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 20 Dec 2022 16:12:38 -0600 Subject: [PATCH 31/46] Refactor SARIFAnalysisReport::addFinding() from 2 to 1 line! Much thanks to @danmar for the tip :) --- cli/sarifanalysisreport.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 7d00ff87d3b..640644c71a8 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -24,8 +24,7 @@ SARIFAnalysisReport::SARIFAnalysisReport( std::string versionNumber) : mVersionNumber(std::move(versionNumber)) {} void SARIFAnalysisReport::addFinding(const ErrorMessage &msg) { - std::map>::iterator it = mFindings.insert(mFindings.begin(), {msg.id, std::vector()}); - it->second.push_back(msg); + mFindings[msg.id].push_back(msg); } static std::map text(const std::string& s) { From 1a20b60a929886cfb3d386a5d2750218f7ec982e Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Thu, 22 Dec 2022 09:05:38 -0600 Subject: [PATCH 32/46] Fix XML alignment by adding missing newline character. --- cli/xmlanalysisreport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp index 49899562ce5..2e56f9dd823 100644 --- a/cli/xmlanalysisreport.cpp +++ b/cli/xmlanalysisreport.cpp @@ -19,7 +19,7 @@ #include "xmlanalysisreport.h" XMLAnalysisReport::XMLAnalysisReport(const std::string& productName) { - mBuffer << ErrorMessage::getXMLHeader(productName); + mBuffer << ErrorMessage::getXMLHeader(productName) << std::endl; } void XMLAnalysisReport::addFinding(const ErrorMessage &msg) { From d1c2d83dfb9ee4c0c3c632400961105a03271226 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Thu, 22 Dec 2022 09:32:20 -0600 Subject: [PATCH 33/46] Undo changes to merge CLI findings into separate class. Ideally, CLI output would be in a separate class. This is DRY and uncoupled. However, I've discovered that it's a big change. Perhaps too big for this unrelated PR. --- Makefile | 6 +----- cli/clianalysisreport.cpp | 30 ------------------------------ cli/clianalysisreport.h | 38 -------------------------------------- cli/cppcheckexecutor.cpp | 14 ++++++++------ 4 files changed, 9 insertions(+), 79 deletions(-) delete mode 100644 cli/clianalysisreport.cpp delete mode 100644 cli/clianalysisreport.h diff --git a/Makefile b/Makefile index c0424d9c3cc..910d016ca6b 100644 --- a/Makefile +++ b/Makefile @@ -262,7 +262,6 @@ CLIOBJ = cli/cmdlineparser.o \ cli/stacktrace.o \ cli/threadexecutor.o \ cli/xmlanalysisreport.o \ - cli/clianalysisreport.o \ cli/sarifanalysisreport.o TESTOBJ = test/options.o \ @@ -341,7 +340,7 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ) all: cppcheck testrunner -testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o cli/clianalysisreport.o cli/xmlanalysisreport.o cli/sarifanalysisreport.o +testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o cli/xmlanalysisreport.o cli/sarifanalysisreport.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC) test: all @@ -657,9 +656,6 @@ cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/executor cli/xmlanalysisreport.o: cli/xmlanalysisreport.cpp cli/analysisreport.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/xmlanalysisreport.cpp -cli/clianalysisreport.o: cli/clianalysisreport.cpp cli/analysisreport.h - $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/clianalysisreport.cpp - cli/sarifanalysisreport.o: cli/sarifanalysisreport.cpp cli/analysisreport.h $(CXX) ${INCLUDE_FOR_CLI} -isystem externals/picojson $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/sarifanalysisreport.cpp diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp deleted file mode 100644 index 2e8c08e5a52..00000000000 --- a/cli/clianalysisreport.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 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 "clianalysisreport.h" - -CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation) - : mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)) {} - -void CLIAnalysisReport::addFinding(const ErrorMessage &msg) { - mBuffer << msg.toString(mVerbose, mTemplateFormat, mTemplateLocation); -} - -std::string CLIAnalysisReport::serialize() { - return mBuffer.str(); -} diff --git a/cli/clianalysisreport.h b/cli/clianalysisreport.h deleted file mode 100644 index 6cc285bcf29..00000000000 --- a/cli/clianalysisreport.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 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 CLI_ANALYSIS_REPORT_H -#define CLI_ANALYSIS_REPORT_H - -#include "analysisreport.h" - -#include - -class CLIAnalysisReport : public AnalysisReport { -public: - CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation); - void addFinding(const ErrorMessage &msg) override; - std::string serialize() override; -private: - bool mVerbose; - std::string mTemplateFormat; - std::string mTemplateLocation; - std::stringstream mBuffer; -}; - -#endif //CLI_ANALYSIS_REPORT_H diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 54f5aae5526..29ff48d890b 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -35,7 +35,6 @@ #include "utils.h" #include "checkunusedfunctions.h" #include "xmlanalysisreport.h" -#include "clianalysisreport.h" #include "sarifanalysisreport.h" #if defined(THREADING_MODEL_THREAD) @@ -102,10 +101,8 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c if (settings.xml) mReport = std::unique_ptr(new XMLAnalysisReport(settings.cppcheckCfgProductName)); - else if (settings.sarif) + if (settings.sarif) mReport = std::unique_ptr(new SARIFAnalysisReport(CppCheck::version())); - else - mReport = std::unique_ptr(new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation)); if (parser.getShowErrorMessages()) { mShowAllErrors = true; @@ -413,7 +410,9 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) } } - reportErr(mReport->serialize()); + if (settings.xml || settings.sarif) { + reportErr(mReport->serialize()); + } mSettings = nullptr; if (returnValue) @@ -510,7 +509,10 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) if (!mShownErrors.insert(msg.toString(mSettings->verbose)).second) return; - mReport->addFinding(msg); + if (mSettings->xml || mSettings->sarif) + mReport->addFinding(msg); + else + reportErr(msg.toString(mSettings->verbose, mSettings->templateFormat, mSettings->templateLocation)); } void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) From 13ce02ecdfe07db324cf976f748349bb42220a8f Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 10 Jan 2023 12:03:16 -0600 Subject: [PATCH 34/46] `std::move` more objects in sarifanalysisreport.cpp. --- cli/analysisreport.h | 2 +- cli/sarifanalysisreport.cpp | 12 ++++++------ cli/sarifanalysisreport.h | 2 +- cli/xmlanalysisreport.cpp | 2 +- cli/xmlanalysisreport.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cli/analysisreport.h b/cli/analysisreport.h index bb94c7a2281..3c2677fcdc7 100644 --- a/cli/analysisreport.h +++ b/cli/analysisreport.h @@ -33,7 +33,7 @@ class AnalysisReport { /** * Submit a CppCheck result for inclusion into the report. */ - virtual void addFinding(const ErrorMessage &msg) = 0; + virtual void addFinding(ErrorMessage msg) = 0; /** * Output the results as a string. diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 640644c71a8..7a4ed21f291 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -23,8 +23,8 @@ SARIFAnalysisReport::SARIFAnalysisReport( std::string versionNumber) : mVersionNumber(std::move(versionNumber)) {} -void SARIFAnalysisReport::addFinding(const ErrorMessage &msg) { - mFindings[msg.id].push_back(msg); +void SARIFAnalysisReport::addFinding(ErrorMessage msg) { + mFindings[msg.id].emplace_back(std::move(msg)); } static std::map text(const std::string& s) { @@ -119,7 +119,7 @@ std::string SARIFAnalysisReport::serialize() { {"properties", picojson::value(properties)}, }; - rules.emplace_back(reportingDescriptor); + rules.emplace_back(std::move(reportingDescriptor)); for (const ErrorMessage& err : it->second) { picojson::array locations; @@ -157,7 +157,7 @@ std::string SARIFAnalysisReport::serialize() { {"physicalLocation", picojson::value(physicalLocation)}, }; - locations.emplace_back(location); + locations.emplace_back(std::move(location)); } // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638 @@ -170,7 +170,7 @@ std::string SARIFAnalysisReport::serialize() { {"locations", picojson::value(locations)}, }; - results.emplace_back(result); + results.emplace_back(std::move(result)); } } @@ -185,7 +185,7 @@ std::string SARIFAnalysisReport::serialize() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317507 run["results"] = picojson::value(results); - runs.emplace_back(run); + runs.emplace_back(std::move(run)); // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317482 sarifLog["runs"] = picojson::value(runs); diff --git a/cli/sarifanalysisreport.h b/cli/sarifanalysisreport.h index 76de3871244..1a8b0ab4435 100644 --- a/cli/sarifanalysisreport.h +++ b/cli/sarifanalysisreport.h @@ -32,7 +32,7 @@ class SARIFAnalysisReport : public AnalysisReport { public: explicit SARIFAnalysisReport(std::string versionNumber); - void addFinding(const ErrorMessage& msg) override; + void addFinding(ErrorMessage msg) override; std::string serialize() override; private: std::string mVersionNumber; diff --git a/cli/xmlanalysisreport.cpp b/cli/xmlanalysisreport.cpp index 2e56f9dd823..447993120b3 100644 --- a/cli/xmlanalysisreport.cpp +++ b/cli/xmlanalysisreport.cpp @@ -22,7 +22,7 @@ XMLAnalysisReport::XMLAnalysisReport(const std::string& productName) { mBuffer << ErrorMessage::getXMLHeader(productName) << std::endl; } -void XMLAnalysisReport::addFinding(const ErrorMessage &msg) { +void XMLAnalysisReport::addFinding(const ErrorMessage msg) { mBuffer << msg.toXML() << std::endl; } diff --git a/cli/xmlanalysisreport.h b/cli/xmlanalysisreport.h index 8a9e6959716..33e1afd6f1b 100644 --- a/cli/xmlanalysisreport.h +++ b/cli/xmlanalysisreport.h @@ -30,7 +30,7 @@ class XMLAnalysisReport : public AnalysisReport { public: explicit XMLAnalysisReport(const std::string& productName); - void addFinding(const ErrorMessage &msg) override; + void addFinding(const ErrorMessage msg) override; std::string serialize() override; private: std::stringstream mBuffer; From 03d91ac65b79f23253db1a55689a499bb1b9b563 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 10 Jan 2023 12:15:00 -0600 Subject: [PATCH 35/46] Use range-based for loop for SARIF generation. --- cli/sarifanalysisreport.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 7a4ed21f291..967a3541677 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -94,8 +94,8 @@ std::string SARIFAnalysisReport::serialize() { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317550 toolComponent["informationUri"] = picojson::value("http://cppcheck.net"); - for (std::map>::iterator it = mFindings.begin(); it != mFindings.end(); ++it) { - const ErrorMessage rule = it->second[0]; + for (auto it : mFindings) { + const ErrorMessage rule = it.second[0]; // https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#reportingdescriptor-object picojson::object properties = { @@ -121,26 +121,26 @@ std::string SARIFAnalysisReport::serialize() { rules.emplace_back(std::move(reportingDescriptor)); - for (const ErrorMessage& err : it->second) { + for (const ErrorMessage& err : it.second) { picojson::array locations; - for (std::list::const_iterator loc = err.callStack.begin(); loc != err.callStack.end(); ++loc) { + for (const ErrorMessage::FileLocation& loc : err.callStack) { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427 picojson::object artifactLocation = { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317430 - {"uri", picojson::value(loc->getfile())} + {"uri", picojson::value(loc.getfile())} }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317685 picojson::object region = { // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317690 - {"startLine", picojson::value(double(loc->line))}, + {"startLine", picojson::value(double(loc.line))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317691 - {"startColumn", picojson::value(double(loc->column))}, + {"startColumn", picojson::value(double(loc.column))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317692 - {"endLine", picojson::value(double(loc->line))}, + {"endLine", picojson::value(double(loc.line))}, // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317693 - {"endColumn", picojson::value(double(loc->column))}, + {"endColumn", picojson::value(double(loc.column))}, }; // https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317678 From e14ff71c4dce3b9e2b9bb687cad3b67bbdf7928e Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 10 Jan 2023 14:26:16 -0600 Subject: [PATCH 36/46] Use constant reference. --- cli/sarifanalysisreport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 967a3541677..105c34215dd 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -95,7 +95,7 @@ std::string SARIFAnalysisReport::serialize() { toolComponent["informationUri"] = picojson::value("http://cppcheck.net"); for (auto it : mFindings) { - const ErrorMessage rule = it.second[0]; + const ErrorMessage& rule = it.second[0]; // https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#reportingdescriptor-object picojson::object properties = { From 74950dcc760c95a2212a4521cc89b8b4b480b074 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 10 Jan 2023 14:29:29 -0600 Subject: [PATCH 37/46] Improve error message to be more helpful. --- cli/cmdlineparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 260637a1ee5..29f4d870632 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -1027,7 +1027,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings->basePaths = mPathNames; if (mSettings->xml && mSettings->sarif) { - printError("output format cannot be both XML and SARIF."); + printError("options --xml and --sarif are mutually exclusive; both cannot be used. Choose only one."); return false; } From 3abccfcd286c075b68edf22dd9fe551cf1cca516 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 10 Jan 2023 15:13:21 -0600 Subject: [PATCH 38/46] Add CLIAnalysisReport class for outputting findings to CLI. --- Makefile | 38 +++++++++++++----------- cli/clianalysisreport.cpp | 62 +++++++++++++++++++++++++++++++++++++++ cli/clianalysisreport.h | 41 ++++++++++++++++++++++++++ cli/cppcheckexecutor.cpp | 24 +++++++-------- 4 files changed, 135 insertions(+), 30 deletions(-) create mode 100644 cli/clianalysisreport.cpp create mode 100644 cli/clianalysisreport.h diff --git a/Makefile b/Makefile index 910d016ca6b..ea67a563246 100644 --- a/Makefile +++ b/Makefile @@ -251,7 +251,8 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \ EXTOBJ = externals/simplecpp/simplecpp.o \ externals/tinyxml2/tinyxml2.o -CLIOBJ = cli/cmdlineparser.o \ +CLIOBJ = cli/clianalysisreport.o \ + cli/cmdlineparser.o \ cli/cppcheckexecutor.o \ cli/cppcheckexecutorseh.o \ cli/cppcheckexecutorsig.o \ @@ -259,10 +260,10 @@ CLIOBJ = cli/cmdlineparser.o \ cli/filelister.o \ cli/main.o \ cli/processexecutor.o \ + cli/sarifanalysisreport.o \ cli/stacktrace.o \ cli/threadexecutor.o \ - cli/xmlanalysisreport.o \ - cli/sarifanalysisreport.o + cli/xmlanalysisreport.o TESTOBJ = test/options.o \ test/test64bit.o \ @@ -340,7 +341,7 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ) all: cppcheck testrunner -testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o cli/xmlanalysisreport.o cli/sarifanalysisreport.o +testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC) test: all @@ -623,16 +624,19 @@ $(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h $(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp -cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/clianalysisreport.o: cli/clianalysisreport.cpp cli/analysisreport.h cli/clianalysisreport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h + $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/clianalysisreport.cpp + +cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/analysisreport.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp -cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h cli/cppcheckexecutorsig.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/threadexecutor.h externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/analysisreport.h cli/clianalysisreport.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h cli/cppcheckexecutorsig.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/sarifanalysisreport.h cli/threadexecutor.h cli/xmlanalysisreport.h externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp -cli/cppcheckexecutorseh.o: cli/cppcheckexecutorseh.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h lib/utils.h +cli/cppcheckexecutorseh.o: cli/cppcheckexecutorseh.cpp cli/analysisreport.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutorseh.cpp -cli/cppcheckexecutorsig.o: cli/cppcheckexecutorsig.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorsig.h cli/stacktrace.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h +cli/cppcheckexecutorsig.o: cli/cppcheckexecutorsig.cpp cli/analysisreport.h cli/cppcheckexecutor.h cli/cppcheckexecutorsig.h cli/stacktrace.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutorsig.cpp cli/executor.o: cli/executor.cpp cli/executor.h @@ -641,24 +645,24 @@ cli/executor.o: cli/executor.cpp cli/executor.h cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/path.h lib/pathmatch.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/filelister.cpp -cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h +cli/main.o: cli/main.cpp cli/analysisreport.h cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/main.cpp -cli/processexecutor.o: cli/processexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/processexecutor.o: cli/processexecutor.cpp cli/analysisreport.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/processexecutor.cpp +cli/sarifanalysisreport.o: cli/sarifanalysisreport.cpp cli/analysisreport.h cli/sarifanalysisreport.h externals/picojson/picojson.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h + $(CXX) ${INCLUDE_FOR_CLI} -isystem externals/picojson $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/sarifanalysisreport.cpp + cli/stacktrace.o: cli/stacktrace.cpp cli/stacktrace.h lib/config.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/stacktrace.cpp -cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h +cli/threadexecutor.o: cli/threadexecutor.cpp cli/analysisreport.h cli/cppcheckexecutor.h cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/threadexecutor.cpp -cli/xmlanalysisreport.o: cli/xmlanalysisreport.cpp cli/analysisreport.h +cli/xmlanalysisreport.o: cli/xmlanalysisreport.cpp cli/analysisreport.h cli/xmlanalysisreport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h $(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/xmlanalysisreport.cpp -cli/sarifanalysisreport.o: cli/sarifanalysisreport.cpp cli/analysisreport.h - $(CXX) ${INCLUDE_FOR_CLI} -isystem externals/picojson $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/sarifanalysisreport.cpp - test/options.o: test/options.cpp test/options.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp @@ -695,7 +699,7 @@ test/testclangimport.o: test/testclangimport.cpp lib/clangimport.h lib/color.h l test/testclass.o: test/testclass.cpp externals/tinyxml2/tinyxml2.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp -test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/redirect.h test/testsuite.h +test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/analysisreport.h cli/cmdlineparser.h cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/redirect.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp test/testcondition.o: test/testcondition.cpp externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/check.h lib/checkcondition.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h @@ -803,7 +807,7 @@ test/testsuite.o: test/testsuite.cpp lib/color.h lib/config.h lib/errorlogger.h test/testsummaries.o: test/testsummaries.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsummaries.cpp -test/testsuppressions.o: test/testsuppressions.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h +test/testsuppressions.o: test/testsuppressions.cpp cli/analysisreport.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsuppressions.cpp test/testsymboldatabase.o: test/testsymboldatabase.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp new file mode 100644 index 00000000000..f65688dcb64 --- /dev/null +++ b/cli/clianalysisreport.cpp @@ -0,0 +1,62 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 +#include + +#include "clianalysisreport.h" + +CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation, std::ofstream* errorOutput) +: mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)), mErrorOutput(errorOutput) {} + +std::string CLIAnalysisReport::serialize() { + return ""; // CLIAnalysisReport emits the findings immediately, so no need to return a report. +} + +#ifdef _WIN32 +// fix trac ticket #439 'Cppcheck reports wrong filename for filenames containing 8-bit ASCII' +static inline std::string ansiToOEM(const std::string &msg, bool doConvert) +{ + if (doConvert) { + const unsigned msglength = msg.length(); + // convert ANSI strings to OEM strings in two steps + std::vector wcContainer(msglength); + std::string result(msglength, '\0'); + + // ansi code page characters to wide characters + MultiByteToWideChar(CP_ACP, 0, msg.data(), msglength, wcContainer.data(), msglength); + // wide characters to oem codepage characters + WideCharToMultiByte(CP_OEMCP, 0, wcContainer.data(), msglength, const_cast(result.data()), msglength, nullptr, nullptr); + + return result; // hope for return value optimization + } + return msg; +} +#else +// no performance regression on non-windows systems +#define ansiToOEM(msg, doConvert) (msg) +#endif + +void CLIAnalysisReport::addFinding(const ErrorMessage msg) { + const std::string errmsg = msg.toString(mVerbose, mTemplateFormat, mTemplateLocation); + if (mErrorOutput) + *mErrorOutput << errmsg << std::endl; + else { + std::cerr << ansiToOEM(errmsg, true) << std::endl; + } +} diff --git a/cli/clianalysisreport.h b/cli/clianalysisreport.h new file mode 100644 index 00000000000..e39648f97b9 --- /dev/null +++ b/cli/clianalysisreport.h @@ -0,0 +1,41 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 CLI_ANALYSIS_REPORT_H +#define CLI_ANALYSIS_REPORT_H + +#include "analysisreport.h" + +/** + * @brief The CLIAnalysisReport class is used to contain the results of a CppCheck analysis + * and output the results to STDERR. + */ +class CLIAnalysisReport : public AnalysisReport { +public: + CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation, std::ofstream* errorOutput); + void addFinding(const ErrorMessage msg) override; + std::string serialize() override; + +private: + bool mVerbose; + std::string mTemplateFormat; + std::string mTemplateLocation; + std::ofstream *mErrorOutput; +}; + +#endif //CLI_ANALYSIS_REPORT_H diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 29ff48d890b..c74555926a7 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -36,6 +36,7 @@ #include "checkunusedfunctions.h" #include "xmlanalysisreport.h" #include "sarifanalysisreport.h" +#include "clianalysisreport.h" #if defined(THREADING_MODEL_THREAD) #include "threadexecutor.h" @@ -99,10 +100,16 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c } } - if (settings.xml) + if (!settings.outputFile.empty()) { + mErrorOutput = new std::ofstream(settings.outputFile); + } + + if (settings.xml || parser.getShowErrorMessages()) mReport = std::unique_ptr(new XMLAnalysisReport(settings.cppcheckCfgProductName)); - if (settings.sarif) + else if (settings.sarif) mReport = std::unique_ptr(new SARIFAnalysisReport(CppCheck::version())); + else + mReport = std::unique_ptr(new CLIAnalysisReport(settings.verbose, settings.templateFormat, settings.templateLocation, mErrorOutput)); if (parser.getShowErrorMessages()) { mShowAllErrors = true; @@ -305,10 +312,6 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) if (settings.reportProgress) mLatestProgressOutputTime = std::time(nullptr); - if (!settings.outputFile.empty()) { - mErrorOutput = new std::ofstream(settings.outputFile); - } - if (!settings.buildDir.empty()) { settings.loadSummaries(); @@ -410,9 +413,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) } } - if (settings.xml || settings.sarif) { - reportErr(mReport->serialize()); - } + reportErr(mReport->serialize()); mSettings = nullptr; if (returnValue) @@ -509,10 +510,7 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) if (!mShownErrors.insert(msg.toString(mSettings->verbose)).second) return; - if (mSettings->xml || mSettings->sarif) - mReport->addFinding(msg); - else - reportErr(msg.toString(mSettings->verbose, mSettings->templateFormat, mSettings->templateLocation)); + mReport->addFinding(msg); } void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) From 1cc35165eb637b3e2d50b1e276745dc0ae63bd07 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Tue, 10 Jan 2023 15:47:13 -0600 Subject: [PATCH 39/46] Indent the member initialization for uncrusty. --- cli/clianalysisreport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp index f65688dcb64..7de63fe6a93 100644 --- a/cli/clianalysisreport.cpp +++ b/cli/clianalysisreport.cpp @@ -22,7 +22,7 @@ #include "clianalysisreport.h" CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation, std::ofstream* errorOutput) -: mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)), mErrorOutput(errorOutput) {} + : mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)), mErrorOutput(errorOutput) {} std::string CLIAnalysisReport::serialize() { return ""; // CLIAnalysisReport emits the findings immediately, so no need to return a report. From 21eba3b38087aa427a13dc2f077fb94e1ae649e1 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 11:05:04 -0600 Subject: [PATCH 40/46] Fix the extra new-line character that was added. --- cli/cppcheckexecutor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index c74555926a7..8bf30639250 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -448,15 +448,15 @@ static inline std::string ansiToOEM(const std::string &msg, bool doConvert) void CppCheckExecutor::reportErr(const std::string &errmsg) { if (mErrorOutput) - *mErrorOutput << errmsg << std::endl; + *mErrorOutput << errmsg; else { - std::cerr << ansiToOEM(errmsg, (mSettings == nullptr) ? true : !mSettings->xml) << std::endl; + std::cerr << ansiToOEM(errmsg, (mSettings == nullptr) ? true : !mSettings->xml); } } void CppCheckExecutor::reportOut(const std::string &outmsg, Color c) { - std::cout << c << ansiToOEM(outmsg, true) << Color::Reset << std::endl; + std::cout << c << ansiToOEM(outmsg, true) << Color::Reset; } void CppCheckExecutor::reportProgress(const std::string &filename, const char stage[], const std::size_t value) From b341465b9369e44e13fa6d07579c8b1b71a6b22f Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 11:14:34 -0600 Subject: [PATCH 41/46] Use `--output-format` instead of `--sarif`. --- cli/cmdlineparser.cpp | 28 +++++++++++++++++++++++----- test/cli/test-sarif.py | 4 ++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 29f4d870632..0e4486f72da 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -941,8 +941,10 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } // Write results in results.xml - else if (std::strcmp(argv[i], "--xml") == 0) + else if (std::strcmp(argv[i], "--xml") == 0) { + printMessage("option --xml is deprecated; use --output-format=xml instead."); mSettings->xml = true; + } // Define the XML file version (and enable XML output) else if (std::strncmp(argv[i], "--xml-version=", 14) == 0) { @@ -964,9 +966,19 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings->xml = true; } - // Write results in SARIF format. - else if (std::strcmp(argv[i], "--sarif") == 0) - mSettings->sarif = true; + // Specify output format (XML, SARIF, etc.) + else if (std::strncmp(argv[i], "--output-format=", 16) == 0) { + const std::string outputFormatArg(argv[i]+16); + + if (outputFormatArg == "xml") + mSettings->xml = true; + else if (outputFormatArg == "sarif") + mSettings->sarif = true; + else { + printError("invalid argument to --output-format option: " + outputFormatArg); + return false; + } + } else { std::string message("unrecognized command line option: \""); @@ -1185,6 +1197,12 @@ void CmdLineParser::printHelp() " is 2. A larger value will mean more errors can be found\n" " but also means the analysis will be slower.\n" " --output-file= Write results to file, rather than standard error.\n" + " --output-format=\n" + " Write results in one of the supported file formats:\n" + " * xml\n" + " XML format (equivalent to --xml)\n" + " * sarif\n" + " Static Analysis Results Interchange Format v2.1.0\n" " --platform=, --platform=\n" " Specifies platform specific types and sizes. The\n" " available builtin platforms are:\n" @@ -1331,7 +1349,7 @@ void CmdLineParser::printHelp() " Example: '-UDEBUG'\n" " -v, --verbose Output more detailed error information.\n" " --version Print out version number.\n" - " --xml Write results in xml format to error stream (stderr).\n" + " --xml [DEPRECATED] Write results in xml format to error stream (stderr).\n" "\n" "Example usage:\n" " # Recursively check the current folder. Print the progress on the screen and\n" diff --git a/test/cli/test-sarif.py b/test/cli/test-sarif.py index 907b8ddca79..962389425bf 100644 --- a/test/cli/test-sarif.py +++ b/test/cli/test-sarif.py @@ -10,7 +10,7 @@ def cppcheck_local(): cwd = os.getcwd() os.chdir('sarif') - ret, stdout, stderr = cppcheck(['--sarif', 'main.c']) + ret, stdout, stderr = cppcheck(['--output-format=sarif', 'main.c']) os.chdir(cwd) return ret, stdout, stderr @@ -68,4 +68,4 @@ def test_for_arrayIndexOutOfBounds_rule(): assert rule['shortDescription']['text'] != '' return else: - assert 'arrayIndexOutOfBounds result missing.' \ No newline at end of file + assert 'arrayIndexOutOfBounds result missing.' From 1b3255483be3a5c4ae725cd9dff826903a4b23c0 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 11:23:00 -0600 Subject: [PATCH 42/46] Use move semantics for SARIF generation if PicoJSON supports it. --- cli/sarifanalysisreport.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 105c34215dd..81ecbc2c6c6 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -27,13 +27,21 @@ void SARIFAnalysisReport::addFinding(ErrorMessage msg) { mFindings[msg.id].emplace_back(std::move(msg)); } -static std::map text(const std::string& s) { +static std::map text(std::string s) { +#ifdef PICOJSON_USE_RVALUE_REFERENCE + std::map m = {{ "text", picojson::value(std::move(s)) }}; +#else std::map m = {{ "text", picojson::value(s) }}; +#endif return m; } -static std::map level(const std::string& s) { +static std::map level(std::string s) { +#ifdef PICOJSON_USE_RVALUE_REFERENCE + std::map m = {{ "level", picojson::value(std::move(s)) }}; +#else std::map m = {{ "level", picojson::value(s) }}; +#endif return m; } From eacd0876192dcd836bffb79646d4b556a04beb7a Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 11:44:38 -0600 Subject: [PATCH 43/46] Fix tests by using `--output-format=xml` instead of `--xml`. --- test/testcmdlineparser.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index 5bddf8ba666..132e76fa1fc 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -1079,7 +1079,7 @@ class TestCmdlineParser : public TestFixture { void xml() { REDIRECT; - const char * const argv[] = {"cppcheck", "--xml", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--output-format=xml", "file.cpp"}; settings.xml_version = 1; settings.xml = false; ASSERT(defParser.parseFromArgs(3, argv)); @@ -1101,7 +1101,7 @@ class TestCmdlineParser : public TestFixture { void xmlver2both() { REDIRECT; - const char * const argv[] = {"cppcheck", "--xml", "--xml-version=2", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--output-format=xml", "--xml-version=2", "file.cpp"}; settings.xml_version = 1; settings.xml = false; ASSERT(defParser.parseFromArgs(4, argv)); @@ -1112,7 +1112,7 @@ class TestCmdlineParser : public TestFixture { void xmlver2both2() { REDIRECT; - const char * const argv[] = {"cppcheck", "--xml-version=2", "--xml", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--xml-version=2", "--output-format=xml", "file.cpp"}; settings.xml_version = 1; settings.xml = false; ASSERT(defParser.parseFromArgs(4, argv)); @@ -1123,7 +1123,7 @@ class TestCmdlineParser : public TestFixture { void xmlverunknown() { REDIRECT; - const char * const argv[] = {"cppcheck", "--xml", "--xml-version=3", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--output-format=xml", "--xml-version=3", "file.cpp"}; // FAils since unknown XML format version ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: '--xml-version' can only be 2.\n", GET_REDIRECT_OUTPUT); @@ -1131,7 +1131,7 @@ class TestCmdlineParser : public TestFixture { void xmlverinvalid() { REDIRECT; - const char * const argv[] = {"cppcheck", "--xml", "--xml-version=a", "file.cpp"}; + const char * const argv[] = {"cppcheck", "--output-format=xml", "--xml-version=a", "file.cpp"}; // FAils since unknown XML format version ASSERT_EQUALS(false, defParser.parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '--xml-version' is not a number.\n", GET_REDIRECT_OUTPUT); From 9995bb1574256deb6b407f92595d420c2fa33ad7 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 11:49:27 -0600 Subject: [PATCH 44/46] Forgot to include windows.h for Windows OSes. --- cli/clianalysisreport.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/clianalysisreport.cpp b/cli/clianalysisreport.cpp index 7de63fe6a93..6ff123cc29a 100644 --- a/cli/clianalysisreport.cpp +++ b/cli/clianalysisreport.cpp @@ -21,6 +21,10 @@ #include "clianalysisreport.h" +#ifdef _WIN32 +#include +#endif + CLIAnalysisReport::CLIAnalysisReport(bool verbose, std::string templateFormat, std::string templateLocation, std::ofstream* errorOutput) : mVerbose(verbose), mTemplateFormat(std::move(templateFormat)), mTemplateLocation(std::move(templateLocation)), mErrorOutput(errorOutput) {} From e53984ec6d591f64646279da0374a4c8f24969e7 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 13:33:01 -0600 Subject: [PATCH 45/46] Fix selfcheck and clang-tidy warnings about passing std::string by value. We will only pass std::string by value if it can be std::move()d. Otherwise, it will get passed as a constant reference. --- cli/sarifanalysisreport.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cli/sarifanalysisreport.cpp b/cli/sarifanalysisreport.cpp index 81ecbc2c6c6..db9485afc90 100644 --- a/cli/sarifanalysisreport.cpp +++ b/cli/sarifanalysisreport.cpp @@ -27,23 +27,29 @@ void SARIFAnalysisReport::addFinding(ErrorMessage msg) { mFindings[msg.id].emplace_back(std::move(msg)); } -static std::map text(std::string s) { #ifdef PICOJSON_USE_RVALUE_REFERENCE +static std::map text(std::string s) { std::map m = {{ "text", picojson::value(std::move(s)) }}; + return m; +} #else +static std::map text(const std::string& s) { std::map m = {{ "text", picojson::value(s) }}; -#endif return m; } +#endif -static std::map level(std::string s) { #ifdef PICOJSON_USE_RVALUE_REFERENCE +static std::map level(std::string s) { std::map m = {{ "level", picojson::value(std::move(s)) }}; + return m; +} #else +static std::map level(const std::string& s) { std::map m = {{ "level", picojson::value(s) }}; -#endif return m; } +#endif static std::string sarifSeverity(Severity::SeverityType severity) { switch (severity) { From 3b2fda22a88cf4fc67bd8a35f46659bb2c8a2bd6 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Jan 2023 13:52:34 -0600 Subject: [PATCH 46/46] Need to link the *analysisreport.o object files for testrunner. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ea67a563246..8e696ceaecf 100644 --- a/Makefile +++ b/Makefile @@ -341,7 +341,7 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ) all: cppcheck testrunner -testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o +testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/cppcheckexecutorseh.o cli/cppcheckexecutorsig.o cli/stacktrace.o cli/filelister.o cli/clianalysisreport.o cli/xmlanalysisreport.o cli/sarifanalysisreport.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC) test: all