Coverage Report

Created: 2022-05-17 06:19

/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.01k
  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.3k
  bool shouldGenerateDiagnostics() const {
159
19.3k
    return getGenerationScheme() != None;
160
19.3k
  }
161
162
162k
  bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; }
163
17.9k
  bool shouldAddControlNotes() const {
164
17.9k
    return getGenerationScheme() == Minimal ||
165
17.9k
           
getGenerationScheme() == Everything2.25k
;
166
17.9k
  }
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
132k
      : SourceRange(R), isPoint(isP) {}
189
77.0k
  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.5k
      : 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
77.0k
  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
113k
        Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
225
113k
    assert(K == SingleLocK || S);
226
0
    assert(K == SingleLocK || Loc.isValid());
227
0
    assert(K == SingleLocK || Range.isValid());
228
113k
  }
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
899k
  bool isValid() const {
336
899k
    return SM != nullptr;
337
899k
  }
338
339
594k
  FullSourceLoc asLocation() const {
340
594k
    return Loc;
341
594k
  }
342
343
36.2k
  PathDiagnosticRange asRange() const {
344
36.2k
    return Range;
345
36.2k
  }
346
347
307k
  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
34.6k
  bool hasRange() const { return K == StmtK || 
K == RangeK4.74k
||
K == DeclK3.87k
; }
357
358
36.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.0k
      : Start(start), End(end) {}
381
382
97.5k
  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.59k
  void flatten() {
389
3.59k
    Start.flatten();
390
3.59k
    End.flatten();
391
3.59k
  }
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
7.85k
  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.54k
  DisplayHint getDisplayHint() const { return Hint; }
451
452
  virtual PathDiagnosticLocation getLocation() const = 0;
453
  virtual void flattenLocations() = 0;
454
455
343k
  Kind getKind() const { return kind; }
456
457
51.0k
  void addRange(SourceRange R) {
458
51.0k
    if (!R.isValid())
459
6
      return;
460
51.0k
    ranges.push_back(R);
461
51.0k
  }
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
38.9k
  ArrayRef<SourceRange> getRanges() const { return ranges; }
475
476
  /// Return the fix-it hints associated with this PathDiagnosticPiece.
477
29.6k
  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.2k
  PathPieces flatten(bool ShouldFlattenMacros) const {
500
22.2k
    PathPieces Result;
501
22.2k
    flattenTo(Result, Result, ShouldFlattenMacros);
502
22.2k
    return Result;
503
22.2k
  }
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
36.7k
      : PathDiagnosticPiece(s, k), Pos(pos) {
518
36.7k
    assert(Pos.isValid() && Pos.hasValidLocation() &&
519
36.7k
           "PathDiagnosticSpotPiece's must have a valid location.");
520
36.7k
    if (addPosRange && 
Pos.hasRange()34.6k
)
addRange(Pos.asRange())31.1k
;
521
36.7k
  }
522
523
72.5k
  PathDiagnosticLocation getLocation() const override { return Pos; }
524
24.4k
  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
35.1k
      : 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
7.70k
  void setPrunable(bool isPrunable, bool override = false) {
547
7.70k
    if (IsPrunable.hasValue() && 
!override469
)
548
469
     return;
549
7.23k
    IsPrunable = isPrunable;
550
7.23k
  }
551
552
  /// Return true if the diagnostic piece is prunable.
553
5.55k
  bool isPrunable() const {
554
5.55k
    return IsPrunable.getValueOr(false);
555
5.55k
  }
556
557
  void dump() const override;
558
559
21.3k
  static bool classof(const PathDiagnosticPiece *P) {
560
21.3k
    return P->getKind() == Event;
561
21.3k
  }
