Merge topic 'sarif-stack-trace'

9a524ded0c SARIF: Report named base directory paths
1cc963776b SARIF: Report call stacks with results
38e0434c9a Instrumentation: Write cmakeInstall snippet on interrupted install

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !12242
This commit is contained in:
Brad King
2026-07-14 13:15:37 +00:00
committed by Kitware Robot
13 changed files with 1027 additions and 69 deletions

View File

@@ -31,38 +31,91 @@ namespace {
constexpr char const* CMakeSarifOutputFlag = "CMAKE_EXPORT_SARIF";
constexpr char const* DefaultSarifFile = ".cmake/sarif/cmake.sarif";
cm::optional<cmSarif::Location> GetLocationFromBacktrace(
cmListFileBacktrace const& backtrace, 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. 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()) {
location.Logical.emplace_back(
cmSarif::LogicalLocation{ lfc.Name, cmSarif::LocationKind::Function });
}
// Add info about the region within the file depending on how specific the
// context is. Watch for deferred call and variable watch placeholders or
// a zero, which indicates the start of processing a list file.
if (lfc.Line == cmListFileContext::DeferPlaceholderLine) {
location.Message = cmSarif::Message{ "DEFERRED" };
} else if (lfc.Line > 0 && lfc.Line != std::numeric_limits<long>::max()) {
cmSarif::Region region;
region.StartLine = lfc.Line;
location.Physical.ArtifactRegion = region;
}
return location;
}
cm::optional<cmSarif::Location> LastLocation(
cmListFileBacktrace backtrace,
std::vector<std::pair<cm::string_view, cm::string_view>> const&
uriBaseIds = {})
{
if (backtrace.Empty()) {
return {};
}
cmListFileContext const& lfc = backtrace.Top();
// Exclude frames with no real location: negative lines are deferred-call
// placeholders, and LONG_MAX is the synthetic line used by variable_watch
// callback dispatch. Neither is a meaningful source location.
if (lfc.Line < 0 || lfc.Line == std::numeric_limits<long>::max()) {
return LocationFromContext(backtrace.Top(), uriBaseIds);
}
cm::optional<cmSarif::Stack> StackFromBacktrace(
cmListFileBacktrace bt,
std::vector<std::pair<cm::string_view, cm::string_view>> const&
uriBaseIds = {})
{
if (bt.Empty()) {
return {};
}
cmSarif::PhysicalLocation location;
location.Artifact.Uri = lfc.FilePath;
cmSarif::Stack stack;
for (; !bt.Empty(); bt = bt.Pop()) {
cmSarif::Location topLocation = LocationFromContext(bt.Top(), uriBaseIds);
// SARIF requests that paths are given relative to a logical base. Report
// paths relative to the source dir / script working directory if possible.
location.Artifact.UriBaseId = cm.GetHomeDirectory();
std::string relative = cmSystemTools::RelativePath(
location.Artifact.UriBaseId, location.Artifact.Uri);
if (!relative.empty()) {
location.Artifact.Uri = relative;
}
// If the location doesn't have a specific region, this entry is a
// placeholder and should not appear in the call stack.
if (!topLocation.Message && !topLocation.Physical.ArtifactRegion) {
continue;
}
if (lfc.Line != 0) {
cmSarif::Region region;
region.StartLine = lfc.Line;
location.ArtifactRegion = region;
cmSarif::StackFrame frame;
frame.Location = std::move(topLocation);
stack.Frames.emplace_back(std::move(frame));
}
return cmSarif::Location{ location };
return stack;
}
cmSarif::Tool CreateCMakeTool()
@@ -213,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
@@ -231,8 +305,12 @@ bool cmCMakeSarifLogger::WriteFile(std::string const& path,
cmSarif::Result result;
result.RuleId = ruleInfo.first;
result.RuleIndex = ruleInfo.second;
result.Message = message.Text;
result.Location = GetLocationFromBacktrace(message.Backtrace, this->CM);
result.Message = cmSarif::Message{ message.Text };
result.Location = LastLocation(message.Backtrace, uriBaseIds);
if (cm::optional<cmSarif::Stack> stack =
StackFromBacktrace(message.Backtrace, uriBaseIds)) {
result.Stacks.emplace_back(std::move(*stack));
}
result.Level = SarifLevelFromMessageType(message.Type);
run.Results.emplace_back(std::move(result));

View File

@@ -3,6 +3,7 @@
#include "cmSarif.h"
#include <memory>
#include <utility>
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
@@ -31,6 +32,13 @@ Json::Value GetJson(ResultSeverityLevel level)
}
}
Json::Value GetJson(Message const& message)
{
Json::Value obj(Json::objectValue);
obj["text"] = message.Text;
return obj;
}
Json::Value GetJson(ArtifactLocation const& artifactLocation)
{
Json::Value obj(Json::objectValue);
@@ -58,13 +66,54 @@ Json::Value GetJson(PhysicalLocation const& physicalLocation)
return obj;
}
Json::Value GetJson(LogicalLocation const& logicalLocation)
{
Json::Value obj(Json::objectValue);
obj["name"] = logicalLocation.Name;
if (!logicalLocation.Kind.empty()) {
obj["kind"] = std::string(logicalLocation.Kind);
}
return obj;
}
Json::Value GetJson(Location const& location)
{
Json::Value obj(Json::objectValue);
obj["physicalLocation"] = cmSarif::GetJson(location.Physical);
if (!location.Logical.empty()) {
Json::Value logical(Json::arrayValue);
for (auto const& loc : location.Logical) {
logical.append(cmSarif::GetJson(loc));
}
obj["logicalLocations"] = logical;
}
if (location.Message) {
obj["message"] = cmSarif::GetJson(*location.Message);
}
return obj;
}
Json::Value GetJson(StackFrame const& frame)
{
Json::Value frameJson(Json::objectValue);
if (frame.Location) {
frameJson["location"] = cmSarif::GetJson(*frame.Location);
}
return frameJson;
}
Json::Value GetJson(Stack const& stack)
{
Json::Value stackJson(Json::objectValue);
Json::Value frames(Json::arrayValue);
for (auto const& frame : stack.Frames) {
frames.append(cmSarif::GetJson(frame));
}
stackJson["frames"] = frames;
return stackJson;
}
Json::Value GetJson(ReportingDescriptor const& reportingDescriptor)
{
Json::Value rd(Json::objectValue);
@@ -80,7 +129,7 @@ Json::Value GetJson(Result const& result)
Json::Value resultJson(Json::objectValue);
if (result.Message) {
resultJson["message"]["text"] = *result.Message;
resultJson["message"] = cmSarif::GetJson(*result.Message);
}
if (result.Level) {
@@ -98,6 +147,14 @@ Json::Value GetJson(Result const& result)
resultJson["locations"][0] = cmSarif::GetJson(*result.Location);
}
if (!result.Stacks.empty()) {
Json::Value stacks(Json::arrayValue);
for (auto const& stack : result.Stacks) {
stacks.append(cmSarif::GetJson(stack));
}
resultJson["stacks"] = stacks;
}
return resultJson;
}
@@ -125,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,9 +2,12 @@
#include <cstddef>
#include <string>
#include <unordered_map>
#include <vector>
#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include <cm3p/json/value.h>
@@ -25,6 +28,14 @@ enum class ResultSeverityLevel
Json::Value GetJson(ResultSeverityLevel level);
/// @brief SARIF message object (§3.11)
struct Message
{
std::string Text;
};
Json::Value GetJson(Message const& message);
/// @brief SARIF artifactLocation object (§3.4)
struct ArtifactLocation
{
@@ -51,14 +62,55 @@ struct PhysicalLocation
Json::Value GetJson(PhysicalLocation const& physicalLocation);
/// @brief Suggested values for the logical location `kind` property (§3.33.7)
///
/// The SARIF-recommended terminology for identifying the type of construct at
/// the associated location. This namespace is for defining the SARIF-specified
/// vocabulary only (although the actual `kind` property can be any string).
namespace LocationKind {
cm::string_view const Function = "function"_s;
}
/// @brief SARIF logicalLocation object (§3.33)
struct LogicalLocation
{
std::string Name;
/// @brief The type of construct identified by the logical location
///
/// The value should be from the suggestions in §3.33.7 but can be any string
/// if none of the specified suggestions apply. See `cmSarif::LocationKind`
/// for the suggested values.
cm::string_view Kind;
};
Json::Value GetJson(LogicalLocation const& logicalLocation);
/// @brief SARIF location object (§3.28)
struct Location
{
PhysicalLocation Physical;
std::vector<LogicalLocation> Logical;
cm::optional<cmSarif::Message> Message;
};
Json::Value GetJson(Location const& location);
struct StackFrame
{
cm::optional<cmSarif::Location> Location;
std::vector<std::string> Parameters;
};
Json::Value GetJson(StackFrame const& stackFrame);
struct Stack
{
std::vector<StackFrame> Frames;
};
Json::Value GetJson(Stack const& stack);
/// @brief A result reported by a run of a static analysis tool
///
/// This is the data model for results in a SARIF log. Typically, a result only
@@ -66,11 +118,14 @@ Json::Value GetJson(Location const& location);
struct Result
{
/// @brief The message text of the result (required if no rule index)
cm::optional<std::string> Message;
cm::optional<cmSarif::Message> Message;
/// @brief The location of the result (optional)
cm::optional<cmSarif::Location> Location;
/// @brief Call stacks related to the result (optional)
std::vector<cmSarif::Stack> Stacks;
/// @brief The severity level of the result (optional)
cm::optional<cmSarif::ResultSeverityLevel> Level;
@@ -86,7 +141,7 @@ Json::Value GetJson(Result const& result);
/// @brief A reporting descriptor provides information about an analysis result
///
/// Reporting descriptors (SARIF specification section 3.49) provide
/// information about categories of reporting items and is used to define
/// information about categories of reporting items and are used to define
/// rules and taxa.
struct ReportingDescriptor
{
@@ -116,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

@@ -0,0 +1 @@
message(WARNING "Warning from an included file")

View File

@@ -7,10 +7,16 @@
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
@@ -22,16 +28,66 @@
"text": "Example warning message"
},
"ruleId": "CMake.Warning",
"ruleIndex": 0
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 5
@@ -43,16 +99,66 @@
"text": "A second example warning message"
},
"ruleId": "CMake.Warning",
"ruleIndex": 0
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 5
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 11
@@ -64,16 +170,66 @@
"text": "Example author warning message"
},
"ruleId": "CMake.Author",
"ruleIndex": 1
"ruleIndex": 1,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 11
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "error",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 16
@@ -85,9 +241,415 @@
"text": "Another example author warning message"
},
"ruleId": "CMake.Author",
"ruleIndex": 1
"ruleIndex": 1,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 16
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 20
}
}
}
],
"message": {
"text": "Warning from a nested function call"
},
"ruleId": "CMake.Warning",
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 20
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "a"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 24
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "b"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 27
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults-Included.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
}
}
}
],
"message": {
"text": "Warning from an included file"
},
"ruleId": "CMake.Warning",
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults-Included.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 30
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 38
}
}
}
],
"message": {
"text": "Warning from a variable_watch callback"
},
"ruleId": "CMake.Warning",
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 38
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "set"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 42
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
},
{
"level": "error",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 46
}
}
}
],
"message": {
"text": "Encabulator: a deferred error"
},
"ruleId": "CMake.FatalError",
"ruleIndex": 2,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "GenerateSarifResults.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 46
}
}
}
},
{
"location": {
"message": {
"text": "DEFERRED"
},
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
}
}
}
}
]
}
]
}
],
"originalUriBaseIds": {
"CMAKE_BINARY_DIR": {
"uri": "file://PATH:<BINARY_DIR>/"
},
"CMAKE_SOURCE_DIR": {
"uri": "file://PATH:<SOURCE_DIR>/"
}
},
"tool": {
"driver": {
"name": "CMake",
@@ -99,6 +661,10 @@
{
"id": "CMake.Author",
"name": "CMD_AUTHOR"
},
{
"id": "CMake.FatalError",
"name": "CMake Error"
}
],
"version": "<IGNORE>"

View File

@@ -18,4 +18,29 @@ CMake Error \(author\) at GenerateSarifResults\.cmake:16 \(message\):
Another example author warning message
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This error is for project developers\. Use -Wno-error=author to suppress it\.$
This error is for project developers\. Use -Wno-error=author to suppress it\.
+
CMake Warning at GenerateSarifResults\.cmake:20 \(message\):
Warning from a nested function call
Call Stack \(most recent call first\):
GenerateSarifResults\.cmake:24 \(a\)
GenerateSarifResults\.cmake:27 \(b\)
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Warning at GenerateSarifResults-Included\.cmake:1 \(message\):
Warning from an included file
Call Stack \(most recent call first\):
GenerateSarifResults\.cmake:30 \(include\)
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Warning at GenerateSarifResults\.cmake:38 \(message\):
Warning from a variable_watch callback
Call Stack \(most recent call first\):
GenerateSarifResults\.cmake:[0-9]+ \(warn_callback\)
GenerateSarifResults\.cmake:42 \(set\)
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Error at GenerateSarifResults\.cmake:46 \(message\):
Encabulator: a deferred error
Call Stack \(most recent call first\):
CMakeLists\.txt:DEFERRED$

View File

@@ -14,3 +14,33 @@ message(AUTHOR_WARNING "Example author warning message")
# Change it and issue another one
cmake_diagnostic(SET CMD_AUTHOR SEND_ERROR)
message(AUTHOR_WARNING "Another example author warning message")
# Define and call some functions to test stack reporting
function(a)
message(WARNING "Warning from a nested function call")
endfunction()
function(b)
a()
endfunction()
b()
# Include another file that generates a warning
include("${CMAKE_CURRENT_LIST_DIR}/GenerateSarifResults-Included.cmake")
# variable_watch and deferred calls add placeholders to the CMake backtrace.
# Placeholders on the stack are prone to accidental reporting as a stack frame
# or line number. Ensure location info is reported but the stack is not
# polluted with placeholders.
function(warn_callback variable access value file stack)
message(WARNING "Warning from a variable_watch callback")
endfunction()
variable_watch(x warn_callback)
set(x "x_value")
# A result from a deferred call should report the location it was deferred from
# and the list file that finished processing and executed the deferred call.
cmake_language(DEFER CALL message SEND_ERROR "Encabulator: a deferred error")

View File

@@ -7,10 +7,16 @@
"level": "error",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "ProjectFatalError.cmake",
"uriBaseId": "PATH:<SOURCE_DIR>"
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
@@ -22,9 +28,61 @@
"text": "Example error"
},
"ruleId": "CMake.FatalError",
"ruleIndex": 0
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "ProjectFatalError.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 1
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
}
],
"originalUriBaseIds": {
"CMAKE_BINARY_DIR": {
"uri": "file://PATH:<BINARY_DIR>/"
},
"CMAKE_SOURCE_DIR": {
"uri": "file://PATH:<SOURCE_DIR>/"
}
},
"tool": {
"driver": {
"name": "CMake",

View File

@@ -1,5 +1,6 @@
include("${CMAKE_CURRENT_LIST_DIR}/check-sarif.cmake")
# This test should produce the same output as GenerateSarifResults
# The result issued before CMAKE_EXPORT_SARIF was enabled should still be
# captured in the SARIF output
check_sarif_output("${RunCMake_TEST_BINARY_DIR}/.cmake/sarif/cmake.sarif"
"${CMAKE_CURRENT_LIST_DIR}/GenerateSarifResults-expected.sarif")
"${CMAKE_CURRENT_LIST_DIR}/ToggleExportSarifVariable-expected.sarif")

View File

@@ -0,0 +1,101 @@
{
"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
"runs": [
{
"results": [
{
"level": "warning",
"locations": [
{
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "ToggleExportSarifVariable.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
}
}
}
],
"message": {
"text": "Example warning message"
},
"ruleId": "CMake.Warning",
"ruleIndex": 0,
"stacks": [
{
"frames": [
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "message"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "ToggleExportSarifVariable.cmake",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 2
}
}
}
},
{
"location": {
"logicalLocations": [
{
"kind": "function",
"name": "include"
}
],
"physicalLocation": {
"artifactLocation": {
"uri": "CMakeLists.txt",
"uriBaseId": "CMAKE_SOURCE_DIR"
},
"region": {
"startLine": 3
}
}
}
}
]
}
]
}
],
"originalUriBaseIds": {
"CMAKE_BINARY_DIR": {
"uri": "file://PATH:<BINARY_DIR>/"
},
"CMAKE_SOURCE_DIR": {
"uri": "file://PATH:<SOURCE_DIR>/"
}
},
"tool": {
"driver": {
"name": "CMake",
"rules": [
{
"id": "CMake.Warning",
"name": "CMake Warning"
}
],
"version": "<IGNORE>"
}
}
}
],
"version": "2.1.0"
}

