Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

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