562
};
563
564
class PathDiagnosticCallPiece : public PathDiagnosticPiece {
565
  const Decl *Caller;
566
  const Decl *Callee = nullptr;
567
568
  // Flag signifying that this diagnostic has only call enter and no matching
569
  // call exit.
570
  bool NoExit;
571
572
  // Flag signifying that the callee function is an Objective-C autosynthesized
573
  // property getter or setter.
574
  bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
575
576
  // The custom string, which should appear after the call Return Diagnostic.
577
  // TODO: Should we allow multiple diagnostics?
578
  std::string CallStackMessage;
579
580
  PathDiagnosticCallPiece(const Decl *callerD,
581
                          const PathDiagnosticLocation &callReturnPos)
582
      : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
583
6.92k
        callReturn(callReturnPos) {}
584
  PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
585
      : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
586
180
        path(oldPath) {}
587
588
public:
589
  PathDiagnosticLocation callEnter;
590
  PathDiagnosticLocation callEnterWithin;
591
  PathDiagnosticLocation callReturn;
592
  PathPieces path;
593
594
  ~PathDiagnosticCallPiece() override;
595
596
66
  const Decl *getCaller() const { return Caller; }
597
598
469
  const Decl *getCallee() const { return Callee; }
599
  void setCallee(const CallEnter &CE, const SourceManager &SM);
600
601
21
  bool hasCallStackMessage() { return !CallStackMessage.empty(); }
602
19
  void setCallStackMessage(StringRef st) { CallStackMessage = std::string(st); }
603
604
8.32k
  PathDiagnosticLocation getLocation() const override { return callEnter; }
605
606
  std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
607
  std::shared_ptr<PathDiagnosticEventPiece>
608
  getCallEnterWithinCallerEvent() const;
609
  std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
610
611
467
  void flattenLocations() override {
612
467
    callEnter.flatten();
613
467
    callReturn.flatten();
614
467
    for (const auto &I : path)
615
1.09k
      I->flattenLocations();
616
467
  }
617
618
  static std::shared_ptr<PathDiagnosticCallPiece>
619
  construct(const CallExitEnd &CE,
620
            const SourceManager &SM);
621
622
  static PathDiagnosticCallPiece *construct(PathPieces &pieces,
623
                                            const Decl *caller);
624
625
  void dump() const override;
626
627
  void Profile(llvm::FoldingSetNodeID &ID) const override;
628
629
82.3k
  static bool classof(const PathDiagnosticPiece *P) {
630
82.3k
    return P->getKind() == Call;
631
82.3k
  }
632
};
633
634
class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
635
  std::vector<PathDiagnosticLocationPair> LPairs;
636
637
public:
638
  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
639
                                 const PathDiagnosticLocation &endPos,
640
                                 StringRef s)
641
1.09k
      : PathDiagnosticPiece(s, ControlFlow) {
642
1.09k
    LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
643
1.09k
  }
644
645
  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
646
                                 const PathDiagnosticLocation &endPos)
647
14.9k
      : PathDiagnosticPiece(ControlFlow) {
648
14.9k
    LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
649
14.9k
  }
650
651
  ~PathDiagnosticControlFlowPiece() override;
652
653
95.0k
  PathDiagnosticLocation getStartLocation() const {
654
95.0k
    assert(!LPairs.empty() &&
655
95.0k
           "PathDiagnosticControlFlowPiece needs at least one location.");
656
0
    return LPairs[0].getStart();
657
95.0k
  }
658
659
66.1k
  PathDiagnosticLocation getEndLocation() const {
660
66.1k
    assert(!LPairs.empty() &&
661
66.1k
           "PathDiagnosticControlFlowPiece needs at least one location.");
662
0
    return LPairs[0].getEnd();
663
66.1k
  }
664
665
1.03k
  void setStartLocation(const PathDiagnosticLocation &L) {
666
1.03k
    LPairs[0].setStart(L);
667
1.03k
  }
668
669
10.5k
  void setEndLocation(const PathDiagnosticLocation &L) {
670
10.5k
    LPairs[0].setEnd(L);
671
10.5k
  }
672
673
0
  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
674
675
38.9k
  PathDiagnosticLocation getLocation() const override {
676
38.9k
    return getStartLocation();
677
38.9k
  }
678
679
  using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
680
681
3.59k
  iterator begin() { return LPairs.begin(); }
