Coverage Report

Created: 2022-07-16 07:03

/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_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/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 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 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
77
    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
8
    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
633
    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
2.05k
  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
222
  virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
157
158
19.9k
  bool shouldGenerateDiagnostics() const {
159
19.9k
    return getGenerationScheme() != None;
160
19.9k
  }
161
162
165k
  bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; }
163
18.2k
  bool shouldAddControlNotes() const {
164
18.2k
    return getGenerationScheme() == Minimal ||
165
18.2k
           
getGenerationScheme() == Everything2.25k
;
166
18.2k
  }
167
168
0
  virtual bool supportsLogicalOpControlFlow() const { return false; }
169
170
  /// Return true if the PathDiagnosticConsumer supports individual
171
  /// PathDiagnostics that span multiple files.
172
24
  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
134k
      : SourceRange(R), isPoint(isP) {}
189
78.9k
  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
17.7k
      : 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
78.9k
  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
116k
        Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
225
116k
    assert(K == SingleLocK || S);
226
0
    assert(K == SingleLocK || Loc.isValid());
227
0
    assert(K == SingleLocK || Range.isValid());
228
116k
  }
229
230
  /// Create a location corresponding to the given declaration.
231
  PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
232
309
      : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
233
309
    assert(D);
234
0
    assert(Loc.isValid());
235
0
    assert(Range.isValid());
236
309
  }
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
303
      : SM(&sm), Loc(loc, sm), Range(genRange()) {
243
303
    assert(Loc.isValid());
244
0
    assert(Range.isValid());
245
303
  }
246
247
  /// Create a location corresponding to the given declaration.
248
  static PathDiagnosticLocation create(const Decl *D,
249
280
                                       const SourceManager &SM) {
250
280
    return PathDiagnosticLocation(D, SM);
251
280
  }
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
0
              const LocationOrAnalysisDeclContext LAC) {
263
0
    return createBegin(D, SM);
264
0
  }
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
3.92k
  bool operator==(const PathDiagnosticLocation &X) const {
328
3.92k
    return K == X.K && 
Loc == X.Loc3.71k
&&
Range == X.Range1.89k
;
329
3.92k
  }
330
331
2.12k
  bool operator!=(const PathDiagnosticLocation &X) const {
332
2.12k
    return !(*this == X);
333
2.12k
  }
334
335
910k
  bool isValid() const {
336
910k
    return SM != nullptr;
337
910k
  }
338
339
608k
  FullSourceLoc asLocation() const {
340
608k
    return Loc;
341
608k
  }
342
343
37.2k
  PathDiagnosticRange asRange() const {
344
37.2k
    return Range;
345
37.2k
  }
346
347
310k
  const Stmt *asStmt() const { assert(isValid()); return S; }
348
98.8k
  const Stmt *getStmtOrNull() const {
349
98.8k
    if (!isValid())
350
0
      return nullptr;
351
98.8k
    return asStmt();
352
98.8k
  }
353
354
0
  const Decl *asDecl() const { assert(isValid()); return D; }
355
356
35.7k
  bool hasRange() const { return K == StmtK || 
K == RangeK4.75k
||
K == DeclK3.89k
; }
357
358
37.8k
  bool hasValidLocation() const { return asLocation().isValid(); }
359
360
256
  void invalidate() {
361
256
    *this = PathDiagnosticLocation();
362
256
  }
363
364
  void flatten();
365
366
646
  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
16.1k
      : Start(start), End(end) {}
381
382
97.6k
  const PathDiagnosticLocation &getStart() const { return Start; }
383
68.6k
  const PathDiagnosticLocation &getEnd() const { return End; }
384
385
1.03k
  void setStart(const PathDiagnosticLocation &L) { Start = L; }
386
10.5k
  void setEnd(const PathDiagnosticLocation &L) { End = L; }
387
388
3.60k
  void flatten() {
389
3.60k
    Start.flatten();
390
3.60k
    End.flatten();
391
3.60k
  }
