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
//===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- 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
//
9
//  This file defines the PathDiagnostic-related interfaces.
10
//
11
//===----------------------------------------------------------------------===//
12
 
13
#ifndef LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
14
#define LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
15
 
16
#include "clang/AST/Stmt.h"
17
#include "clang/Analysis/AnalysisDeclContext.h"
18
#include "clang/Basic/LLVM.h"
19
#include "clang/Basic/SourceLocation.h"
20
#include "llvm/ADT/ArrayRef.h"
21
#include "llvm/ADT/FoldingSet.h"
22
#include "llvm/ADT/PointerUnion.h"
23
#include "llvm/ADT/SmallVector.h"
24
#include "llvm/ADT/StringRef.h"
25
#include "llvm/Support/Allocator.h"
26
#include <cassert>
27
#include <deque>
28
#include <iterator>
29
#include <list>
30
#include <map>
31
#include <memory>
32
#include <optional>
33
#include <set>
34
#include <string>
35
#include <utility>
36
#include <vector>
37
 
38
namespace clang {
39
 
40
class AnalysisDeclContext;
41
class BinaryOperator;
42
class CallEnter;
43
class CallExitEnd;
44
class ConditionalOperator;
45
class Decl;
46
class LocationContext;
47
class MemberExpr;
48
class ProgramPoint;
49
class SourceManager;
50
 
51
namespace ento {
52
 
53
//===----------------------------------------------------------------------===//
54
// High-level interface for handlers of path-sensitive diagnostics.
55
//===----------------------------------------------------------------------===//
56
 
57
class PathDiagnostic;
58
 
59
/// These options tweak the behavior of path diangostic consumers.
60
/// Most of these options are currently supported by very few consumers.
61
struct PathDiagnosticConsumerOptions {
62
  /// Run-line of the tool that produced the diagnostic.
63
  /// It can be included with the diagnostic for debugging purposes.
64
  std::string ToolInvocation;
65
 
66
  /// Whether to include additional information about macro expansions
67
  /// with the diagnostics, because otherwise they can be hard to obtain
68
  /// without re-compiling the program under analysis.
69
  bool ShouldDisplayMacroExpansions = false;
70
 
71
  /// Whether to include LLVM statistics of the process in the diagnostic.
72
  /// Useful for profiling the tool on large real-world codebases.
73
  bool ShouldSerializeStats = false;
74
 
75
  /// If the consumer intends to produce multiple output files, should it
76
  /// use a pseudo-random file name or a human-readable file name.
77
  bool ShouldWriteVerboseReportFilename = false;
78
 
79
  /// Whether the consumer should treat consumed diagnostics as hard errors.
80
  /// Useful for breaking your build when issues are found.
81
  bool ShouldDisplayWarningsAsErrors = false;
82
 
83
  /// Whether the consumer should attempt to rewrite the source file
84
  /// with fix-it hints attached to the diagnostics it consumes.
85
  bool ShouldApplyFixIts = false;
86
 
87
  /// Whether the consumer should present the name of the entity that emitted
88
  /// the diagnostic (eg., a checker) so that the user knew how to disable it.
89
  bool ShouldDisplayDiagnosticName = false;
90
};
91
 
92
class PathDiagnosticConsumer {
93
public:
94
  class PDFileEntry : public llvm::FoldingSetNode {
95
  public:
96
    PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
97
 
98
    using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
99
 
100
    /// A vector of <consumer,file> pairs.
101
    ConsumerFiles files;
102
 
103
    /// A precomputed hash tag used for uniquing PDFileEntry objects.
104
    const llvm::FoldingSetNodeID NodeID;
105
 
106
    /// Used for profiling in the FoldingSet.
107
    void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
108
  };
109
 
110
  class FilesMade {
111
    llvm::BumpPtrAllocator Alloc;
112
    llvm::FoldingSet<PDFileEntry> Set;
113
 
114
  public:
115
    ~FilesMade();
116
 
117
    bool empty() const { return Set.empty(); }
118
 
119
    void addDiagnostic(const PathDiagnostic &PD,
120
                       StringRef ConsumerName,
121
                       StringRef fileName);
122
 
123
    PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
124
  };
125
 
126
private:
127
  virtual void anchor();
128
 
129
public:
130
  PathDiagnosticConsumer() = default;
131
  virtual ~PathDiagnosticConsumer();
132
 
133
  void FlushDiagnostics(FilesMade *FilesMade);
134
 
135
  virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
136
                                    FilesMade *filesMade) = 0;
137
 
138
  virtual StringRef getName() const = 0;
139
 
140
  void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
141
 
142
  enum PathGenerationScheme {
143
    /// Only runs visitors, no output generated.
144
    None,
145
 
146
    /// Used for SARIF and text output.
147
    Minimal,
148
 
149
    /// Used for plist output, used for "arrows" generation.
150
    Extensive,
151
 
152
    /// Used for HTML, shows both "arrows" and control notes.
153
    Everything
154
  };
155
 
156
  virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
157
 
158
  bool shouldGenerateDiagnostics() const {
159
    return getGenerationScheme() != None;
160
  }
161
 
162
  bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; }
163
  bool shouldAddControlNotes() const {
164
    return getGenerationScheme() == Minimal ||
165
           getGenerationScheme() == Everything;
166
  }
167
 
168
  virtual bool supportsLogicalOpControlFlow() const { return false; }
169
 
170
  /// Return true if the PathDiagnosticConsumer supports individual
171
  /// PathDiagnostics that span multiple files.
172
  virtual bool supportsCrossFileDiagnostics() const { return false; }
173
 
174
protected:
175
  bool flushed = false;
176
  llvm::FoldingSet<PathDiagnostic> Diags;
177
};
178
 