682
3.59k
  iterator end() { return LPairs.end(); }
683
684
3.59k
  void flattenLocations() override {
685
3.59k
    for (auto &I : *this)
686
3.59k
      I.flatten();
687
3.59k
  }
688
689
  using const_iterator =
690
      std::vector<PathDiagnosticLocationPair>::const_iterator;
691
692
2.53k
  const_iterator begin() const { return LPairs.begin(); }
693
2.53k
  const_iterator end() const { return LPairs.end(); }
694
695
82.5k
  static bool classof(const PathDiagnosticPiece *P) {
696
82.5k
    return P->getKind() == ControlFlow;
697
82.5k
  }
698
699
  void dump() const override;
700
701
  void Profile(llvm::FoldingSetNodeID &ID) const override;
702
};
703
704
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
705
public:
706
  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
707
46
      : PathDiagnosticSpotPiece(pos, "", Macro) {}
708
  ~PathDiagnosticMacroPiece() override;
709
710
  PathPieces subPieces;
711
712
46
  void flattenLocations() override {
713
46
    PathDiagnosticSpotPiece::flattenLocations();
714
46
    for (const auto &I : subPieces)
715
94
      I->flattenLocations();
716
46
  }
717
718
38.3k
  static bool classof(const PathDiagnosticPiece *P) {
719
38.3k
    return P->getKind() == Macro;
720
38.3k
  }
721
722
  void dump() const override;
723
724
  void Profile(llvm::FoldingSetNodeID &ID) const override;
725
};
726
727
class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
728
public:
729
  PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
730
                          bool AddPosRange = true)
731
227
      : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
732
  ~PathDiagnosticNotePiece() override;
733
734
30.7k
  static bool classof(const PathDiagnosticPiece *P) {
735
30.7k
    return P->getKind() == Note;
736
30.7k
  }
737
738
  void dump() const override;
739
740
  void Profile(llvm::FoldingSetNodeID &ID) const override;
741
};
742
743
class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
744
public:
745
  PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
746
                           bool AddPosRange = true)
747
1.29k
      : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
748
  ~PathDiagnosticPopUpPiece() override;
749
750
1.93k
  static bool classof(const PathDiagnosticPiece *P) {
751
1.93k
    return P->getKind() == PopUp;
752
1.93k
  }
753
754
  void dump() const override;
755
756
  void Profile(llvm::FoldingSetNodeID &ID) const override;
757
};
758
759
/// File IDs mapped to sets of line numbers.
760
using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
761
762
/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
763
///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
764
///  each which represent the pieces of the path.
765
class PathDiagnostic : public llvm::FoldingSetNode {
766
  std::string CheckerName;
767
  const Decl *DeclWithIssue;
768
  std::string BugType;
769
  std::string VerboseDesc;
770
  std::string ShortDesc;
771
  std::string Category;
772
  std::deque<std::string> OtherDesc;
773
774
  /// Loc The location of the path diagnostic report.
775
  PathDiagnosticLocation Loc;
776
777
  PathPieces pathImpl;
778
  SmallVector<PathPieces *, 3> pathStack;
779
780
  /// Important bug uniqueing location.
781
  /// The location info is useful to differentiate between bugs.
782
  PathDiagnosticLocation UniqueingLoc;
783
  const Decl *UniqueingDecl;
784
785
  /// Lines executed in the path.
786
  std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
787
788
public:
789
  PathDiagnostic() = delete;
790
  PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
791
                 StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
792
                 StringRef category, PathDiagnosticLocation LocationToUnique,
793
                 const Decl *DeclToUnique,
794
                 std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
795
  ~PathDiagnostic();
796
797
  const PathPieces &path;
798
799
  /// Return the path currently used by builders for constructing the
800
  /// PathDiagnostic.
801
303k
  PathPieces &getActivePath() {
802
303k
    if (pathStack.empty())
803
163k
      return pathImpl;
804
140k
    return *pathStack.back();
805
303k
  }
806
807
  /// Return a mutable version of 'path'.
808
33.7k
  PathPieces &getMutablePieces() {
809
33.7k
    return pathImpl;
810
33.7k
  }
811
812
  /// Return the unrolled size of the path.
813
  unsigned full_size();
814
815
6.92k
  void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
816
7.10k
  void popActivePath() { if (!pathStack.empty()) 
pathStack.pop_back()6.92k
; }
817
818
7.10k
  bool isWithinCall() const { return !pathStack.empty(); }
819
820
20.6k
  void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
821
20.6k
    assert(!Loc.isValid() && "End location already set!");
822
0
    Loc = EndPiece->getLocation();
823
20.6k
    assert(Loc.isValid() && "Invalid location for end-of-path piece");
824
0
    getActivePath().push_back(std::move(EndPiece));
825
20.6k
  }