392
393
0
  void Profile(llvm::FoldingSetNodeID &ID) const {
394
0
    Start.Profile(ID);
395
0
    End.Profile(ID);
396
0
  }
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
13.3k
  StringRef getString() const { return str; }
437
438
  /// Tag this PathDiagnosticPiece with the given C-string.
439
8.32k
  void setTag(const char *tag) { Tag = tag; }
440
441
  /// Return the opaque tag (if any) on the PathDiagnosticPiece.
442
331
  const void *getTag() const { return Tag.data(); }
443
444
  /// Return the string representation of the tag.  This is useful
445
  /// for debugging.
446
14
  StringRef getTagStr() const { return Tag; }
447
448
  /// getDisplayHint - Return a hint indicating where the diagnostic should
449
  ///  be displayed by the PathDiagnosticConsumer.
450
3.56k
  DisplayHint getDisplayHint() const { return Hint; }
451
452
  virtual PathDiagnosticLocation getLocation() const = 0;
453
  virtual void flattenLocations() = 0;
454
455
372k
  Kind getKind() const { return kind; }
456
457
52.6k
  void addRange(SourceRange R) {
458
52.6k
    if (!R.isValid())
459
6
      return;
460
52.6k
    ranges.push_back(R);
461
52.6k
  }
462
463
0
  void addRange(SourceLocation B, SourceLocation E) {
464
0
    if (!B.isValid() || !E.isValid())
465
0
      return;
466
0
    ranges.push_back(SourceRange(B,E));
467
0
  }
468
469
13
  void addFixit(FixItHint F) {
470
13
    fixits.push_back(F);
471
13
  }
472
473
  /// Return the SourceRanges associated with this PathDiagnosticPiece.
474
39.5k
  ArrayRef<SourceRange> getRanges() const { return ranges; }
475
476
  /// Return the fix-it hints associated with this PathDiagnosticPiece.
477
30.2k
  ArrayRef<FixItHint> getFixits() const { return fixits; }
478
479
  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
480
481
2
  void setAsLastInMainSourceFile() {
482
2
    LastInMainSourceFile = true;
483
2
  }
484
485
152
  bool isLastInMainSourceFile() const {
486
152
    return LastInMainSourceFile;
487
152
  }
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
22.8k
  PathPieces flatten(bool ShouldFlattenMacros) const {
500
22.8k
    PathPieces Result;
501
22.8k
    flattenTo(Result, Result, ShouldFlattenMacros);
502
22.8k
    return Result;
503
22.8k
  }
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
37.8k
      : PathDiagnosticPiece(s, k), Pos(pos) {
518
37.8k
    assert(Pos.isValid() && Pos.hasValidLocation() &&
519
37.8k
           "PathDiagnosticSpotPiece's must have a valid location.");
520
37.8k
    if (addPosRange && 
Pos.hasRange()35.7k
)
addRange(Pos.asRange())32.1k
;
521
37.8k
  }
522
523
73.8k
  PathDiagnosticLocation getLocation() const override { return Pos; }
524
24.9k
  void flattenLocations() override { Pos.flatten(); }
525
526
  void Profile(llvm::FoldingSetNodeID &ID) const override;
527
528
0
  static bool classof(const PathDiagnosticPiece *P) {
529
0
    return P->getKind() == Event || P->getKind() == Macro ||
530
0
           P->getKind() == Note || P->getKind() == PopUp;
531
0
  }
532
};
533
534
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
535
  Optional<bool> IsPrunable;
536
537
public:
538
  PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
539
                           StringRef s, bool addPosRange = true)
540
36.2k
      : 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
8.17k
  void setPrunable(bool isPrunable, bool override = false) {
547
8.17k
    if (IsPrunable && 
!override474
)
548
474
      return;
549
7.70k
    IsPrunable = isPrunable;
550
7.70k
  }
551
552
  /// Return true if the diagnostic piece is prunable.
553
5.58k
  bool isPrunable() const { return IsPrunable.value_or(false); }
554
555
  void dump() const override;