View File

@@ -1,25 +1,4 @@
^CMake Warning at GenerateSarifResults\.cmake:2 \(message\):
^CMake Warning at ToggleExportSarifVariable\.cmake:2 \(message\):
Example warning message
Call Stack \(most recent call first\):
ToggleExportSarifVariable\.cmake:[0-9]+ \(include\)
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Warning at GenerateSarifResults\.cmake:5 \(message\):
A second example warning message
Call Stack \(most recent call first\):
ToggleExportSarifVariable\.cmake:[0-9]+ \(include\)
CMakeLists\.txt:[0-9]+ \(include\)
+
CMake Warning \(author\) at GenerateSarifResults\.cmake:11 \(message\):
Example author warning message
Call Stack \(most recent call first\):
ToggleExportSarifVariable\.cmake:[0-9]+ \(include\)
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-author to suppress it\.
+
CMake Error \(author\) at GenerateSarifResults\.cmake:16 \(message\):
Another example author warning message
Call Stack \(most recent call first\):
ToggleExportSarifVariable\.cmake:[0-9]+ \(include\)
CMakeLists\.txt:[0-9]+ \(include\)
This error is for project developers\. Use -Wno-error=author to suppress it\.$
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -1,6 +1,3 @@
# Generate potential SARIF results
include("${CMAKE_CURRENT_LIST_DIR}/GenerateSarifResults.cmake")
# Enable SARIF logging at the end for the most behavior coverage
# All results should be captured regardless of when enabled
# Enable logging after generating a result to ensure it is still captured.
message(WARNING "Example warning message")
set(CMAKE_EXPORT_SARIF ON CACHE BOOL "Export SARIF results" FORCE)