- //== 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 
-