179
//===----------------------------------------------------------------------===//
180
// Path-sensitive diagnostics.
181
//===----------------------------------------------------------------------===//
182
 
183
class PathDiagnosticRange : public SourceRange {
184
public:
185
  bool isPoint = false;
186
 
187
  PathDiagnosticRange(SourceRange R, bool isP = false)
188
      : SourceRange(R), isPoint(isP) {}
189
  PathDiagnosticRange() = default;
190
};
191
 
192
using LocationOrAnalysisDeclContext =
193
    llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
194
 
195
class PathDiagnosticLocation {
196
private:
197
  enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
198
 
199
  const Stmt *S = nullptr;
200
  const Decl *D = nullptr;
201
  const SourceManager *SM = nullptr;
202
  FullSourceLoc Loc;
203
  PathDiagnosticRange Range;
204
 
205
  PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
206
      : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
207
 
208
  FullSourceLoc genLocation(
209
      SourceLocation L = SourceLocation(),
210
      LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
211
 
212
  PathDiagnosticRange genRange(
213
      LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
214
 
215
public:
216
  /// Create an invalid location.
217
  PathDiagnosticLocation() = default;
218
 
219
  /// Create a location corresponding to the given statement.
220
  PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
221
                         LocationOrAnalysisDeclContext lac)
222
      : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
223
        S(K == StmtK ? s : nullptr), SM(&sm),
224
        Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
225
    assert(K == SingleLocK || S);
226
    assert(K == SingleLocK || Loc.isValid());
227
    assert(K == SingleLocK || Range.isValid());
228
  }
229
 
230
  /// Create a location corresponding to the given declaration.
231
  PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
232
      : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
233
    assert(D);
234
    assert(Loc.isValid());
235
    assert(Range.isValid());
236
  }
237
 
238
  /// Create a location at an explicit offset in the source.
239
  ///
240
  /// This should only be used if there are no more appropriate constructors.
241
  PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
242
      : SM(&sm), Loc(loc, sm), Range(genRange()) {
243
    assert(Loc.isValid());
244
    assert(Range.isValid());
245
  }
246
 
247
  /// Create a location corresponding to the given declaration.
248
  static PathDiagnosticLocation create(const Decl *D,
249
                                       const SourceManager &SM) {
250
    return PathDiagnosticLocation(D, SM);
251
  }
252
 
253
  /// Create a location for the beginning of the declaration.
254
  static PathDiagnosticLocation createBegin(const Decl *D,
255
                                            const SourceManager &SM);
256
 
257
  /// Create a location for the beginning of the declaration.
258
  /// The third argument is ignored, useful for generic treatment
259
  /// of statements and declarations.
260
  static PathDiagnosticLocation
261
  createBegin(const Decl *D, const SourceManager &SM,
262
              const LocationOrAnalysisDeclContext LAC) {
263
    return createBegin(D, SM);
264
  }
