Skip to content

Commit f6f4d25

Browse files
committed
move sarif reporter to its own class so it can be used for tests, change tests so it doesnt need to run executable
1 parent ca1b522 commit f6f4d25

4 files changed

Lines changed: 322 additions & 288 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ frontend/frontend.o: frontend/frontend.cpp frontend/frontend.h lib/addoninfo.h l
667667
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h lib/xml.h
668668
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp
669669

670-
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
670+
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h cli/sarifreport.h cli/sehwrapper.h cli/signalhandler.h cli/singleexecutor.h cli/threadexecutor.h externals/picojson/picojson.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
671671
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp
672672

673673
cli/executor.o: cli/executor.cpp cli/executor.h lib/addoninfo.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
@@ -835,7 +835,7 @@ test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/proc
835835
test/testprogrammemory.o: test/testprogrammemory.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/settings.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
836836
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprogrammemory.cpp
837837

838-
test/testsarif.o: test/testsarif.cpp externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
838+
test/testsarif.o: test/testsarif.cpp cli/sarifreport.h externals/picojson/picojson.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/json.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
839839
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsarif.cpp
840840

841841
test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h

cli/cppcheckexecutor.cpp

Lines changed: 1 addition & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "errortypes.h"
3434
#include "filesettings.h"
3535
#include "json.h"
36+
#include "sarifreport.h"
3637
#include "settings.h"
3738
#include "singleexecutor.h"
3839
#include "suppressions.h"
@@ -78,189 +79,6 @@
7879
#endif
7980