556
557
30.8k
  static bool classof(const PathDiagnosticPiece *P) {
558
30.8k
    return P->getKind() == Event;
559
30.8k
  }
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
7.02k
        callReturn(callReturnPos) {}
582
  PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
583
      : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
584
182
        path(oldPath) {}
585
586
public:
587
  PathDiagnosticLocation callEnter;
588
  PathDiagnosticLocation callEnterWithin;
589
  PathDiagnosticLocation callReturn;
590
  PathPieces path;
591
592
  ~PathDiagnosticCallPiece() override;
593
594
66
  const Decl *getCaller() const { return Caller; }
595
596
471
  const Decl *getCallee() const { return Callee; }
597
  void setCallee(const CallEnter &CE, const SourceManager &SM);
598
599
21
  bool hasCallStackMessage() { return !CallStackMessage.empty(); }
600
19
  void setCallStackMessage(StringRef st) { CallStackMessage = std::string(st); }
601
602
8.42k
  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
469
  void flattenLocations() override {
610
469
    callEnter.flatten();
611
469
    callReturn.flatten();
612
469
    for (const auto &I : path)
613
1.09k
      I->flattenLocations();
614
469
  }
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
98.0k
  static bool classof(const PathDiagnosticPiece *P) {
628
98.0k
    return P->getKind() == Call;
629
98.0k
  }
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
1.13k
      : PathDiagnosticPiece(s, ControlFlow) {
640
1.13k
    LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
641
1.13k
  }
642
643
  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
644
                                 const PathDiagnosticLocation &endPos)
645
14.9k
      : PathDiagnosticPiece(ControlFlow) {
646
14.9k
    LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
647
14.9k
  }
648
649
  ~PathDiagnosticControlFlowPiece() override;
650
651
95.0k
  PathDiagnosticLocation getStartLocation() const {
652
95.0k
    assert(!LPairs.empty() &&
653
95.0k
           "PathDiagnosticControlFlowPiece needs at least one location.");
654
0
    return LPairs[0].getStart();
655
95.0k
  }
656
657
66.1k
  PathDiagnosticLocation getEndLocation() const {
658
66.1k
    assert(!LPairs.empty() &&
659
66.1k
           "PathDiagnosticControlFlowPiece needs at least one location.");
660
0
    return LPairs[0].getEnd();
661
66.1k
  }
662
663
1.03k
  void setStartLocation(const PathDiagnosticLocation &L) {
664
1.03k
    LPairs[0].setStart(L);
665
1.03k
  }
666
667
10.5k
  void setEndLocation(const PathDiagnosticLocation &L) {
668
10.5k
    LPairs[0].setEnd(L);
669
10.5k
  }
670
671
0
  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
672
673
39.0k
  PathDiagnosticLocation getLocation() const override {
674
39.0k
    return getStartLocation();
675
39.0k
  }
676
677
  using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
678
679
3.60k
  iterator begin() { return LPairs.begin(); }
680
3.60k
  iterator end() { return LPairs.end(); }
681
682
3.60k
  void flattenLocations() override {
683
3.60k
    for (auto &I : *this)
684
3.60k
      I.flatten();
685
3.60k
  }
686
687
  using const_iterator =
688
      std::vector<PathDiagnosticLocationPair>::const_iterator;
689
690
2.53k
  const_iterator begin() const { return LPairs.begin(); }
691
2.53k
  const_iterator end() const { return LPairs.end(); }
692
693
85.1k
  static bool classof(const PathDiagnosticPiece *P) {
694
85.1k
    return P->getKind() == ControlFlow;
695
85.1k
  }
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
46
      : PathDiagnosticSpotPiece(pos, "", Macro) {}
706
  ~PathDiagnosticMacroPiece() override;
707
708
  PathPieces subPieces;
709
710
46
  void flattenLocations() override {
711
46
    PathDiagnosticSpotPiece::flattenLocations();
712
46
    for (const auto &I : subPieces)
713
94
      I->flattenLocations();
714
46
  }
715
716
38.5k
  static bool classof(const PathDiagnosticPiece *P) {
717
38.5k
    return P->getKind() == Macro;
718
38.5k
  }
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
227
      : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
