Clang Project

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