SARIF: Report named base directory paths

Result locations in the SARIF log are now reported relative to a named logical
base defined in the run log.
This commit is contained in:
Daniel Tierney
2026-07-02 12:07:29 -04:00
parent 1cc963776b
commit 9a524ded0c
6 changed files with 128 additions and 52 deletions

View File

@@ -31,21 +31,35 @@ namespace {
constexpr char const* CMakeSarifOutputFlag = "CMAKE_EXPORT_SARIF";
constexpr char const* DefaultSarifFile = ".cmake/sarif/cmake.sarif";
cmSarif::Location LocationFromContext(cmListFileContext const& lfc,
cmake const& cm)
/// @brief Express the location of a `cmListFileContext` in SARIF
/// @param[in] uriBaseIds A list of logical base directory names and their path
///
/// Build a SARIF location object detailing the location data available from a
/// context. More specific information like the region (line number) and
/// function call name will be included if available.
///
/// SARIF requests that paths are given relative to a logical base for
/// relocatability. Context locations will be made relative to a logical base
/// iff they fall under one of the directories listed in the `uriBaseIds`
/// map. Bases are tried in order.
cmSarif::Location LocationFromContext(
cmListFileContext const& lfc,
std::vector<std::pair<cm::string_view, cm::string_view>> const&
uriBaseIds = {})
{
cmSarif::Location location;
location.Physical.Artifact.Uri = lfc.FilePath;
// SARIF requests that paths are given relative to a logical base for
// relocatability.
// Use the CMake home directory as a base dir for files under it.
std::string const& cmHomeDir = cm.GetHomeDirectory();
std::string relative =
cmSystemTools::RelativeIfUnder(cmHomeDir, location.Physical.Artifact.Uri);
if (relative != location.Physical.Artifact.Uri) {
location.Physical.Artifact.Uri = relative;
location.Physical.Artifact.UriBaseId = cmHomeDir;
// relocatability. Check if these files are under any of the bases, if
// provided.
for (auto const& baseUri : uriBaseIds) {
std::string relative = cmSystemTools::RelativeIfUnder(
std::string(baseUri.second), location.Physical.Artifact.Uri);
if (relative != location.Physical.Artifact.Uri) {
location.Physical.Artifact.Uri = relative;
location.Physical.Artifact.UriBaseId = std::string(baseUri.first);
}
}
if (!lfc.Name.empty()) {
@@ -67,17 +81,21 @@ cmSarif::Location LocationFromContext(cmListFileContext const& lfc,
return location;
}
cm::optional<cmSarif::Location> LastLocation(cmListFileBacktrace backtrace,
cmake const& cm)
cm::optional<cmSarif::Location> LastLocation(
cmListFileBacktrace backtrace,
std::vector<std::pair<cm::string_view, cm::string_view>> const&
uriBaseIds = {})
{
if (backtrace.Empty()) {
return {};
}
return LocationFromContext(backtrace.Top(), cm);
return LocationFromContext(backtrace.Top(), uriBaseIds);
}
cm::optional<cmSarif::Stack> StackFromBacktrace(cmListFileBacktrace bt,
cmake const& cm)
cm::optional<cmSarif::Stack> StackFromBacktrace(
cmListFileBacktrace bt,
std::vector<std::pair<cm::string_view, cm::string_view>> const&
uriBaseIds = {})
{
if (bt.Empty()) {
return {};
@@ -85,7 +103,7 @@ cm::optional<cmSarif::Stack> StackFromBacktrace(cmListFileBacktrace bt,
cmSarif::Stack stack;
for (; !bt.Empty(); bt = bt.Pop()) {
cmSarif::Location topLocation = LocationFromContext(bt.Top(), cm);
cmSarif::Location topLocation = LocationFromContext(bt.Top(), uriBaseIds);
// If the location doesn't have a specific region, this entry is a
// placeholder and should not appear in the call stack.
@@ -248,6 +266,27 @@ bool cmCMakeSarifLogger::WriteFile(std::string const& path,
return *result.first;
};
// Make a prioritized list of base directories applicable in this context.
// This is used for normalizing the paths of related locations.
std::vector<std::pair<cm::string_view, cm::string_view>> uriBaseIds;
std::string const& binDir = this->CM.GetHomeOutputDirectory();
if (!binDir.empty()) {
uriBaseIds.emplace_back("CMAKE_BINARY_DIR", binDir);
}
std::string const& homeDir = this->CM.GetHomeDirectory();
if (!homeDir.empty()) {
uriBaseIds.emplace_back("CMAKE_SOURCE_DIR", homeDir);
}
// Log the base directories for this run.
for (auto const& base : uriBaseIds) {
run.OriginalUriBaseIds.emplace(
std::string(base.first),
cmSarif::ArtifactLocation{ cmStrCat("file://", base.second, "/"), "" });
}
cmMessenger const& messenger = *this->CM.GetMessenger();
for (auto const& message : messenger.GetDisplayedMessages()) {
// SARIF should only emit diagnostic messages, not general messages/logs
@@ -267,9 +306,9 @@ bool cmCMakeSarifLogger::WriteFile(std::string const& path,
result.RuleId = ruleInfo.first;
result.RuleIndex = ruleInfo.second;
result.Message = cmSarif::Message{ message.Text };
result.Location = LastLocation(message.Backtrace, this->CM);
result.Location = LastLocation(message.Backtrace, uriBaseIds);
if (cm::optional<cmSarif::Stack> stack =
StackFromBacktrace(message.Backtrace, this->CM)) {
StackFromBacktrace(message.Backtrace, uriBaseIds)) {
result.Stacks.emplace_back(std::move(*stack));
}
result.Level = SarifLevelFromMessageType(message.Type);

View File

@@ -3,6 +3,7 @@
#include "cmSarif.h"
#include <memory>
#include <utility>
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
@@ -181,11 +182,21 @@ Json::Value GetJson(Run const& run)
{
Json::Value runJson(Json::objectValue);
runJson["tool"] = cmSarif::GetJson(run.Tool);
if (!run.OriginalUriBaseIds.empty()) {
Json::Value uriBaseIds(Json::objectValue);
for (auto const& base : run.OriginalUriBaseIds) {
uriBaseIds[base.first] = cmSarif::GetJson(base.second);
}
runJson["originalUriBaseIds"] = uriBaseIds;
}
Json::Value results(Json::arrayValue);
for (auto const& result : run.Results) {
results.append(cmSarif::GetJson(result));
}
runJson["results"] = results;
return runJson;
}

View File

@@ -2,6 +2,7 @@
#include <cstddef>
#include <string>
#include <unordered_map>
#include <vector>
#include <cm/optional>
@@ -170,6 +171,7 @@ struct Run
{
cmSarif::Tool Tool;
std::vector<Result> Results;
std::unordered_map<std::string, ArtifactLocation> OriginalUriBaseIds;
};
Json::Value GetJson(Run const& run);

View File

@@ -16,7 +16,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
@@ -43,7 +43,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
@@ -62,7 +62,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -87,7 +87,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 5
@@ -114,7 +114,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 5
@@ -133,7 +133,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -158,7 +158,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 11
@@ -185,7 +185,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 11
@@ -204,7 +204,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -229,7 +229,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 16
@@ -256,7 +256,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 16
@@ -275,7 +275,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -300,7 +300,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 20
@@ -327,7 +327,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 20
@@ -346,7 +346,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 24
@@ -365,7 +365,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 27
@@ -384,7 +384,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -409,7 +409,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults-Included.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
@@ -436,7 +436,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults-Included.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
@@ -455,7 +455,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 30
@@ -474,7 +474,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -499,7 +499,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 38
@@ -526,7 +526,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 38
@@ -545,7 +545,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 42
@@ -564,7 +564,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -589,7 +589,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 46
@@ -616,7 +616,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 46
@@ -632,7 +632,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
}
}
}
@@ -642,6 +642,14 @@
]
}
],
"originalUriBaseIds": {
"CMAKE_BINARY_DIR": {
"uri": "file://PATH:<BINARY_DIR>/"
},
"CMAKE_SOURCE_DIR": {
"uri": "file://PATH:<SOURCE_DIR>/"
}
},
"tool": {
"driver": {
"name": "CMake",

View File

@@ -16,7 +16,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "ProjectFatalError.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
@@ -43,7 +43,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "ProjectFatalError.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
@@ -62,7 +62,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -75,6 +75,14 @@
]
}
],
"originalUriBaseIds": {
"CMAKE_BINARY_DIR": {
"uri": "file://PATH:<BINARY_DIR>/"
},
"CMAKE_SOURCE_DIR": {
"uri": "file://PATH:<SOURCE_DIR>/"
}
},
"tool": {
"driver": {
"name": "CMake",

View File

@@ -16,7 +16,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "ToggleExportSarifVariable.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
@@ -43,7 +43,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "ToggleExportSarifVariable.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
@@ -62,7 +62,7 @@
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
@@ -75,6 +75,14 @@
]
}
],
"originalUriBaseIds": {
"CMAKE_BINARY_DIR": {
"uri": "file://PATH:<BINARY_DIR>/"
},
"CMAKE_SOURCE_DIR": {
"uri": "file://PATH:<SOURCE_DIR>/"
}
},
"tool": {
"driver": {
"name": "CMake",