265
 
266
  /// Create a location for the beginning of the statement.
267
  static PathDiagnosticLocation createBegin(const Stmt *S,
268
                                            const SourceManager &SM,
269
                                            const LocationOrAnalysisDeclContext LAC);
270
 
271
  /// Create a location for the end of the statement.
272
  ///
273
  /// If the statement is a CompoundStatement, the location will point to the
274
  /// closing brace instead of following it.
275
  static PathDiagnosticLocation createEnd(const Stmt *S,
276
                                          const SourceManager &SM,
277
                                       const LocationOrAnalysisDeclContext LAC);
278
 
279
  /// Create the location for the operator of the binary expression.
280
  /// Assumes the statement has a valid location.
281
  static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
282
                                                  const SourceManager &SM);
283
  static PathDiagnosticLocation createConditionalColonLoc(
284
                                                  const ConditionalOperator *CO,
285
                                                  const SourceManager &SM);
286
 
287
  /// For member expressions, return the location of the '.' or '->'.
288
  /// Assumes the statement has a valid location.
289
  static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
290
                                                const SourceManager &SM);
291
 
292
  /// Create a location for the beginning of the compound statement.
293
  /// Assumes the statement has a valid location.
294
  static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
295
                                                 const SourceManager &SM);
296
 
297
  /// Create a location for the end of the compound statement.
298
  /// Assumes the statement has a valid location.
299
  static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
300
                                               const SourceManager &SM);
301
 
302
  /// Create a location for the beginning of the enclosing declaration body.
303
  /// Defaults to the beginning of the first statement in the declaration body.
304
  static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
305
                                                const SourceManager &SM);
306
 
307
  /// Constructs a location for the end of the enclosing declaration body.
308
  /// Defaults to the end of brace.
309
  static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
310
                                                   const SourceManager &SM);
311
 
312
  /// Create a location corresponding to the given valid ProgramPoint.
313
  static PathDiagnosticLocation create(const ProgramPoint &P,
314
                                       const SourceManager &SMng);
315
 
316
  /// Convert the given location into a single kind location.
317
  static PathDiagnosticLocation createSingleLocation(
318
                                             const PathDiagnosticLocation &PDL);
319
 
320
  /// Construct a source location that corresponds to either the beginning
321
  /// or the end of the given statement, or a nearby valid source location
322
  /// if the statement does not have a valid source location of its own.
323
  static SourceLocation
324
  getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
325
                         bool UseEndOfStatement = false);
326
 
327
  bool operator==(const PathDiagnosticLocation &X) const {
328
    return K == X.K && Loc == X.Loc && Range == X.Range;
329
  }
330
 
331
  bool operator!=(const PathDiagnosticLocation &X) const {
332
    return !(*this == X);
333
  }
334
 
335
  bool isValid() const {
336
    return SM != nullptr;
337
  }
338
 
339
  FullSourceLoc asLocation() const {
340
    return Loc;
341
  }
342
 
343
  PathDiagnosticRange asRange() const {
344
    return Range;
345
  }
346
 
347
  const Stmt *asStmt() const { assert(isValid()); return S; }
348
  const Stmt *getStmtOrNull() const {
349
    if (!isValid())
350
      return nullptr;
351
    return asStmt();
352
  }
353
 
354
  const Decl *asDecl() const { assert(isValid()); return D; }
355
 
356
  bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
357
 
358
  bool hasValidLocation() const { return asLocation().isValid(); }
359
 
360
  void invalidate() {
361
    *this = PathDiagnosticLocation();
362
  }
363
 
364
  void flatten();
365
 
366
  const SourceManager& getManager() const { assert(isValid()); return *SM; }
367
 
368
  void Profile(llvm::FoldingSetNodeID &ID) const;
369
 
370
  void dump() const;
371
};
372
 
373
class PathDiagnosticLocationPair {
374
private:
375
  PathDiagnosticLocation Start, End;
376
 
377
public:
378
  PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
379
                             const PathDiagnosticLocation &end)
380
      : Start(start), End(end) {}
381
 
382
  const PathDiagnosticLocation &getStart() const { return Start; }
383
  const PathDiagnosticLocation &getEnd() const { return End; }
384
 
385
  void setStart(const PathDiagnosticLocation &L) { Start = L; }
