Update the SARIF exporter to SARIF 2.1

This updates the SARIF exporter to produce SARIF 2.1 output. The bulk of the diffs come from two changes to SARIF:
* https://github.com/oasis-tcs/sarif-spec/issues/309
* https://github.com/oasis-tcs/sarif-spec/issues/179

Differential Revision: https://reviews.llvm.org/D65211

llvm-svn: 370068
This commit is contained in:
Joe Ranieri 2019-08-27 14:43:54 +00:00
parent 4a2a653288
commit fce4324f92
4 changed files with 141 additions and 152 deletions

View File

@ -106,26 +106,26 @@ static std::string fileNameToURI(StringRef Filename) {
return Ret.str().str();
}
static json::Object createFileLocation(const FileEntry &FE) {
static json::Object createArtifactLocation(const FileEntry &FE) {
return json::Object{{"uri", fileNameToURI(getFileName(FE))}};
}
static json::Object createFile(const FileEntry &FE) {
return json::Object{{"fileLocation", createFileLocation(FE)},
static json::Object createArtifact(const FileEntry &FE) {
return json::Object{{"location", createArtifactLocation(FE)},
{"roles", json::Array{"resultFile"}},
{"length", FE.getSize()},
{"mimeType", "text/plain"}};
}
static json::Object createFileLocation(const FileEntry &FE,
json::Array &Files) {
static json::Object createArtifactLocation(const FileEntry &FE,
json::Array &Artifacts) {
std::string FileURI = fileNameToURI(getFileName(FE));
// See if the Files array contains this URI already. If it does not, create
// a new file object to add to the array.
auto I = llvm::find_if(Files, [&](const json::Value &File) {
// See if the Artifacts array contains this URI already. If it does not,
// create a new artifact object to add to the array.
auto I = llvm::find_if(Artifacts, [&](const json::Value &File) {
if (const json::Object *Obj = File.getAsObject()) {
if (const json::Object *FileLoc = Obj->getObject("fileLocation")) {
if (const json::Object *FileLoc = Obj->getObject("location")) {
Optional<StringRef> URI = FileLoc->getString("uri");
return URI && URI->equals(FileURI);
}
@ -133,13 +133,13 @@ static json::Object createFileLocation(const FileEntry &FE,
return false;
});
// Calculate the index within the file location array so it can be stored in
// Calculate the index within the artifact array so it can be stored in
// the JSON object.
auto Index = static_cast<unsigned>(std::distance(Files.begin(), I));
if (I == Files.end())
Files.push_back(createFile(FE));
auto Index = static_cast<unsigned>(std::distance(Artifacts.begin(), I));
if (I == Artifacts.end())
Artifacts.push_back(createArtifact(FE));
return json::Object{{"uri", FileURI}, {"fileIndex", Index}};
return json::Object{{"uri", FileURI}, {"index", Index}};
}
static json::Object createTextRegion(SourceRange R, const SourceManager &SM) {
@ -158,8 +158,9 @@ static json::Object createTextRegion(SourceRange R, const SourceManager &SM) {
static json::Object createPhysicalLocation(SourceRange R, const FileEntry &FE,
const SourceManager &SMgr,
json::Array &Files) {
return json::Object{{{"fileLocation", createFileLocation(FE, Files)},
json::Array &Artifacts) {
return json::Object{
{{"artifactLocation", createArtifactLocation(FE, Artifacts)},
{"region", createTextRegion(R, SMgr)}}};
}
@ -213,7 +214,7 @@ static Importance calculateImportance(const PathDiagnosticPiece &Piece) {
}
static json::Object createThreadFlow(const PathPieces &Pieces,
json::Array &Files) {
json::Array &Artifacts) {
const SourceManager &SMgr = Pieces.front()->getLocation().getManager();
json::Array Locations;
for (const auto &Piece : Pieces) {
@ -222,7 +223,7 @@ static json::Object createThreadFlow(const PathPieces &Pieces,
createLocation(createPhysicalLocation(
P.asRange(),
*P.asLocation().getExpansionLoc().getFileEntry(),
SMgr, Files),
SMgr, Artifacts),
Piece->getString()),
calculateImportance(*Piece)));
}
@ -230,19 +231,13 @@ static json::Object createThreadFlow(const PathPieces &Pieces,
}
static json::Object createCodeFlow(const PathPieces &Pieces,
json::Array &Files) {
json::Array &Artifacts) {
return json::Object{
{"threadFlows", json::Array{createThreadFlow(Pieces, Files)}}};
{"threadFlows", json::Array{createThreadFlow(Pieces, Artifacts)}}};
}
static json::Object createTool() {
return json::Object{{"name", "clang"},
{"fullName", "clang static analyzer"},
{"language", "en-US"},
{"version", getClangFullVersion()}};
}
static json::Object createResult(const PathDiagnostic &Diag, json::Array &Files,
static json::Object createResult(const PathDiagnostic &Diag,
json::Array &Artifacts,
const StringMap<unsigned> &RuleMapping) {
const PathPieces &Path = Diag.path.flatten(false);
const SourceManager &SMgr = Path.front()->getLocation().getManager();
@ -252,12 +247,12 @@ static json::Object createResult(const PathDiagnostic &Diag, json::Array &Files,
return json::Object{
{"message", createMessage(Diag.getVerboseDescription())},
{"codeFlows", json::Array{createCodeFlow(Path, Files)}},
{"codeFlows", json::Array{createCodeFlow(Path, Artifacts)}},
{"locations",
json::Array{createLocation(createPhysicalLocation(
Diag.getLocation().asRange(),
*Diag.getLocation().asLocation().getExpansionLoc().getFileEntry(),
SMgr, Files))}},
SMgr, Artifacts))}},
{"ruleIndex", Iter->getValue()},
{"ruleId", Diag.getCheckName()}};
}
@ -288,7 +283,7 @@ static json::Object createRule(const PathDiagnostic &Diag) {
StringRef CheckName = Diag.getCheckName();
json::Object Ret{
{"fullDescription", createMessage(getRuleDescription(CheckName))},
{"name", createMessage(CheckName)},
{"name", CheckName},
{"id", CheckName}};
std::string RuleURI = getRuleHelpURIStr(CheckName);
@ -315,24 +310,28 @@ static json::Array createRules(std::vector<const PathDiagnostic *> &Diags,
return Rules;
}
static json::Object createResources(std::vector<const PathDiagnostic *> &Diags,
static json::Object createTool(std::vector<const PathDiagnostic *> &Diags,
StringMap<unsigned> &RuleMapping) {
return json::Object{{"rules", createRules(Diags, RuleMapping)}};
return json::Object{
{"driver", json::Object{{"name", "clang"},
{"fullName", "clang static analyzer"},
{"language", "en-US"},
{"version", getClangFullVersion()},
{"rules", createRules(Diags, RuleMapping)}}}};
}
static json::Object createRun(std::vector<const PathDiagnostic *> &Diags) {
json::Array Results, Files;
json::Array Results, Artifacts;
StringMap<unsigned> RuleMapping;
json::Object Resources = createResources(Diags, RuleMapping);
json::Object Tool = createTool(Diags, RuleMapping);
llvm::for_each(Diags, [&](const PathDiagnostic *D) {
Results.push_back(createResult(*D, Files, RuleMapping));
Results.push_back(createResult(*D, Artifacts, RuleMapping));
});
return json::Object{{"tool", createTool()},
{"resources", std::move(Resources)},
return json::Object{{"tool", std::move(Tool)},
{"results", std::move(Results)},
{"files", std::move(Files)}};
{"artifacts", std::move(Artifacts)}};
}
void SarifDiagnostics::FlushDiagnosticsImpl(
@ -350,8 +349,8 @@ void SarifDiagnostics::FlushDiagnosticsImpl(
}
json::Object Sarif{
{"$schema",
"http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28"},
{"version", "2.0.0-csd.2.beta.2018-11-28"},
"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"},
{"version", "2.1.0"},
{"runs", json::Array{createRun(Diags)}}};
OS << llvm::formatv("{0:2}\n", json::Value(std::move(Sarif)));
}

View File

@ -1,31 +1,18 @@
{
"$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"runs": [
{
"files": [
"artifacts": [
{
"fileLocation": {
},
"length": 434,
"location": {
},
"mimeType": "text/plain",
"roles": [
"resultFile"
]
}
],
"resources": {
"rules": [
{
"fullDescription": {
"text": "Mark tainted symbols as such."
},
"id": "debug.TaintTest",
"name": {
"text": "debug.TaintTest"
}
}
]
},
"results": [
{
"codeFlows": [
@ -40,8 +27,8 @@
"text": "Calling 'f'"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 6,
@ -59,8 +46,8 @@
"text": "tainted"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 18,
@ -79,8 +66,8 @@
"locations": [
{
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 18,
@ -99,9 +86,20 @@
}
],
"tool": {
"driver": {
"fullName": "clang static analyzer",
"language": "en-US",
"name": "clang",
"rules": [
{
"fullDescription": {
"text": "Mark tainted symbols as such."
},
"id": "debug.TaintTest",
"name": "debug.TaintTest"
}
],
}
}
}
],

View File

@ -1,61 +1,18 @@
{
"$schema": "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"runs": [
{
"files": [
"artifacts": [
{
"fileLocation": {
},
"length": 951,
"location": {
},
"mimeType": "text/plain",
"roles": [
"resultFile"
]
}
],
"resources": {
"rules": [
{
"fullDescription": {
"text": "Mark tainted symbols as such."
},
"id": "debug.TaintTest",
"name": {
"text": "debug.TaintTest"
}
},
{
"fullDescription": {
"text": "Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)"
},
"helpUri": "https://clang-analyzer.llvm.org/available_checks.html#core.CallAndMessage",
"id": "core.CallAndMessage",
"name": {
"text": "core.CallAndMessage"
}
},
{
"fullDescription": {
"text": "Check for division by zero"
},
"helpUri": "https://clang-analyzer.llvm.org/available_checks.html#core.DivideZero",
"id": "core.DivideZero",
"name": {
"text": "core.DivideZero"
}
},
{
"fullDescription": {
"text": "Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free()."
},
"helpUri": "https://clang-analyzer.llvm.org/available_checks.html#unix.Malloc",
"id": "unix.Malloc",
"name": {
"text": "unix.Malloc"
}
}
]
},
"results": [
{
"codeFlows": [
@ -70,8 +27,8 @@
"text": "Calling 'f'"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 6,
@ -89,8 +46,8 @@
"text": "tainted"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 18,
@ -109,8 +66,8 @@
"locations": [
{
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 18,
@ -140,8 +97,8 @@
"text": "Calling 'g'"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 6,
@ -159,8 +116,8 @@
"text": "'fp' declared without an initial value"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 11,
@ -178,8 +135,8 @@
"text": "Called function pointer is an uninitialized pointer value"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 9,
@ -198,8 +155,8 @@
"locations": [
{
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 9,
@ -229,8 +186,8 @@
"text": "Assuming 'i' is equal to 0"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 13,
@ -248,8 +205,8 @@
"text": "Taking true branch"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 3,
@ -266,8 +223,8 @@
"text": "Division by zero"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 14,
@ -285,8 +242,8 @@
"locations": [
{
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 14,
@ -315,8 +272,8 @@
"text": "Memory is allocated"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 24,
@ -334,8 +291,8 @@
"text": "Assuming 'i' is < 4"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 12,
@ -353,8 +310,8 @@
"text": "Taking true branch"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 3,
@ -371,8 +328,8 @@
"text": "Potential leak of memory pointed to by 'mem'"
},
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 12,
@ -390,8 +347,8 @@
"locations": [
{
"physicalLocation": {
"fileLocation": {
"fileIndex": 0,
"artifactLocation": {
"index": 0,
},
"region": {
"endColumn": 12,
@ -409,9 +366,44 @@
}
],
"tool": {
"driver": {
"fullName": "clang static analyzer",
"language": "en-US",
"name": "clang",
"rules": [
{
"fullDescription": {
"text": "Mark tainted symbols as such."
},
"id": "debug.TaintTest",
"name": "debug.TaintTest"
},
{
"fullDescription": {
"text": "Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)"
},
"helpUri": "https://clang-analyzer.llvm.org/available_checks.html#core.CallAndMessage",
"id": "core.CallAndMessage",
"name": "core.CallAndMessage"
},
{
"fullDescription": {
"text": "Check for division by zero"
},
"helpUri": "https://clang-analyzer.llvm.org/available_checks.html#core.DivideZero",
"id": "core.DivideZero",
"name": "core.DivideZero"
},
{
"fullDescription": {
"text": "Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free()."
},
"helpUri": "https://clang-analyzer.llvm.org/available_checks.html#unix.Malloc",
"id": "unix.Malloc",
"name": "unix.Malloc"
}
],
}
}
}
],

View File

@ -22,7 +22,7 @@ config.substitutions.append(('%normalize_sarif',
"grep -Ev '^[[:space:]]*(%s|%s|%s)[[:space:]]*$'" %
('"uri": "file:.*%basename_t"',
'"version": ".* version .*"',
'"version": "2\.0\.0-csd\.[0-9]*\.beta\.[0-9-]{10}"')))
'"version": "2.1.0"')))
if not config.root.clang_staticanalyzer:
config.unsupported = True