826
827
2
  void appendToDesc(StringRef S) {
828
2
    if (!ShortDesc.empty())
829
2
      ShortDesc += S;
830
2
    VerboseDesc += S;
831
2
  }
832
833
1.95k
  StringRef getVerboseDescription() const { return VerboseDesc; }
834
835
20.5k
  StringRef getShortDescription() const {
836
20.5k
    return ShortDesc.empty() ? 
VerboseDesc1.85k
:
ShortDesc18.6k
;
837
20.5k
  }
838
839
19.1k
  StringRef getCheckerName() const { return CheckerName; }
840
2.47k
  StringRef getBugType() const { return BugType; }
841
1.62k
  StringRef getCategory() const { return Category; }
842
843
  using meta_iterator = std::deque<std::string>::const_iterator;
844
845
132
  meta_iterator meta_begin() const { return OtherDesc.begin(); }
846
132
  meta_iterator meta_end() const { return OtherDesc.end(); }
847
0
  void addMeta(StringRef s) { OtherDesc.push_back(std::string(s)); }
848
849
737
  const FilesToLineNumsMap &getExecutedLines() const {
850
737
    return *ExecutedLines;
851
737
  }
852
853
20.6k
  FilesToLineNumsMap &getExecutedLines() {
854
20.6k
    return *ExecutedLines;
855
20.6k
  }
856
857
  /// Return the semantic context where an issue occurred.  If the
858
  /// issue occurs along a path, this represents the "central" area
859
  /// where the bug manifests.
860
1.60k
  const Decl *getDeclWithIssue() const { return DeclWithIssue; }
861
862
2
  void setDeclWithIssue(const Decl *D) {
863
2
    DeclWithIssue = D;
864
2
  }
865
866
493k
  PathDiagnosticLocation getLocation() const {
867
493k
    return Loc;
868
493k
  }
869
870
2
  void setLocation(PathDiagnosticLocation NewLoc) {
871
2
    Loc = NewLoc;
872
2
  }
873
874
  /// Get the location on which the report should be uniqued.
875
80.8k
  PathDiagnosticLocation getUniqueingLoc() const {
876
80.8k
    return UniqueingLoc;
877
80.8k
  }
878
879
  /// Get the declaration containing the uniqueing location.
880
209
  const Decl *getUniqueingDecl() const {
881
209
    return UniqueingDecl;
882
209
  }
883
884
20.6k
  void flattenLocations() {
885
20.6k
    Loc.flatten();
886
20.6k
    for (const auto &I : pathImpl)
887
27.2k
      I->flattenLocations();
888
20.6k
  }
889
890
  /// Profiles the diagnostic, independent of the path it references.
891
  ///
892
  /// This can be used to merge diagnostics that refer to the same issue
893
  /// along different paths.
894
  void Profile(llvm::FoldingSetNodeID &ID) const;
895
896
  /// Profiles the diagnostic, including its path.
897
  ///
898
  /// Two diagnostics with the same issue along different paths will generate
899
  /// different profiles.
900
  void FullProfile(llvm::FoldingSetNodeID &ID) const;
901
};
902
903
} // namespace ento
904
} // namespace clang
905
906
#endif // LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H