386
  void setEnd(const PathDiagnosticLocation &L) { End = L; }
387
 
388
  void flatten() {
389
    Start.flatten();
390
    End.flatten();
391
  }
392
 
393
  void Profile(llvm::FoldingSetNodeID &ID) const {
394
    Start.Profile(ID);
395
    End.Profile(ID);
396
  }
397
};
398
 
399
//===----------------------------------------------------------------------===//
400
// Path "pieces" for path-sensitive diagnostics.
401
//===----------------------------------------------------------------------===//
402
 
403
class PathDiagnosticPiece: public llvm::FoldingSetNode {
404
public:
405
  enum Kind { ControlFlow, Event, Macro, Call, Note, PopUp };
406
  enum DisplayHint { Above, Below };
407
 
408
private:
409
  const std::string str;
410
  const Kind kind;
411
  const DisplayHint Hint;
412
 
413
  /// In the containing bug report, this piece is the last piece from
414
  /// the main source file.
415
  bool LastInMainSourceFile = false;
416
 
417
  /// A constant string that can be used to tag the PathDiagnosticPiece,
418
  /// typically with the identification of the creator.  The actual pointer
419
  /// value is meant to be an identifier; the string itself is useful for
420
  /// debugging.
421
  StringRef Tag;
422
 
423
  std::vector<SourceRange> ranges;
424
  std::vector<FixItHint> fixits;
425
 
426
protected:
427
  PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
428
  PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
429
 
430
public:
431
  PathDiagnosticPiece() = delete;
432
  PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
433
  PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
434
  virtual ~PathDiagnosticPiece();
435
 
436
  StringRef getString() const { return str; }
437
 
438
  /// Tag this PathDiagnosticPiece with the given C-string.
439
  void setTag(const char *tag) { Tag = tag; }
440
 
441
  /// Return the opaque tag (if any) on the PathDiagnosticPiece.
442
  const void *getTag() const { return Tag.data(); }
443
 
444
  /// Return the string representation of the tag.  This is useful
445
  /// for debugging.
446
  StringRef getTagStr() const { return Tag; }
447
 
448
  /// getDisplayHint - Return a hint indicating where the diagnostic should
449
  ///  be displayed by the PathDiagnosticConsumer.
450
  DisplayHint getDisplayHint() const { return Hint; }
451
 
452
  virtual PathDiagnosticLocation getLocation() const = 0;
453
  virtual void flattenLocations() = 0;
454
 
455
  Kind getKind() const { return kind; }
456
 
457
  void addRange(SourceRange R) {
458
    if (!R.isValid())
459
      return;
460
    ranges.push_back(R);
461
  }
462
 
463
  void addRange(SourceLocation B, SourceLocation E) {
464
    if (!B.isValid() || !E.isValid())
465
      return;
466
    ranges.push_back(SourceRange(B,E));
467
  }
468
 
469
  void addFixit(FixItHint F) {
470
    fixits.push_back(F);
471
  }
472
 
473
  /// Return the SourceRanges associated with this PathDiagnosticPiece.
474
  ArrayRef<SourceRange> getRanges() const { return ranges; }
475
 
476
  /// Return the fix-it hints associated with this PathDiagnosticPiece.
477
  ArrayRef<FixItHint> getFixits() const { return fixits; }
478
 
479
  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
480
 
481
  void setAsLastInMainSourceFile() {
482
    LastInMainSourceFile = true;
483
  }
484
 
485
  bool isLastInMainSourceFile() const {
486
    return LastInMainSourceFile;
487
  }
488
 
489
  virtual void dump() const = 0;
490
};
491
 
492
using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
493
 
494
class PathPieces : public std::list<PathDiagnosticPieceRef> {
495
  void flattenTo(PathPieces &Primary, PathPieces &Current,
496
                 bool ShouldFlattenMacros) const;
497
 
498
public:
499
  PathPieces flatten(bool ShouldFlattenMacros) const {
500
    PathPieces Result;
501
    flattenTo(Result, Result, ShouldFlattenMacros);
502
    return Result;
503
  }
504
 
505
  void dump() const;
506
};
507
 
508
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
509
private:
510
  PathDiagnosticLocation Pos;
511
 
512
public:
513
  PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
514
                          StringRef s,
515
                          PathDiagnosticPiece::Kind k,
516
                          bool addPosRange = true)