730
  ~PathDiagnosticNotePiece() override;
731
732
31.4k
  static bool classof(const PathDiagnosticPiece *P) {
733
31.4k
    return P->getKind() == Note;
734
31.4k
  }
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
1.31k
      : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
746
  ~PathDiagnosticPopUpPiece() override;
747
748
1.96k
  static bool classof(const PathDiagnosticPiece *P) {
749
1.96k
    return P->getKind() == PopUp;
750
1.96k
  }
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
308k
  PathPieces &getActivePath() {
800
308k
    if (pathStack.empty())
801
166k
      return pathImpl;
802
142k
    return *pathStack.back();
803
308k
  }
804
805
  /// Return a mutable version of 'path'.
806
34.4k
  PathPieces &getMutablePieces() {
807
34.4k
    return pathImpl;
808
34.4k
  }
809
810
  /// Return the unrolled size of the path.
811
  unsigned full_size();
812
813
7.02k
  void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
814
7.20k
  void popActivePath() { if (!pathStack.empty()) 
pathStack.pop_back()7.02k
; }
815
816
7.20k
  bool isWithinCall() const { return !pathStack.empty(); }
817
818
21.2k
  void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
819
21.2k
    assert(!Loc.isValid() && "End location already set!");
820
0
    Loc = EndPiece->getLocation();
821
21.2k
    assert(Loc.isValid() && "Invalid location for end-of-path piece");
822
0
    getActivePath().push_back(std::move(EndPiece));
823
21.2k
  }
824
825
2
  void appendToDesc(StringRef S) {
826
2
    if (!ShortDesc.empty())
827
2
      ShortDesc += S;
828
2
    VerboseDesc += S;
829
2
  }
830
831
2.00k
  StringRef getVerboseDescription() const { return VerboseDesc; }
832
833
21.1k
  StringRef getShortDescription() const {
834
21.1k
    return ShortDesc.empty() ? 
VerboseDesc1.85k
:
ShortDesc19.2k
;
835
21.1k
  }
836
837
19.7k
  StringRef getCheckerName() const { return CheckerName; }
838
2.49k
  StringRef getBugType() const { return BugType; }
839
1.64k
  StringRef getCategory() const { return Category; }
840
841
  using meta_iterator = std::deque<std::string>::const_iterator;
842
843
132
  meta_iterator meta_begin() const { return OtherDesc.begin(); }
844
132
  meta_iterator meta_end() const { return OtherDesc.end(); }
845
0
  void addMeta(StringRef s) { OtherDesc.push_back(std::string(s)); }
846
847
737
  const FilesToLineNumsMap &getExecutedLines() const {
848
737
    return *ExecutedLines;
849
737
  }
850
851
21.2k
  FilesToLineNumsMap &getExecutedLines() {
852
21.2k
    return *ExecutedLines;
853
21.2k
  }
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
1.60k
  const Decl *getDeclWithIssue() const { return DeclWithIssue; }
859
860
2
  void setDeclWithIssue(const Decl *D) {
861
2
    DeclWithIssue = D;
862
2
  }
863
864
506k
  PathDiagnosticLocation getLocation() const {
865
506k
    return Loc;
866
506k
  }
867
868
2
  void setLocation(PathDiagnosticLocation NewLoc) {
869
2
    Loc = NewLoc;
870
2
  }
871
872
  /// Get the location on which the report should be uniqued.
873
82.8k
  PathDiagnosticLocation getUniqueingLoc() const {
874
82.8k
    return UniqueingLoc;
875
82.8k
  }
876
877
  /// Get the declaration containing the uniqueing location.
878
209
  const Decl *getUniqueingDecl() const {
879
209
    return UniqueingDecl;
880
209
  }
881
882
21.2k
  void flattenLocations() {
883
21.2k
    Loc.flatten();
884
21.2k
    for (const auto &I : pathImpl)
885
27.8k
      I->flattenLocations();
886
21.2k
  }
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