Coverage Report

Created: 2021-02-23 11:24

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