Coverage Report

Created: 2020-10-24 06:27

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