517
      : PathDiagnosticPiece(s, k), Pos(pos) {
518
    assert(Pos.isValid() && Pos.hasValidLocation() &&
519
           "PathDiagnosticSpotPiece's must have a valid location.");
520
    if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
521
  }
522
 
523
  PathDiagnosticLocation getLocation() const override { return Pos; }
524
  void flattenLocations() override { Pos.flatten(); }
525
 
526
  void Profile(llvm::FoldingSetNodeID &ID) const override;
527
 
528
  static bool classof(const PathDiagnosticPiece *P) {
529
    return P->getKind() == Event || P->getKind() == Macro ||
530
           P->getKind() == Note || P->getKind() == PopUp;
531
  }
532
};
533
 
534
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
535
  std::optional<bool> IsPrunable;
536
 
537
public:
538
  PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
539
                           StringRef s, bool addPosRange = true)
540
      : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
541
  ~PathDiagnosticEventPiece() override;
542
 
543
  /// Mark the diagnostic piece as being potentially prunable.  This
544
  /// flag may have been previously set, at which point it will not
545
  /// be reset unless one specifies to do so.
546
  void setPrunable(bool isPrunable, bool override = false) {
547
    if (IsPrunable && !override)
548
      return;
549
    IsPrunable = isPrunable;
550
  }
551
 
552
  /// Return true if the diagnostic piece is prunable.
553
  bool isPrunable() const { return IsPrunable.value_or(false); }
554
 
555
  void dump() const override;
556
 
557
  static bool classof(const PathDiagnosticPiece *P) {
558
    return P->getKind() == Event;
559
  }
560
};
561
 
562
class PathDiagnosticCallPiece : public PathDiagnosticPiece {
563
  const Decl *Caller;
564
  const Decl *Callee = nullptr;
565
 
566
  // Flag signifying that this diagnostic has only call enter and no matching
567
  // call exit.
568
  bool NoExit;
569
 
570
  // Flag signifying that the callee function is an Objective-C autosynthesized
571
  // property getter or setter.
572
  bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
573
 
574
  // The custom string, which should appear after the call Return Diagnostic.
575
  // TODO: Should we allow multiple diagnostics?
576
  std::string CallStackMessage;
577
 
578
  PathDiagnosticCallPiece(const Decl *callerD,
579
                          const PathDiagnosticLocation &callReturnPos)
580
      : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
581
        callReturn(callReturnPos) {}
582
  PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
583
      : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
584
        path(oldPath) {}
585
 
586
public:
587
  PathDiagnosticLocation callEnter;
588
  PathDiagnosticLocation callEnterWithin;
589
  PathDiagnosticLocation callReturn;
590
  PathPieces path;
591
 
592
  ~PathDiagnosticCallPiece() override;
593
 
594
  const Decl *getCaller() const { return Caller; }
595
 
596
  const Decl *getCallee() const { return Callee; }
597
  void setCallee(const CallEnter &CE, const SourceManager &SM);
598
 
599
  bool hasCallStackMessage() { return !CallStackMessage.empty(); }
600
  void setCallStackMessage(StringRef st) { CallStackMessage = std::string(st); }
601
 
602
  PathDiagnosticLocation getLocation() const override { return callEnter; }
603
 
604
  std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
605
  std::shared_ptr<PathDiagnosticEventPiece>
606
  getCallEnterWithinCallerEvent() const;
607
  std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
608
 
609
  void flattenLocations() override {
610
    callEnter.flatten();
611
    callReturn.flatten();
612
    for (const auto &I : path)
613
      I->flattenLocations();
614
  }
615
 
616
  static std::shared_ptr<PathDiagnosticCallPiece>
617
  construct(const CallExitEnd &CE,
618
            const SourceManager &SM);
619
 
620
  static PathDiagnosticCallPiece *construct(PathPieces &pieces,
621
                                            const Decl *caller);
622
 
623
  void dump() const override;
624
 
625
  void Profile(llvm::FoldingSetNodeID &ID) const override;
626
 
627
  static bool classof(const PathDiagnosticPiece *P) {
628
    return P->getKind() == Call;
629
  }
630
};
631
 
632
class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
633
  std::vector<PathDiagnosticLocationPair> LPairs;
634
 
635
public:
636
  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
637
                                 const PathDiagnosticLocation &endPos,
