Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //== clang/Basic/Sarif.h - SARIF Diagnostics Object Model -------*- C++ -*--==// | 
| 2 | // | ||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | ||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| 6 | // | ||
| 7 | //===----------------------------------------------------------------------===// | ||
| 8 | /// \file | ||
| 9 | /// Defines clang::SarifDocumentWriter, clang::SarifRule, clang::SarifResult. | ||
| 10 | /// | ||
| 11 | /// The document built can be accessed as a JSON Object. | ||
| 12 | /// Several value semantic types are also introduced which represent properties | ||
| 13 | /// of the SARIF standard, such as 'artifact', 'result', 'rule'. | ||
| 14 | /// | ||
| 15 | /// A SARIF (Static Analysis Results Interchange Format) document is JSON | ||
| 16 | /// document that describes in detail the results of running static analysis | ||
| 17 | /// tools on a project. Each (non-trivial) document consists of at least one | ||
| 18 | /// "run", which are themselves composed of details such as: | ||
| 19 | /// * Tool: The tool that was run | ||
| 20 | /// * Rules: The rules applied during the tool run, represented by | ||
| 21 | ///   \c reportingDescriptor objects in SARIF | ||
| 22 | /// * Results: The matches for the rules applied against the project(s) being | ||
| 23 | ///   evaluated, represented by \c result objects in SARIF | ||
| 24 | /// | ||
| 25 | /// Reference: | ||
| 26 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html">The SARIF standard</a> | ||
| 27 | /// 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> | ||
| 28 | /// 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> | ||
| 29 | //===----------------------------------------------------------------------===// | ||
| 30 | |||
| 31 | #ifndef LLVM_CLANG_BASIC_SARIF_H | ||
| 32 | #define LLVM_CLANG_BASIC_SARIF_H | ||
| 33 | |||
| 34 | #include "clang/Basic/SourceLocation.h" | ||
| 35 | #include "clang/Basic/Version.h" | ||
| 36 | #include "llvm/ADT/ArrayRef.h" | ||
| 37 | #include "llvm/ADT/SmallVector.h" | ||
| 38 | #include "llvm/ADT/StringMap.h" | ||
| 39 | #include "llvm/ADT/StringRef.h" | ||
| 40 | #include "llvm/Support/JSON.h" | ||
| 41 | #include <cassert> | ||
| 42 | #include <cstddef> | ||
| 43 | #include <cstdint> | ||
| 44 | #include <initializer_list> | ||
| 45 | #include <optional> | ||
| 46 | #include <string> | ||
| 47 | |||
| 48 | namespace clang { | ||
| 49 | |||
| 50 | class SarifDocumentWriter; | ||
| 51 | class SourceManager; | ||
| 52 | |||
| 53 | namespace detail { | ||
| 54 | |||
| 55 | /// \internal | ||
| 56 | /// An artifact location is SARIF's way of describing the complete location | ||
| 57 | /// of an artifact encountered during analysis. The \c artifactLocation object | ||
| 58 | /// typically consists of a URI, and/or an index to reference the artifact it | ||
| 59 | /// locates. | ||
| 60 | /// | ||
| 61 | /// This builder makes an additional assumption: that every artifact encountered | ||
| 62 | /// by \c clang will be a physical, top-level artifact. Which is why the static | ||
| 63 | /// creation method \ref SarifArtifactLocation::create takes a mandatory URI | ||
| 64 | /// parameter. The official standard states that either a \c URI or \c Index | ||
| 65 | /// must be available in the object, \c clang picks the \c URI as a reasonable | ||
| 66 | /// default, because it intends to deal in physical artifacts for now. | ||
| 67 | /// | ||
| 68 | /// Reference: | ||
| 69 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427">artifactLocation object</a> | ||
| 70 | /// 2. \ref SarifArtifact | ||
| 71 | class SarifArtifactLocation { | ||
| 72 | private: | ||
| 73 | friend class clang::SarifDocumentWriter; | ||
| 74 | |||
| 75 | std::optional<uint32_t> Index; | ||
| 76 | std::string URI; | ||
| 77 | |||
| 78 | SarifArtifactLocation() = delete; | ||
| 79 | explicit SarifArtifactLocation(const std::string &URI) : URI(URI) {} | ||
| 80 | |||
| 81 | public: | ||
| 82 | static SarifArtifactLocation create(llvm::StringRef URI) { | ||
| 83 | return SarifArtifactLocation{URI.str()}; | ||
| 84 |   } | ||
| 85 | |||
| 86 | SarifArtifactLocation setIndex(uint32_t Idx) { | ||
| 87 | Index = Idx; | ||
| 88 | return *this; | ||
| 89 |   } | ||
| 90 | }; | ||
| 91 | |||
| 92 | /// \internal | ||
| 93 | /// An artifact in SARIF is any object (a sequence of bytes) addressable by | ||
| 94 | /// a URI (RFC 3986). The most common type of artifact for clang's use-case | ||
| 95 | /// would be source files. SARIF's artifact object is described in detail in | ||
| 96 | /// section 3.24. | ||
| 97 | // | ||
| 98 | /// Since every clang artifact MUST have a location (there being no nested | ||
| 99 | /// artifacts), the creation method \ref SarifArtifact::create requires a | ||
| 100 | /// \ref SarifArtifactLocation object. | ||
| 101 | /// | ||
| 102 | /// Reference: | ||
| 103 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317611">artifact object</a> | ||
| 104 | class SarifArtifact { | ||
| 105 | private: | ||
| 106 | friend class clang::SarifDocumentWriter; | ||
| 107 | |||
| 108 | std::optional<uint32_t> Offset; | ||
| 109 | std::optional<size_t> Length; | ||
| 110 | std::string MimeType; | ||
| 111 |   SarifArtifactLocation Location; | ||
| 112 | llvm::SmallVector<std::string, 4> Roles; | ||
| 113 | |||
| 114 | SarifArtifact() = delete; | ||
| 115 | |||
| 116 | explicit SarifArtifact(const SarifArtifactLocation &Loc) : Location(Loc) {} | ||
| 117 | |||
| 118 | public: | ||
| 119 | static SarifArtifact create(const SarifArtifactLocation &Loc) { | ||
| 120 | return SarifArtifact{Loc}; | ||
| 121 |   } | ||
| 122 | |||
| 123 | SarifArtifact setOffset(uint32_t ArtifactOffset) { | ||
| 124 | Offset = ArtifactOffset; | ||
| 125 | return *this; | ||
| 126 |   } | ||
| 127 | |||
| 128 | SarifArtifact setLength(size_t NumBytes) { | ||
| 129 | Length = NumBytes; | ||
| 130 | return *this; | ||
| 131 |   } | ||
| 132 | |||
| 133 | SarifArtifact setRoles(std::initializer_list<llvm::StringRef> ArtifactRoles) { | ||
| 134 | Roles.assign(ArtifactRoles.begin(), ArtifactRoles.end()); | ||
| 135 | return *this; | ||
| 136 |   } | ||
| 137 | |||
| 138 | SarifArtifact setMimeType(llvm::StringRef ArtifactMimeType) { | ||
| 139 | MimeType = ArtifactMimeType.str(); | ||
| 140 | return *this; | ||
| 141 |   } | ||
| 142 | }; | ||
| 143 | |||
| 144 | } // namespace detail | ||
| 145 | |||
| 146 | enum class ThreadFlowImportance { Important, Essential, Unimportant }; | ||
| 147 | |||
| 148 | /// The level of severity associated with a \ref SarifResult. | ||
| 149 | /// | ||
| 150 | /// Of all the levels, \c None is the only one that is not associated with | ||
| 151 | /// a failure. | ||
| 152 | /// | ||
| 153 | /// A typical mapping for clang's DiagnosticKind to SarifResultLevel would look | ||
| 154 | /// like: | ||
| 155 | /// * \c None: \ref clang::DiagnosticsEngine::Level::Remark, \ref clang::DiagnosticsEngine::Level::Ignored | ||
| 156 | /// * \c Note: \ref clang::DiagnosticsEngine::Level::Note | ||
| 157 | /// * \c Warning: \ref clang::DiagnosticsEngine::Level::Warning | ||
| 158 | /// * \c Error could be generated from one of: | ||
| 159 | ///   - \ref clang::DiagnosticsEngine::Level::Warning with \c -Werror | ||
| 160 | ///   - \ref clang::DiagnosticsEngine::Level::Error | ||
| 161 | ///   - \ref clang::DiagnosticsEngine::Level::Fatal when \ref clang::DiagnosticsEngine::ErrorsAsFatal is set. | ||
| 162 | /// | ||
| 163 | /// Reference: | ||
| 164 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317648">level property</a> | ||
| 165 | enum class SarifResultLevel { None, Note, Warning, Error }; | ||
| 166 | |||
| 167 | /// A thread flow is a sequence of code locations that specify a possible path | ||
| 168 | /// through a single thread of execution. | ||
| 169 | /// A thread flow in SARIF is related to a code flow which describes | ||
| 170 | /// the progress of one or more programs through one or more thread flows. | ||
| 171 | /// | ||
| 172 | /// Reference: | ||
| 173 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317744">threadFlow object</a> | ||
| 174 | /// 2. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317740">codeFlow object</a> | ||
| 175 | class ThreadFlow { | ||
| 176 | friend class SarifDocumentWriter; | ||
| 177 | |||
| 178 |   CharSourceRange Range; | ||
| 179 |   ThreadFlowImportance Importance; | ||
| 180 | std::string Message; | ||
| 181 | |||
| 182 | ThreadFlow() = default; | ||
| 183 | |||
| 184 | public: | ||
| 185 | static ThreadFlow create() { return {}; } | ||
| 186 | |||
| 187 | ThreadFlow setRange(const CharSourceRange &ItemRange) { | ||
| 188 | assert(ItemRange.isCharRange() && | ||
| 189 | "ThreadFlows require a character granular source range!"); | ||
| 190 | Range = ItemRange; | ||
| 191 | return *this; | ||
| 192 |   } | ||
| 193 | |||
| 194 | ThreadFlow setImportance(const ThreadFlowImportance &ItemImportance) { | ||
| 195 | Importance = ItemImportance; | ||
| 196 | return *this; | ||
| 197 |   } | ||
| 198 | |||
| 199 | ThreadFlow setMessage(llvm::StringRef ItemMessage) { | ||
| 200 | Message = ItemMessage.str(); | ||
| 201 | return *this; | ||
| 202 |   } | ||
| 203 | }; | ||
| 204 | |||
| 205 | /// A SARIF Reporting Configuration (\c reportingConfiguration) object contains | ||
| 206 | /// properties for a \ref SarifRule that can be configured at runtime before | ||
| 207 | /// analysis begins. | ||
| 208 | /// | ||
| 209 | /// Reference: | ||
| 210 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317852">reportingConfiguration object</a> | ||
| 211 | class SarifReportingConfiguration { | ||
| 212 | friend class clang::SarifDocumentWriter; | ||
| 213 | |||
| 214 | bool Enabled = true; | ||
| 215 | SarifResultLevel Level = SarifResultLevel::Warning; | ||
| 216 | float Rank = -1.0f; | ||
| 217 | |||
| 218 | SarifReportingConfiguration() = default; | ||
| 219 | |||
| 220 | public: | ||
| 221 | static SarifReportingConfiguration create() { return {}; }; | ||
| 222 | |||
| 223 | SarifReportingConfiguration disable() { | ||
| 224 | Enabled = false; | ||
| 225 | return *this; | ||
| 226 |   } | ||
| 227 | |||
| 228 | SarifReportingConfiguration enable() { | ||
| 229 | Enabled = true; | ||
| 230 | return *this; | ||
| 231 |   } | ||
| 232 | |||
| 233 | SarifReportingConfiguration setLevel(SarifResultLevel TheLevel) { | ||
| 234 | Level = TheLevel; | ||
| 235 | return *this; | ||
| 236 |   } | ||
| 237 | |||
| 238 | SarifReportingConfiguration setRank(float TheRank) { | ||
| 239 | assert(TheRank >= 0.0f && "Rule rank cannot be smaller than 0.0"); | ||
| 240 | assert(TheRank <= 100.0f && "Rule rank cannot be larger than 100.0"); | ||
| 241 | Rank = TheRank; | ||
| 242 | return *this; | ||
| 243 |   } | ||
| 244 | }; | ||
| 245 | |||
| 246 | /// A SARIF rule (\c reportingDescriptor object) contains information that | ||
| 247 | /// describes a reporting item generated by a tool. A reporting item is | ||
| 248 | /// either a result of analysis or notification of a condition encountered by | ||
| 249 | /// the tool. Rules are arbitrary but are identifiable by a hierarchical | ||
| 250 | /// rule-id. | ||
| 251 | /// | ||
| 252 | /// This builder provides an interface to create SARIF \c reportingDescriptor | ||
| 253 | /// objects via the \ref SarifRule::create static method. | ||
| 254 | /// | ||
| 255 | /// Reference: | ||
| 256 | /// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836">reportingDescriptor object</a> | ||
| 257 | class SarifRule { | ||
| 258 | friend class clang::SarifDocumentWriter; | ||
| 259 | |||
| 260 | std::string Name; | ||
| 261 | std::string Id; | ||
| 262 | std::string Description; | ||
| 263 | std::string HelpURI; | ||
| 264 |   SarifReportingConfiguration DefaultConfiguration; | ||
| 265 | |||
| 266 | SarifRule() : DefaultConfiguration(SarifReportingConfiguration::create()) {} | ||
| 267 | |||
| 268 | public: | ||
| 269 | static SarifRule create() { return {}; } | ||
| 270 | |||
| 271 | SarifRule setName(llvm::StringRef RuleName) { | ||
| 272 | Name = RuleName.str(); | ||
| 273 | return *this; | ||
| 274 |   } | ||
| 275 | |||
| 276 | SarifRule setRuleId(llvm::StringRef RuleId) { | ||
| 277 | Id = RuleId.str(); | ||
| 278 | return *this; | ||
| 279 |   } | ||
| 280 | |||
| 281 | SarifRule setDescription(llvm::StringRef RuleDesc) { | ||
| 282 | Description = RuleDesc.str(); | ||
| 283 | return *this; | ||
| 284 |   } | ||
| 285 | |||
| 286 | SarifRule setHelpURI(llvm::StringRef RuleHelpURI) { | ||
| 287 | HelpURI = RuleHelpURI.str(); | ||
| 288 | return *this; | ||
| 289 |   } | ||
| 290 | |||
| 291 | SarifRule | ||
| 292 | setDefaultConfiguration(const SarifReportingConfiguration &Configuration) { | ||
| 293 | DefaultConfiguration = Configuration; | ||
| 294 | return *this; | ||
| 295 |   } | ||
| 296 | }; | ||
| 297 | |||
| 298 | /// A SARIF result (also called a "reporting item") is a unit of output | ||
| 299 | /// produced when one of the tool's \c reportingDescriptor encounters a match | ||
| 300 | /// on the file being analysed by the tool. | ||
| 301 | /// | ||
| 302 | /// This builder provides a \ref SarifResult::create static method that can be | ||
| 303 | /// used to create an empty shell onto which attributes can be added using the | ||
| 304 | /// \c setX(...) methods. | ||
| 305 | /// | ||
| 306 | /// For example: | ||
| 307 | /// \code{.cpp} | ||
| 308 | /// SarifResult result = SarifResult::create(...) | ||
| 309 | ///                         .setRuleId(...) | ||
| 310 | ///                         .setDiagnosticMessage(...); | ||
| 311 | /// \endcode | ||
| 312 | /// | ||
| 313 | /// Reference: | ||
| 314 | /// 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> | ||
| 315 | class SarifResult { | ||
| 316 | friend class clang::SarifDocumentWriter; | ||
| 317 | |||
| 318 |   // NOTE: | ||
| 319 |   // This type cannot fit all possible indexes representable by JSON, but is | ||
| 320 |   // chosen because it is the largest unsigned type that can be safely | ||
| 321 |   // converted to an \c int64_t. | ||
| 322 | uint32_t RuleIdx; | ||
| 323 | std::string RuleId; | ||
| 324 | std::string DiagnosticMessage; | ||
| 325 | llvm::SmallVector<CharSourceRange, 8> Locations; | ||
| 326 | llvm::SmallVector<ThreadFlow, 8> ThreadFlows; | ||
| 327 | std::optional<SarifResultLevel> LevelOverride; | ||
| 328 | |||
| 329 | SarifResult() = delete; | ||
| 330 | explicit SarifResult(uint32_t RuleIdx) : RuleIdx(RuleIdx) {} | ||
| 331 | |||
| 332 | public: | ||
| 333 | static SarifResult create(uint32_t RuleIdx) { return SarifResult{RuleIdx}; } | ||
| 334 | |||
| 335 | SarifResult setIndex(uint32_t Idx) { | ||
| 336 | RuleIdx = Idx; | ||
| 337 | return *this; | ||
| 338 |   } | ||
| 339 | |||
| 340 | SarifResult setRuleId(llvm::StringRef Id) { | ||
| 341 | RuleId = Id.str(); | ||
| 342 | return *this; | ||
| 343 |   } | ||
| 344 | |||
| 345 | SarifResult setDiagnosticMessage(llvm::StringRef Message) { | ||
| 346 | DiagnosticMessage = Message.str(); | ||
| 347 | return *this; | ||
| 348 |   } | ||
| 349 | |||
| 350 | SarifResult setLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) { | ||
| 351 | #ifndef NDEBUG | ||
| 352 | for (const auto &Loc : DiagLocs) { | ||
| 353 | assert(Loc.isCharRange() && | ||
| 354 | "SARIF Results require character granular source ranges!"); | ||
| 355 |     } | ||
| 356 | #endif | ||
| 357 | Locations.assign(DiagLocs.begin(), DiagLocs.end()); | ||
| 358 | return *this; | ||
| 359 |   } | ||
| 360 | SarifResult setThreadFlows(llvm::ArrayRef<ThreadFlow> ThreadFlowResults) { | ||
| 361 | ThreadFlows.assign(ThreadFlowResults.begin(), ThreadFlowResults.end()); | ||
| 362 | return *this; | ||
| 363 |   } | ||
| 364 | |||
| 365 | SarifResult setDiagnosticLevel(const SarifResultLevel &TheLevel) { | ||
| 366 | LevelOverride = TheLevel; | ||
| 367 | return *this; | ||
| 368 |   } | ||
| 369 | }; | ||
| 370 | |||
| 371 | /// This class handles creating a valid SARIF document given various input | ||
| 372 | /// attributes. However, it requires an ordering among certain method calls: | ||
| 373 | /// | ||
| 374 | /// 1. Because every SARIF document must contain at least 1 \c run, callers | ||
| 375 | ///    must ensure that \ref SarifDocumentWriter::createRun is called before | ||
| 376 | ///    any other methods. | ||
| 377 | /// 2. If SarifDocumentWriter::endRun is called, callers MUST call | ||
| 378 | ///    SarifDocumentWriter::createRun, before invoking any of the result | ||
| 379 | ///    aggregation methods such as SarifDocumentWriter::appendResult etc. | ||
| 380 | class SarifDocumentWriter { | ||
| 381 | private: | ||
| 382 | const llvm::StringRef SchemaURI{ | ||
| 383 |       "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/" | ||
| 384 | "sarif-schema-2.1.0.json"}; | ||
| 385 | const llvm::StringRef SchemaVersion{"2.1.0"}; | ||
| 386 | |||
| 387 |   /// \internal | ||
| 388 |   /// Return a pointer to the current tool. Asserts that a run exists. | ||
| 389 | llvm::json::Object &getCurrentTool(); | ||
| 390 | |||
| 391 |   /// \internal | ||
| 392 |   /// Checks if there is a run associated with this document. | ||
| 393 |   /// | ||
| 394 |   /// \return true on success | ||
| 395 | bool hasRun() const; | ||
| 396 | |||
| 397 |   /// \internal | ||
| 398 |   /// Reset portions of the internal state so that the document is ready to | ||
| 399 |   /// receive data for a new run. | ||
| 400 | void reset(); | ||
| 401 | |||
| 402 |   /// \internal | ||
| 403 |   /// Return a mutable reference to the current run, after asserting it exists. | ||
| 404 |   /// | ||
| 405 |   /// \note It is undefined behavior to call this if a run does not exist in | ||
| 406 |   /// the SARIF document. | ||
| 407 | llvm::json::Object &getCurrentRun(); | ||
| 408 | |||
| 409 |   /// Create a code flow object for the given threadflows. | ||
| 410 |   /// See \ref ThreadFlow. | ||
| 411 |   /// | ||
| 412 |   /// \note It is undefined behavior to call this if a run does not exist in | ||
| 413 |   /// the SARIF document. | ||
| 414 | llvm::json::Object | ||
| 415 | createCodeFlow(const llvm::ArrayRef<ThreadFlow> ThreadFlows); | ||
| 416 | |||
| 417 |   /// Add the given threadflows to the ones this SARIF document knows about. | ||
| 418 | llvm::json::Array | ||
| 419 | createThreadFlows(const llvm::ArrayRef<ThreadFlow> ThreadFlows); | ||
| 420 | |||
| 421 |   /// Add the given \ref CharSourceRange to the SARIF document as a physical | ||
| 422 |   /// location, with its corresponding artifact. | ||
| 423 | llvm::json::Object createPhysicalLocation(const CharSourceRange &R); | ||
| 424 | |||
| 425 | public: | ||
| 426 | SarifDocumentWriter() = delete; | ||
| 427 | |||
| 428 |   /// Create a new empty SARIF document with the given source manager. | ||
| 429 | SarifDocumentWriter(const SourceManager &SourceMgr) : SourceMgr(SourceMgr) {} | ||
| 430 | |||
| 431 |   /// Release resources held by this SARIF document. | ||
| 432 | ~SarifDocumentWriter() = default; | ||
| 433 | |||
| 434 |   /// Create a new run with which any upcoming analysis will be associated. | ||
| 435 |   /// Each run requires specifying the tool that is generating reporting items. | ||
| 436 | void createRun(const llvm::StringRef ShortToolName, | ||
| 437 | const llvm::StringRef LongToolName, | ||
| 438 | const llvm::StringRef ToolVersion = CLANG_VERSION_STRING); | ||
| 439 | |||
| 440 |   /// If there is a current run, end it. | ||
| 441 |   /// | ||
| 442 |   /// This method collects various book-keeping required to clear and close | ||
| 443 |   /// resources associated with the current run, but may also allocate some | ||
| 444 |   /// for the next run. | ||
| 445 |   /// | ||
| 446 |   /// Calling \ref endRun before associating a run through \ref createRun leads | ||
| 447 |   /// to undefined behaviour. | ||
| 448 | void endRun(); | ||
| 449 | |||
| 450 |   /// Associate the given rule with the current run. | ||
| 451 |   /// | ||
| 452 |   /// Returns an integer rule index for the created rule that is unique within | ||
| 453 |   /// the current run, which can then be used to create a \ref SarifResult | ||
| 454 |   /// to add to the current run. Note that a rule must exist before being | ||
| 455 |   /// referenced by a result. | ||
| 456 |   /// | ||
| 457 |   /// \pre | ||
| 458 |   /// There must be a run associated with the document, failing to do so will | ||
| 459 |   /// cause undefined behaviour. | ||
| 460 | size_t createRule(const SarifRule &Rule); | ||
| 461 | |||
| 462 |   /// Append a new result to the currently in-flight run. | ||
| 463 |   /// | ||
| 464 |   /// \pre | ||
| 465 |   /// There must be a run associated with the document, failing to do so will | ||
| 466 |   /// cause undefined behaviour. | ||
| 467 |   /// \pre | ||
| 468 |   /// \c RuleIdx used to create the result must correspond to a rule known by | ||
| 469 |   /// the SARIF document. It must be the value returned by a previous call | ||
| 470 |   /// to \ref createRule. | ||
| 471 | void appendResult(const SarifResult &SarifResult); | ||
| 472 | |||
| 473 |   /// Return the SARIF document in its current state. | ||
| 474 |   /// Calling this will trigger a copy of the internal state including all | ||
| 475 |   /// reported diagnostics, resulting in an expensive call. | ||
| 476 | llvm::json::Object createDocument(); | ||
| 477 | |||
| 478 | private: | ||
| 479 |   /// Source Manager to use for the current SARIF document. | ||
| 480 | const SourceManager &SourceMgr; | ||
| 481 | |||
| 482 |   /// Flag to track the state of this document: | ||
| 483 |   /// A closed document is one on which a new runs must be created. | ||
| 484 |   /// This could be a document that is freshly created, or has recently | ||
| 485 |   /// finished writing to a previous run. | ||
| 486 | bool Closed = true; | ||
| 487 | |||
| 488 |   /// A sequence of SARIF runs. | ||
| 489 |   /// Each run object describes a single run of an analysis tool and contains | ||
| 490 |   /// the output of that run. | ||
| 491 |   /// | ||
| 492 |   /// Reference: <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317484">run object</a> | ||
| 493 | llvm::json::Array Runs; | ||
| 494 | |||
| 495 |   /// The list of rules associated with the most recent active run. These are | ||
| 496 |   /// defined using the diagnostics passed to the SarifDocument. Each rule | ||
| 497 |   /// need not be unique through the result set. E.g. there may be several | ||
| 498 |   /// 'syntax' errors throughout code under analysis, each of which has its | ||
| 499 |   /// own specific diagnostic message (and consequently, RuleId). Rules are | ||
| 500 |   /// also known as "reportingDescriptor" objects in SARIF. | ||
| 501 |   /// | ||
| 502 |   /// Reference: <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317556">rules property</a> | ||
| 503 | llvm::SmallVector<SarifRule, 32> CurrentRules; | ||
| 504 | |||
| 505 |   /// The list of artifacts that have been encountered on the most recent active | ||
| 506 |   /// run. An artifact is defined in SARIF as a sequence of bytes addressable | ||
| 507 |   /// by a URI. A common example for clang's case would be files named by | ||
| 508 |   /// filesystem paths. | ||
| 509 | llvm::StringMap<detail::SarifArtifact> CurrentArtifacts; | ||
| 510 | }; | ||
| 511 | } // namespace clang | ||
| 512 | |||
| 513 | #endif // LLVM_CLANG_BASIC_SARIF_H |