aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Basic/Sarif.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Basic/Sarif.h')
-rw-r--r--contrib/llvm-project/clang/include/clang/Basic/Sarif.h513
1 files changed, 513 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Basic/Sarif.h b/contrib/llvm-project/clang/include/clang/Basic/Sarif.h
new file mode 100644
index 000000000000..e6c46224b316
--- /dev/null
+++ b/contrib/llvm-project/clang/include/clang/Basic/Sarif.h
@@ -0,0 +1,513 @@
+//== clang/Basic/Sarif.h - SARIF Diagnostics Object Model -------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// Defines clang::SarifDocumentWriter, clang::SarifRule, clang::SarifResult.
+///
+/// The document built can be accessed as a JSON Object.
+/// Several value semantic types are also introduced which represent properties
+/// of the SARIF standard, such as 'artifact', 'result', 'rule'.
+///
+/// A SARIF (Static Analysis Results Interchange Format) document is JSON
+/// document that describes in detail the results of running static analysis
+/// tools on a project. Each (non-trivial) document consists of at least one
+/// "run", which are themselves composed of details such as:
+/// * Tool: The tool that was run
+/// * Rules: The rules applied during the tool run, represented by
+/// \c reportingDescriptor objects in SARIF
+/// * Results: The matches for the rules applied against the project(s) being
+/// evaluated, represented by \c result objects in SARIF
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html">The SARIF standard</a>
+/// 2. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836">SARIF<pre>reportingDescriptor</pre></a>
+/// 3. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638">SARIF<pre>result</pre></a>
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_SARIF_H
+#define LLVM_CLANG_BASIC_SARIF_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <optional>
+#include <string>
+
+namespace clang {
+
+class SarifDocumentWriter;
+class SourceManager;
+
+namespace detail {
+
+/// \internal
+/// An artifact location is SARIF's way of describing the complete location
+/// of an artifact encountered during analysis. The \c artifactLocation object
+/// typically consists of a URI, and/or an index to reference the artifact it
+/// locates.
+///
+/// This builder makes an additional assumption: that every artifact encountered
+/// by \c clang will be a physical, top-level artifact. Which is why the static
+/// creation method \ref SarifArtifactLocation::create takes a mandatory URI
+/// parameter. The official standard states that either a \c URI or \c Index
+/// must be available in the object, \c clang picks the \c URI as a reasonable
+/// default, because it intends to deal in physical artifacts for now.
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427">artifactLocation object</a>
+/// 2. \ref SarifArtifact
+class SarifArtifactLocation {
+private:
+ friend class clang::SarifDocumentWriter;
+
+ std::optional<uint32_t> Index;
+ std::string URI;
+
+ SarifArtifactLocation() = delete;
+ explicit SarifArtifactLocation(const std::string &URI) : URI(URI) {}
+
+public:
+ static SarifArtifactLocation create(llvm::StringRef URI) {
+ return SarifArtifactLocation{URI.str()};
+ }
+
+ SarifArtifactLocation setIndex(uint32_t Idx) {
+ Index = Idx;
+ return *this;
+ }
+};
+
+/// \internal
+/// An artifact in SARIF is any object (a sequence of bytes) addressable by
+/// a URI (RFC 3986). The most common type of artifact for clang's use-case
+/// would be source files. SARIF's artifact object is described in detail in
+/// section 3.24.
+//
+/// Since every clang artifact MUST have a location (there being no nested
+/// artifacts), the creation method \ref SarifArtifact::create requires a
+/// \ref SarifArtifactLocation object.
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317611">artifact object</a>
+class SarifArtifact {
+private:
+ friend class clang::SarifDocumentWriter;
+
+ std::optional<uint32_t> Offset;
+ std::optional<size_t> Length;
+ std::string MimeType;
+ SarifArtifactLocation Location;
+ llvm::SmallVector<std::string, 4> Roles;
+
+ SarifArtifact() = delete;
+
+ explicit SarifArtifact(const SarifArtifactLocation &Loc) : Location(Loc) {}
+
+public:
+ static SarifArtifact create(const SarifArtifactLocation &Loc) {
+ return SarifArtifact{Loc};
+ }
+
+ SarifArtifact setOffset(uint32_t ArtifactOffset) {
+ Offset = ArtifactOffset;
+ return *this;
+ }
+
+ SarifArtifact setLength(size_t NumBytes) {
+ Length = NumBytes;
+ return *this;
+ }
+
+ SarifArtifact setRoles(std::initializer_list<llvm::StringRef> ArtifactRoles) {
+ Roles.assign(ArtifactRoles.begin(), ArtifactRoles.end());
+ return *this;
+ }
+
+ SarifArtifact setMimeType(llvm::StringRef ArtifactMimeType) {
+ MimeType = ArtifactMimeType.str();
+ return *this;
+ }
+};
+
+} // namespace detail
+
+enum class ThreadFlowImportance { Important, Essential, Unimportant };
+
+/// The level of severity associated with a \ref SarifResult.
+///
+/// Of all the levels, \c None is the only one that is not associated with
+/// a failure.
+///
+/// A typical mapping for clang's DiagnosticKind to SarifResultLevel would look
+/// like:
+/// * \c None: \ref clang::DiagnosticsEngine::Level::Remark, \ref clang::DiagnosticsEngine::Level::Ignored
+/// * \c Note: \ref clang::DiagnosticsEngine::Level::Note
+/// * \c Warning: \ref clang::DiagnosticsEngine::Level::Warning
+/// * \c Error could be generated from one of:
+/// - \ref clang::DiagnosticsEngine::Level::Warning with \c -Werror
+/// - \ref clang::DiagnosticsEngine::Level::Error
+/// - \ref clang::DiagnosticsEngine::Level::Fatal when \ref clang::DiagnosticsEngine::ErrorsAsFatal is set.
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317648">level property</a>
+enum class SarifResultLevel { None, Note, Warning, Error };
+
+/// A thread flow is a sequence of code locations that specify a possible path
+/// through a single thread of execution.
+/// A thread flow in SARIF is related to a code flow which describes
+/// the progress of one or more programs through one or more thread flows.
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317744">threadFlow object</a>
+/// 2. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317740">codeFlow object</a>
+class ThreadFlow {
+ friend class SarifDocumentWriter;
+
+ CharSourceRange Range;
+ ThreadFlowImportance Importance;
+ std::string Message;
+
+ ThreadFlow() = default;
+
+public:
+ static ThreadFlow create() { return {}; }
+
+ ThreadFlow setRange(const CharSourceRange &ItemRange) {
+ assert(ItemRange.isCharRange() &&
+ "ThreadFlows require a character granular source range!");
+ Range = ItemRange;
+ return *this;
+ }
+
+ ThreadFlow setImportance(const ThreadFlowImportance &ItemImportance) {
+ Importance = ItemImportance;
+ return *this;
+ }
+
+ ThreadFlow setMessage(llvm::StringRef ItemMessage) {
+ Message = ItemMessage.str();
+ return *this;
+ }
+};
+
+/// A SARIF Reporting Configuration (\c reportingConfiguration) object contains
+/// properties for a \ref SarifRule that can be configured at runtime before
+/// analysis begins.
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317852">reportingConfiguration object</a>
+class SarifReportingConfiguration {
+ friend class clang::SarifDocumentWriter;
+
+ bool Enabled = true;
+ SarifResultLevel Level = SarifResultLevel::Warning;
+ float Rank = -1.0f;
+
+ SarifReportingConfiguration() = default;
+
+public:
+ static SarifReportingConfiguration create() { return {}; };
+
+ SarifReportingConfiguration disable() {
+ Enabled = false;
+ return *this;
+ }
+
+ SarifReportingConfiguration enable() {
+ Enabled = true;
+ return *this;
+ }
+
+ SarifReportingConfiguration setLevel(SarifResultLevel TheLevel) {
+ Level = TheLevel;
+ return *this;
+ }
+
+ SarifReportingConfiguration setRank(float TheRank) {
+ assert(TheRank >= 0.0f && "Rule rank cannot be smaller than 0.0");
+ assert(TheRank <= 100.0f && "Rule rank cannot be larger than 100.0");
+ Rank = TheRank;
+ return *this;
+ }
+};
+
+/// A SARIF rule (\c reportingDescriptor object) contains information that
+/// describes a reporting item generated by a tool. A reporting item is
+/// either a result of analysis or notification of a condition encountered by
+/// the tool. Rules are arbitrary but are identifiable by a hierarchical
+/// rule-id.
+///
+/// This builder provides an interface to create SARIF \c reportingDescriptor
+/// objects via the \ref SarifRule::create static method.
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836">reportingDescriptor object</a>
+class SarifRule {
+ friend class clang::SarifDocumentWriter;
+
+ std::string Name;
+ std::string Id;
+ std::string Description;
+ std::string HelpURI;
+ SarifReportingConfiguration DefaultConfiguration;
+
+ SarifRule() : DefaultConfiguration(SarifReportingConfiguration::create()) {}
+
+public:
+ static SarifRule create() { return {}; }
+
+ SarifRule setName(llvm::StringRef RuleName) {
+ Name = RuleName.str();
+ return *this;
+ }
+
+ SarifRule setRuleId(llvm::StringRef RuleId) {
+ Id = RuleId.str();
+ return *this;
+ }
+
+ SarifRule setDescription(llvm::StringRef RuleDesc) {
+ Description = RuleDesc.str();
+ return *this;
+ }
+
+ SarifRule setHelpURI(llvm::StringRef RuleHelpURI) {
+ HelpURI = RuleHelpURI.str();
+ return *this;
+ }
+
+ SarifRule
+ setDefaultConfiguration(const SarifReportingConfiguration &Configuration) {
+ DefaultConfiguration = Configuration;
+ return *this;
+ }
+};
+
+/// A SARIF result (also called a "reporting item") is a unit of output
+/// produced when one of the tool's \c reportingDescriptor encounters a match
+/// on the file being analysed by the tool.
+///
+/// This builder provides a \ref SarifResult::create static method that can be
+/// used to create an empty shell onto which attributes can be added using the
+/// \c setX(...) methods.
+///
+/// For example:
+/// \code{.cpp}
+/// SarifResult result = SarifResult::create(...)
+/// .setRuleId(...)
+/// .setDiagnosticMessage(...);
+/// \endcode
+///
+/// Reference:
+/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638">SARIF<pre>result</pre></a>
+class SarifResult {
+ friend class clang::SarifDocumentWriter;
+
+ // NOTE:
+ // This type cannot fit all possible indexes representable by JSON, but is
+ // chosen because it is the largest unsigned type that can be safely
+ // converted to an \c int64_t.
+ uint32_t RuleIdx;
+ std::string RuleId;
+ std::string DiagnosticMessage;
+ llvm::SmallVector<CharSourceRange, 8> Locations;
+ llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
+ std::optional<SarifResultLevel> LevelOverride;
+
+ SarifResult() = delete;
+ explicit SarifResult(uint32_t RuleIdx) : RuleIdx(RuleIdx) {}
+
+public:
+ static SarifResult create(uint32_t RuleIdx) { return SarifResult{RuleIdx}; }
+
+ SarifResult setIndex(uint32_t Idx) {
+ RuleIdx = Idx;
+ return *this;
+ }
+
+ SarifResult setRuleId(llvm::StringRef Id) {
+ RuleId = Id.str();
+ return *this;
+ }
+
+ SarifResult setDiagnosticMessage(llvm::StringRef Message) {
+ DiagnosticMessage = Message.str();
+ return *this;
+ }
+
+ SarifResult setLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
+#ifndef NDEBUG
+ for (const auto &Loc : DiagLocs) {
+ assert(Loc.isCharRange() &&
+ "SARIF Results require character granular source ranges!");
+ }
+#endif
+ Locations.assign(DiagLocs.begin(), DiagLocs.end());
+ return *this;
+ }
+ SarifResult setThreadFlows(llvm::ArrayRef<ThreadFlow> ThreadFlowResults) {
+ ThreadFlows.assign(ThreadFlowResults.begin(), ThreadFlowResults.end());
+ return *this;
+ }
+
+ SarifResult setDiagnosticLevel(const SarifResultLevel &TheLevel) {
+ LevelOverride = TheLevel;
+ return *this;
+ }
+};
+
+/// This class handles creating a valid SARIF document given various input
+/// attributes. However, it requires an ordering among certain method calls:
+///
+/// 1. Because every SARIF document must contain at least 1 \c run, callers
+/// must ensure that \ref SarifDocumentWriter::createRun is called before
+/// any other methods.
+/// 2. If SarifDocumentWriter::endRun is called, callers MUST call
+/// SarifDocumentWriter::createRun, before invoking any of the result
+/// aggregation methods such as SarifDocumentWriter::appendResult etc.
+class SarifDocumentWriter {
+private:
+ const llvm::StringRef SchemaURI{
+ "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/"
+ "sarif-schema-2.1.0.json"};
+ const llvm::StringRef SchemaVersion{"2.1.0"};
+
+ /// \internal
+ /// Return a pointer to the current tool. Asserts that a run exists.
+ llvm::json::Object &getCurrentTool();
+
+ /// \internal
+ /// Checks if there is a run associated with this document.
+ ///
+ /// \return true on success
+ bool hasRun() const;
+
+ /// \internal
+ /// Reset portions of the internal state so that the document is ready to
+ /// receive data for a new run.
+ void reset();
+
+ /// \internal
+ /// Return a mutable reference to the current run, after asserting it exists.
+ ///
+ /// \note It is undefined behavior to call this if a run does not exist in
+ /// the SARIF document.
+ llvm::json::Object &getCurrentRun();
+
+ /// Create a code flow object for the given threadflows.
+ /// See \ref ThreadFlow.
+ ///
+ /// \note It is undefined behavior to call this if a run does not exist in
+ /// the SARIF document.
+ llvm::json::Object
+ createCodeFlow(const llvm::ArrayRef<ThreadFlow> ThreadFlows);
+
+ /// Add the given threadflows to the ones this SARIF document knows about.
+ llvm::json::Array
+ createThreadFlows(const llvm::ArrayRef<ThreadFlow> ThreadFlows);
+
+ /// Add the given \ref CharSourceRange to the SARIF document as a physical
+ /// location, with its corresponding artifact.
+ llvm::json::Object createPhysicalLocation(const CharSourceRange &R);
+
+public:
+ SarifDocumentWriter() = delete;
+
+ /// Create a new empty SARIF document with the given source manager.
+ SarifDocumentWriter(const SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
+
+ /// Release resources held by this SARIF document.
+ ~SarifDocumentWriter() = default;
+
+ /// Create a new run with which any upcoming analysis will be associated.
+ /// Each run requires specifying the tool that is generating reporting items.
+ void createRun(const llvm::StringRef ShortToolName,
+ const llvm::StringRef LongToolName,
+ const llvm::StringRef ToolVersion = CLANG_VERSION_STRING);
+
+ /// If there is a current run, end it.
+ ///
+ /// This method collects various book-keeping required to clear and close
+ /// resources associated with the current run, but may also allocate some
+ /// for the next run.
+ ///
+ /// Calling \ref endRun before associating a run through \ref createRun leads
+ /// to undefined behaviour.
+ void endRun();
+
+ /// Associate the given rule with the current run.
+ ///
+ /// Returns an integer rule index for the created rule that is unique within
+ /// the current run, which can then be used to create a \ref SarifResult
+ /// to add to the current run. Note that a rule must exist before being
+ /// referenced by a result.
+ ///
+ /// \pre
+ /// There must be a run associated with the document, failing to do so will
+ /// cause undefined behaviour.
+ size_t createRule(const SarifRule &Rule);
+
+ /// Append a new result to the currently in-flight run.
+ ///
+ /// \pre
+ /// There must be a run associated with the document, failing to do so will
+ /// cause undefined behaviour.
+ /// \pre
+ /// \c RuleIdx used to create the result must correspond to a rule known by
+ /// the SARIF document. It must be the value returned by a previous call
+ /// to \ref createRule.
+ void appendResult(const SarifResult &SarifResult);
+
+ /// Return the SARIF document in its current state.
+ /// Calling this will trigger a copy of the internal state including all
+ /// reported diagnostics, resulting in an expensive call.
+ llvm::json::Object createDocument();
+
+private:
+ /// Source Manager to use for the current SARIF document.
+ const SourceManager &SourceMgr;
+
+ /// Flag to track the state of this document:
+ /// A closed document is one on which a new runs must be created.
+ /// This could be a document that is freshly created, or has recently
+ /// finished writing to a previous run.
+ bool Closed = true;
+
+ /// A sequence of SARIF runs.
+ /// Each run object describes a single run of an analysis tool and contains
+ /// the output of that run.
+ ///
+ /// Reference: <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317484">run object</a>
+ llvm::json::Array Runs;
+
+ /// The list of rules associated with the most recent active run. These are
+ /// defined using the diagnostics passed to the SarifDocument. Each rule
+ /// need not be unique through the result set. E.g. there may be several
+ /// 'syntax' errors throughout code under analysis, each of which has its
+ /// own specific diagnostic message (and consequently, RuleId). Rules are
+ /// also known as "reportingDescriptor" objects in SARIF.
+ ///
+ /// Reference: <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317556">rules property</a>
+ llvm::SmallVector<SarifRule, 32> CurrentRules;
+
+ /// The list of artifacts that have been encountered on the most recent active
+ /// run. An artifact is defined in SARIF as a sequence of bytes addressable
+ /// by a URI. A common example for clang's case would be files named by
+ /// filesystem paths.
+ llvm::StringMap<detail::SarifArtifact> CurrentArtifacts;
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_SARIF_H