638
                                 StringRef s)
639
      : PathDiagnosticPiece(s, ControlFlow) {
640
    LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
641
  }
642
 
643
  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
644
                                 const PathDiagnosticLocation &endPos)
645
      : PathDiagnosticPiece(ControlFlow) {
646
    LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
647
  }
648
 
649
  ~PathDiagnosticControlFlowPiece() override;
650
 
651
  PathDiagnosticLocation getStartLocation() const {
652
    assert(!LPairs.empty() &&
653
           "PathDiagnosticControlFlowPiece needs at least one location.");
654
    return LPairs[0].getStart();
655
  }
656
 
657
  PathDiagnosticLocation getEndLocation() const {
658
    assert(!LPairs.empty() &&
659
           "PathDiagnosticControlFlowPiece needs at least one location.");
660
    return LPairs[0].getEnd();
661
  }
662
 
663
  void setStartLocation(const PathDiagnosticLocation &L) {
664
    LPairs[0].setStart(L);
665
  }
666
 
667
  void setEndLocation(const PathDiagnosticLocation &L) {
668
    LPairs[0].setEnd(L);
669
  }
670
 
671
  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
672
 
673
  PathDiagnosticLocation getLocation() const override {
674
    return getStartLocation();
675
  }
676
 
677
  using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
678
 
679
  iterator begin() { return LPairs.begin(); }
680
  iterator end() { return LPairs.end(); }
681
 
682
  void flattenLocations() override {
683
    for (auto &I : *this)
684
      I.flatten();
685
  }
686
 
687
  using const_iterator =
688
      std::vector<PathDiagnosticLocationPair>::const_iterator;
689
 
690
  const_iterator begin() const { return LPairs.begin(); }
691
  const_iterator end() const { return LPairs.end(); }
692
 
693
  static bool classof(const PathDiagnosticPiece *P) {
694
    return P->getKind() == ControlFlow;
695
  }
696
 
697
  void dump() const override;
698
 
699
  void Profile(llvm::FoldingSetNodeID &ID) const override;
700
};
701
 
702
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
703
public:
704
  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
705
      : PathDiagnosticSpotPiece(pos, "", Macro) {}
706
  ~PathDiagnosticMacroPiece() override;
707
 
708
  PathPieces subPieces;
709
 
710
  void flattenLocations() override {
711
    PathDiagnosticSpotPiece::flattenLocations();
712
    for (const auto &I : subPieces)
713
      I->flattenLocations();
714
  }
715
 
716
  static bool classof(const PathDiagnosticPiece *P) {
717
    return P->getKind() == Macro;
718
  }
719
 
720
  void dump() const override;
721
 
722
  void Profile(llvm::FoldingSetNodeID &ID) const override;
723
};
724
 
725
class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
726
public:
727
  PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
728
                          bool AddPosRange = true)
729
      : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
730
  ~PathDiagnosticNotePiece() override;
731
 
732
  static bool classof(const PathDiagnosticPiece *P) {
733
    return P->getKind() == Note;
734
  }
735
 
736
  void dump() const override;
737
 
738
  void Profile(llvm::FoldingSetNodeID &ID) const override;
739
};
740
 
741
class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
742
public:
743
  PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
744
                           bool AddPosRange = true)
745
      : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
746
  ~PathDiagnosticPopUpPiece() override;
747
 
748
  static bool classof(const PathDiagnosticPiece *P) {
749
    return P->getKind() == PopUp;
750
  }
751
 
752
  void dump() const override;
753
 
754
  void Profile(llvm::FoldingSetNodeID &ID) const override;
755
};
756
 
757
/// File IDs mapped to sets of line numbers.
758
using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
759
 
