diff --git a/Source/cmCMakeSarifLogger.cxx b/Source/cmCMakeSarifLogger.cxx index 5d594f4bd0..2d30f3e7f6 100644 --- a/Source/cmCMakeSarifLogger.cxx +++ b/Source/cmCMakeSarifLogger.cxx @@ -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> 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 LastLocation(cmListFileBacktrace backtrace, - cmake const& cm) +cm::optional LastLocation( + cmListFileBacktrace backtrace, + std::vector> const& + uriBaseIds = {}) { if (backtrace.Empty()) { return {}; } - return LocationFromContext(backtrace.Top(), cm); + return LocationFromContext(backtrace.Top(), uriBaseIds); } -cm::optional StackFromBacktrace(cmListFileBacktrace bt, - cmake const& cm) +cm::optional StackFromBacktrace( + cmListFileBacktrace bt, + std::vector> const& + uriBaseIds = {}) { if (bt.Empty()) { return {}; @@ -85,7 +103,7 @@ cm::optional 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> 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 stack = - StackFromBacktrace(message.Backtrace, this->CM)) { + StackFromBacktrace(message.Backtrace, uriBaseIds)) { result.Stacks.emplace_back(std::move(*stack)); } result.Level = SarifLevelFromMessageType(message.Type); diff --git a/Source/cmSarif.cxx b/Source/cmSarif.cxx index 1c9b81acc5..00affb6efc 100644 --- a/Source/cmSarif.cxx +++ b/Source/cmSarif.cxx @@ -3,6 +3,7 @@ #include "cmSarif.h" #include +#include #include #include @@ -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; } diff --git a/Source/cmSarif.h b/Source/cmSarif.h index bd779e736a..c18bad07c3 100644 --- a/Source/cmSarif.h +++ b/Source/cmSarif.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -170,6 +171,7 @@ struct Run { cmSarif::Tool Tool; std::vector Results; + std::unordered_map OriginalUriBaseIds; }; Json::Value GetJson(Run const& run); diff --git a/Tests/RunCMake/SarifOutput/GenerateSarifResults-expected.sarif b/Tests/RunCMake/SarifOutput/GenerateSarifResults-expected.sarif index b0f4c4a011..eecdd696f8 100644 --- a/Tests/RunCMake/SarifOutput/GenerateSarifResults-expected.sarif +++ b/Tests/RunCMake/SarifOutput/GenerateSarifResults-expected.sarif @@ -16,7 +16,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 2 @@ -43,7 +43,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 2 @@ -62,7 +62,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -87,7 +87,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 5 @@ -114,7 +114,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 5 @@ -133,7 +133,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -158,7 +158,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 11 @@ -185,7 +185,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 11 @@ -204,7 +204,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -229,7 +229,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 16 @@ -256,7 +256,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 16 @@ -275,7 +275,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -300,7 +300,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 20 @@ -327,7 +327,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 20 @@ -346,7 +346,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 24 @@ -365,7 +365,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 27 @@ -384,7 +384,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -409,7 +409,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults-Included.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 1 @@ -436,7 +436,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults-Included.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 1 @@ -455,7 +455,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 30 @@ -474,7 +474,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -499,7 +499,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 38 @@ -526,7 +526,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 38 @@ -545,7 +545,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 42 @@ -564,7 +564,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -589,7 +589,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 46 @@ -616,7 +616,7 @@ "physicalLocation": { "artifactLocation": { "uri": "GenerateSarifResults.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 46 @@ -632,7 +632,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" } } } @@ -642,6 +642,14 @@ ] } ], + "originalUriBaseIds": { + "CMAKE_BINARY_DIR": { + "uri": "file://PATH:/" + }, + "CMAKE_SOURCE_DIR": { + "uri": "file://PATH:/" + } + }, "tool": { "driver": { "name": "CMake", diff --git a/Tests/RunCMake/SarifOutput/ProjectFatalError-expected.sarif b/Tests/RunCMake/SarifOutput/ProjectFatalError-expected.sarif index 0968d5c70a..2f9463b828 100644 --- a/Tests/RunCMake/SarifOutput/ProjectFatalError-expected.sarif +++ b/Tests/RunCMake/SarifOutput/ProjectFatalError-expected.sarif @@ -16,7 +16,7 @@ "physicalLocation": { "artifactLocation": { "uri": "ProjectFatalError.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 1 @@ -43,7 +43,7 @@ "physicalLocation": { "artifactLocation": { "uri": "ProjectFatalError.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 1 @@ -62,7 +62,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -75,6 +75,14 @@ ] } ], + "originalUriBaseIds": { + "CMAKE_BINARY_DIR": { + "uri": "file://PATH:/" + }, + "CMAKE_SOURCE_DIR": { + "uri": "file://PATH:/" + } + }, "tool": { "driver": { "name": "CMake", diff --git a/Tests/RunCMake/SarifOutput/ToggleExportSarifVariable-expected.sarif b/Tests/RunCMake/SarifOutput/ToggleExportSarifVariable-expected.sarif index df80678919..436c6d4071 100644 --- a/Tests/RunCMake/SarifOutput/ToggleExportSarifVariable-expected.sarif +++ b/Tests/RunCMake/SarifOutput/ToggleExportSarifVariable-expected.sarif @@ -16,7 +16,7 @@ "physicalLocation": { "artifactLocation": { "uri": "ToggleExportSarifVariable.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 2 @@ -43,7 +43,7 @@ "physicalLocation": { "artifactLocation": { "uri": "ToggleExportSarifVariable.cmake", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 2 @@ -62,7 +62,7 @@ "physicalLocation": { "artifactLocation": { "uri": "CMakeLists.txt", - "uriBaseId": "PATH:" + "uriBaseId": "CMAKE_SOURCE_DIR" }, "region": { "startLine": 3 @@ -75,6 +75,14 @@ ] } ], + "originalUriBaseIds": { + "CMAKE_BINARY_DIR": { + "uri": "file://PATH:/" + }, + "CMAKE_SOURCE_DIR": { + "uri": "file://PATH:/" + } + }, "tool": { "driver": { "name": "CMake",