8081
namespace {
81-
class SarifReport {
82-
public:
83-
void addFinding(ErrorMessage msg) {
84-
mFindings.push_back(std::move(msg));
85-
}
86-
87-
picojson::array serializeRules() const {
88-
picojson::array ret;
89-
std::set<std::string> ruleIds;
90-
for (const auto& finding : mFindings) {
91-
// github only supports findings with locations
92-
if (finding.callStack.empty())
93-
continue;
94-
if (ruleIds.insert(finding.id).second) {
95-
// setting name and description to empty strings will make github default
96-
// to the instance specific violation message and not rule description,
97-
// this makes it so not all the violations have the same description.
98-
picojson::object rule;
99-
rule["id"] = picojson::value(finding.id);
100-
// rule.name
101-
rule["name"] = picojson::value("");
102-
// rule.shortDescription.text
103-
picojson::object shortDescription;
104-
shortDescription["text"] = picojson::value("");
105-
rule["shortDescription"] = picojson::value(shortDescription);
106-
// rule.fullDescription.text
107-
picojson::object fullDescription;
108-
fullDescription["text"] = picojson::value("");
109-
rule["fullDescription"] = picojson::value(fullDescription);
110-
// rule.help.text
111-
picojson::object help;
112-
help["text"] = picojson::value("");
113-
rule["help"] = picojson::value(help);
114-
// rule.properties.precision, rule.properties.problem.severity
115-
picojson::object properties;
116-
properties["precision"] = picojson::value(sarifPrecision(finding));
117-
// rule.properties.security-severity, rule.properties.tags
118-
picojson::array tags;
119-
120-
// If we have a CWE ID, treat it as security-related (CWE is the authoritative source for security weaknesses)
121-
if (finding.cwe.id > 0) {
122-
double securitySeverity = 0;
123-
if (finding.severity == Severity::error && !ErrorLogger::isCriticalErrorId(finding.id)) {
124-
securitySeverity = 9.9; // critical = 9.0+
125-
}
126-
else if (finding.severity == Severity::warning) {
127-
securitySeverity = 8.5; // high = 7.0 to 8.9
128-
}
129-
else if (finding.severity == Severity::performance || finding.severity == Severity::portability ||
130-
finding.severity == Severity::style) {
131-
securitySeverity = 5.5; // medium = 4.0 to 6.9
132-
}
133-
else if (finding.severity == Severity::information || finding.severity == Severity::internal ||
134-
finding.severity == Severity::debug || finding.severity == Severity::none) {
135-
securitySeverity = 2.0; // low = 0.1 to 3.9
136-
}
137-
if (securitySeverity > 0.0) {
138-
std::ostringstream ss;
139-
ss << securitySeverity;
140-
properties["security-severity"] = picojson::value(ss.str());
141-
tags.emplace_back("external/cwe/cwe-" + std::to_string(finding.cwe.id));
142-
tags.emplace_back("security");
143-
}
144-
}
145-
146-
// Add tags array if it has any content
147-
if (!tags.empty()) {
148-
properties["tags"] = picojson::value(tags);
149-
}
150-
151-
// Set problem.severity for use with github
152-
const std::string problemSeverity = sarifSeverity(finding);
153-
properties["problem.severity"] = picojson::value(problemSeverity);
154-
rule["properties"] = picojson::value(properties);
155-
// rule.defaultConfiguration.level
156-
picojson::object defaultConfiguration;
157-
defaultConfiguration["level"] = picojson::value(sarifSeverity(finding));
158-
rule["defaultConfiguration"] = picojson::value(defaultConfiguration);
159-
160-
ret.emplace_back(rule);
161-
}
162-
}
163-
return ret;
164-
}
165-
166-
static picojson::array serializeLocations(const ErrorMessage& finding) {
167-
picojson::array ret;
168-
for (const auto& location : finding.callStack) {
169-
picojson::object physicalLocation;
170-
picojson::object artifactLocation;
171-
artifactLocation["uri"] = picojson::value(location.getfile(false));
172-
physicalLocation["artifactLocation"] = picojson::value(artifactLocation);
173-
picojson::object region;
174-
region["startLine"] = picojson::value(static_cast<int64_t>(location.line < 1 ? 1 : location.line));
175-
region["startColumn"] = picojson::value(static_cast<int64_t>(location.column < 1 ? 1 : location.column));
176-
region["endLine"] = region["startLine"];
177-
region["endColumn"] = region["startColumn"];
178-
physicalLocation["region"] = picojson::value(region);
179-
picojson::object loc;
180-
loc["physicalLocation"] = picojson::value(physicalLocation);
181-
ret.emplace_back(loc);
182-
}
183-
return ret;
184-
}
185-
186-
picojson::array serializeResults() const {
187-
picojson::array results;
188-
for (const auto& finding : mFindings) {
189-
// github only supports findings with locations
190-
if (finding.callStack.empty())
191-
continue;
192-
picojson::object res;
193-
res["level"] = picojson::value(sarifSeverity(finding));
194-
res["locations"] = picojson::value(serializeLocations(finding));
195-
picojson::object message;
196-
message["text"] = picojson::value(finding.shortMessage());
197-
res["message"] = picojson::value(message);
198-
res["ruleId"] = picojson::value(finding.id);
199-
results.emplace_back(res);
200-
}
201-
return results;
202-
}
203-
204-
picojson::value serializeRuns(const std::string& productName, const std::string& version) const {
205-
picojson::object driver;
206-
driver["name"] = picojson::value(productName);
207-
driver["semanticVersion"] = picojson::value(version);
208-
driver["informationUri"] = picojson::value("https://cppcheck.sourceforge.io");
209-
driver["rules"] = picojson::value(serializeRules());
210-
picojson::object tool;
211-
tool["driver"] = picojson::value(driver);
212-
picojson::object run;
213-
run["tool"] = picojson::value(tool);
214-
run["results"] = picojson::value(serializeResults());
215-
picojson::array runs{picojson::value(run)};
216-
return picojson::value(runs);
217-
}
218-
219-
std::string serialize(std::string productName) const {
220-
const auto nameAndVersion = Settings::getNameAndVersion(productName);
221-
productName = nameAndVersion.first.empty() ? "Cppcheck" : nameAndVersion.first;
222-
std::string version = nameAndVersion.first.empty() ? CppCheck::version() : nameAndVersion.second;
223-
if (version.find(' ') != std::string::npos)
224-
version.erase(version.find(' '), std::string::npos);
225-
226-
picojson::object doc;
227-
doc["version"] = picojson::value("2.1.0");
228-
doc["$schema"] = picojson::value("https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json");
229-
doc["runs"] = serializeRuns(productName, version);
230-
231-
return picojson::value(doc).serialize(true);
232-
}
233-
234-
private:
235-
static std::string sarifSeverity(const ErrorMessage& errmsg) {
236-
if (ErrorLogger::isCriticalErrorId(errmsg.id))
237-
return "error";
238-
switch (errmsg.severity) {
239-
case Severity::error:
240-
case Severity::warning:
241-
return "error";
242-
case Severity::style:
243-
case Severity::portability:
244-
case Severity::performance:
245-
return "warning";
246-
case Severity::information:
247-
case Severity::internal:
248-
case Severity::debug:
249-
case Severity::none:
250-
return "note";
251-
}
252-
return "note";
253-
}
254-
255-
static std::string sarifPrecision(const ErrorMessage& errmsg) {
256-
if (errmsg.certainty == Certainty::inconclusive)
257-
return "medium";
258-
return "high";
259-
}
260-
261-
std::vector<ErrorMessage> mFindings;
262-
};
263-
26482
class CmdLineLoggerStd : public CmdLineLogger
26583
{
26684
public:

0 commit comments

Comments
 (0)