760
/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
761
///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
762
///  each which represent the pieces of the path.
763
class PathDiagnostic : public llvm::FoldingSetNode {
764
  std::string CheckerName;
765
  const Decl *DeclWithIssue;
766
  std::string BugType;
767
  std::string VerboseDesc;
768
  std::string ShortDesc;
769
  std::string Category;
770
  std::deque<std::string> OtherDesc;
771
 
772
  /// Loc The location of the path diagnostic report.
773
  PathDiagnosticLocation Loc;
774
 
775
  PathPieces pathImpl;
776
  SmallVector<PathPieces *, 3> pathStack;
777
 
778
  /// Important bug uniqueing location.
779
  /// The location info is useful to differentiate between bugs.
780
  PathDiagnosticLocation UniqueingLoc;
781
  const Decl *UniqueingDecl;
782
 
783
  /// Lines executed in the path.
784
  std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
785
 
786
public:
787
  PathDiagnostic() = delete;
788
  PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
789
                 StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
790
                 StringRef category, PathDiagnosticLocation LocationToUnique,
791
                 const Decl *DeclToUnique,
792
                 std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
793
  ~PathDiagnostic();
794
 
795
  const PathPieces &path;
796
 
797
  /// Return the path currently used by builders for constructing the
798
  /// PathDiagnostic.
799
  PathPieces &getActivePath() {
800
    if (pathStack.empty())
801
      return pathImpl;
802
    return *pathStack.back();
803
  }
804
 
805
  /// Return a mutable version of 'path'.
806
  PathPieces &getMutablePieces() {
807
    return pathImpl;
808
  }
809
 
810
  /// Return the unrolled size of the path.
811
  unsigned full_size();
812
 
813
  void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
814
  void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
815
 
816
  bool isWithinCall() const { return !pathStack.empty(); }
817
 
818
  void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
819
    assert(!Loc.isValid() && "End location already set!");
820
    Loc = EndPiece->getLocation();
821
    assert(Loc.isValid() && "Invalid location for end-of-path piece");
822
    getActivePath().push_back(std::move(EndPiece));
823
  }
824
 
825
  void appendToDesc(StringRef S) {
826
    if (!ShortDesc.empty())
827
      ShortDesc += S;
828
    VerboseDesc += S;
829
  }
830
 
831
  StringRef getVerboseDescription() const { return VerboseDesc; }
832
 
833
  StringRef getShortDescription() const {
834
    return ShortDesc.empty() ? VerboseDesc : ShortDesc;
835
  }
836
 
837
  StringRef getCheckerName() const { return CheckerName; }
838
  StringRef getBugType() const { return BugType; }
839
  StringRef getCategory() const { return Category; }
840
 
841
  using meta_iterator = std::deque<std::string>::const_iterator;
842
 
843
  meta_iterator meta_begin() const { return OtherDesc.begin(); }
844
  meta_iterator meta_end() const { return OtherDesc.end(); }
845
  void addMeta(StringRef s) { OtherDesc.push_back(std::string(s)); }
846
 
847
  const FilesToLineNumsMap &getExecutedLines() const {
848
    return *ExecutedLines;
849
  }
850
 
851
  FilesToLineNumsMap &getExecutedLines() {
852
    return *ExecutedLines;
853
  }
854
 
855
  /// Return the semantic context where an issue occurred.  If the
856
  /// issue occurs along a path, this represents the "central" area
857
  /// where the bug manifests.
858
  const Decl *getDeclWithIssue() const { return DeclWithIssue; }
859
 
860
  void setDeclWithIssue(const Decl *D) {
861
    DeclWithIssue = D;
862
  }
863
 
864
  PathDiagnosticLocation getLocation() const {
865
    return Loc;
866
  }
867
 
868
  void setLocation(PathDiagnosticLocation NewLoc) {
869
    Loc = NewLoc;
870
  }
871
 
872
  /// Get the location on which the report should be uniqued.
873
  PathDiagnosticLocation getUniqueingLoc() const {
874
    return UniqueingLoc;
875
  }
876
 
877
  /// Get the declaration containing the uniqueing location.
878
  const Decl *getUniqueingDecl() const {
879
    return UniqueingDecl;
880
  }
881
 
882
  void flattenLocations() {
883
    Loc.flatten();
884
    for (const auto &I : pathImpl)
885
      I->flattenLocations();
886
  }
887
 
888
  /// Profiles the diagnostic, independent of the path it references.
889
  ///
890
  /// This can be used to merge diagnostics that refer to the same issue
891
  /// along different paths.
892
  void Profile(llvm::FoldingSetNodeID &ID) const;
893
 
894
  /// Profiles the diagnostic, including its path.
895
  ///
896
  /// Two diagnostics with the same issue along different paths will generate
897
  /// different profiles.
898
  void FullProfile(llvm::FoldingSetNodeID &ID) const;
899
};
900
 
901
} // namespace ento
902
} // namespace clang
903
 
904
#endif // LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H