1 //===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the PathDiagnostic-related interfaces.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
15 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
17 #include "clang/AST/Stmt.h"
18 #include "clang/Analysis/AnalysisDeclContext.h"
19 #include "clang/Basic/LLVM.h"
20 #include "clang/Basic/SourceLocation.h"
21 #include "llvm/ADT/ArrayRef.h"
22 #include "llvm/ADT/FoldingSet.h"
23 #include "llvm/ADT/Optional.h"
24 #include "llvm/ADT/PointerUnion.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Support/Allocator.h"
41 class AnalysisDeclContext;
46 class ConditionalOperator;
49 class LocationContext;
59 using SymbolRef = const SymExpr *;
61 //===----------------------------------------------------------------------===//
62 // High-level interface for handlers of path-sensitive diagnostics.
63 //===----------------------------------------------------------------------===//
67 class PathDiagnosticConsumer {
69 class PDFileEntry : public llvm::FoldingSetNode {
71 PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
73 using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
75 /// A vector of <consumer,file> pairs.
78 /// A precomputed hash tag used for uniquing PDFileEntry objects.
79 const llvm::FoldingSetNodeID NodeID;
81 /// Used for profiling in the FoldingSet.
82 void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
86 llvm::BumpPtrAllocator Alloc;
87 llvm::FoldingSet<PDFileEntry> Set;
92 bool empty() const { return Set.empty(); }
94 void addDiagnostic(const PathDiagnostic &PD,
95 StringRef ConsumerName,
98 PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
102 virtual void anchor();
105 PathDiagnosticConsumer() = default;
106 virtual ~PathDiagnosticConsumer();
108 void FlushDiagnostics(FilesMade *FilesMade);
110 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
111 FilesMade *filesMade) = 0;
113 virtual StringRef getName() const = 0;
115 void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
117 enum PathGenerationScheme {
118 /// Only runs visitors, no output generated.
121 /// Used for HTML and text output.
124 /// Used for plist output, used for "arrows" generation.
128 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
129 virtual bool supportsLogicalOpControlFlow() const { return false; }
131 /// Return true if the PathDiagnosticConsumer supports individual
132 /// PathDiagnostics that span multiple files.
133 virtual bool supportsCrossFileDiagnostics() const { return false; }
136 bool flushed = false;
137 llvm::FoldingSet<PathDiagnostic> Diags;
140 //===----------------------------------------------------------------------===//
141 // Path-sensitive diagnostics.
142 //===----------------------------------------------------------------------===//
144 class PathDiagnosticRange : public SourceRange {
146 bool isPoint = false;
148 PathDiagnosticRange(SourceRange R, bool isP = false)
149 : SourceRange(R), isPoint(isP) {}
150 PathDiagnosticRange() = default;
153 using LocationOrAnalysisDeclContext =
154 llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
156 class PathDiagnosticLocation {
158 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
160 const Stmt *S = nullptr;
161 const Decl *D = nullptr;
162 const SourceManager *SM = nullptr;
164 PathDiagnosticRange Range;
166 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
167 : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
169 FullSourceLoc genLocation(
170 SourceLocation L = SourceLocation(),
171 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
173 PathDiagnosticRange genRange(
174 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
177 /// Create an invalid location.
178 PathDiagnosticLocation() = default;
180 /// Create a location corresponding to the given statement.
181 PathDiagnosticLocation(const Stmt *s,
182 const SourceManager &sm,
183 LocationOrAnalysisDeclContext lac)
184 : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
185 S(K == StmtK ? s : nullptr), SM(&sm),
186 Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
187 assert(K == SingleLocK || S);
188 assert(K == SingleLocK || Loc.isValid());
189 assert(K == SingleLocK || Range.isValid());
192 /// Create a location corresponding to the given declaration.
193 PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
194 : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
196 assert(Loc.isValid());
197 assert(Range.isValid());
200 /// Create a location at an explicit offset in the source.
202 /// This should only be used if there are no more appropriate constructors.
203 PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
204 : SM(&sm), Loc(loc, sm), Range(genRange()) {
205 assert(Loc.isValid());
206 assert(Range.isValid());
209 /// Create a location corresponding to the given declaration.
210 static PathDiagnosticLocation create(const Decl *D,
211 const SourceManager &SM) {
212 return PathDiagnosticLocation(D, SM);
215 /// Create a location for the beginning of the declaration.
216 static PathDiagnosticLocation createBegin(const Decl *D,
217 const SourceManager &SM);
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 const LocationOrAnalysisDeclContext LAC) {
225 return createBegin(D, SM);
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);
233 /// Create a location for the end of the statement.
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);
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);
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);
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);
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);
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);
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);
274 /// Create a location corresponding to the given valid ExplodedNode.
275 static PathDiagnosticLocation create(const ProgramPoint &P,
276 const SourceManager &SMng);
278 /// Create a location corresponding to the next valid ExplodedNode as end
279 /// of path location.
280 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
281 const SourceManager &SM);
283 /// Convert the given location into a single kind location.
284 static PathDiagnosticLocation createSingleLocation(
285 const PathDiagnosticLocation &PDL);
287 bool operator==(const PathDiagnosticLocation &X) const {
288 return K == X.K && Loc == X.Loc && Range == X.Range;
291 bool operator!=(const PathDiagnosticLocation &X) const {
292 return !(*this == X);
295 bool isValid() const {
296 return SM != nullptr;
299 FullSourceLoc asLocation() const {
303 PathDiagnosticRange asRange() const {
307 const Stmt *asStmt() const { assert(isValid()); return S; }
308 const Stmt *getStmtOrNull() const {
314 const Decl *asDecl() const { assert(isValid()); return D; }
316 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
319 *this = PathDiagnosticLocation();
324 const SourceManager& getManager() const { assert(isValid()); return *SM; }
326 void Profile(llvm::FoldingSetNodeID &ID) const;
330 /// Given an exploded node, retrieve the statement that should be used
331 /// for the diagnostic location.
332 static const Stmt *getStmt(const ExplodedNode *N);
334 /// Retrieve the statement corresponding to the successor node.
335 static const Stmt *getNextStmt(const ExplodedNode *N);
338 class PathDiagnosticLocationPair {
340 PathDiagnosticLocation Start, End;
343 PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
344 const PathDiagnosticLocation &end)
345 : Start(start), End(end) {}
347 const PathDiagnosticLocation &getStart() const { return Start; }
348 const PathDiagnosticLocation &getEnd() const { return End; }
350 void setStart(const PathDiagnosticLocation &L) { Start = L; }
351 void setEnd(const PathDiagnosticLocation &L) { End = L; }
358 void Profile(llvm::FoldingSetNodeID &ID) const {
364 //===----------------------------------------------------------------------===//
365 // Path "pieces" for path-sensitive diagnostics.
366 //===----------------------------------------------------------------------===//
368 class PathDiagnosticPiece: public llvm::FoldingSetNode {
370 enum Kind { ControlFlow, Event, Macro, Call, Note };
371 enum DisplayHint { Above, Below };
374 const std::string str;
376 const DisplayHint Hint;
378 /// In the containing bug report, this piece is the last piece from
379 /// the main source file.
380 bool LastInMainSourceFile = false;
382 /// A constant string that can be used to tag the PathDiagnosticPiece,
383 /// typically with the identification of the creator. The actual pointer
384 /// value is meant to be an identifier; the string itself is useful for
388 std::vector<SourceRange> ranges;
391 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
392 PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
395 PathDiagnosticPiece() = delete;
396 PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
397 PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
398 virtual ~PathDiagnosticPiece();
400 StringRef getString() const { return str; }
402 /// Tag this PathDiagnosticPiece with the given C-string.
403 void setTag(const char *tag) { Tag = tag; }
405 /// Return the opaque tag (if any) on the PathDiagnosticPiece.
406 const void *getTag() const { return Tag.data(); }
408 /// Return the string representation of the tag. This is useful
410 StringRef getTagStr() const { return Tag; }
412 /// getDisplayHint - Return a hint indicating where the diagnostic should
413 /// be displayed by the PathDiagnosticConsumer.
414 DisplayHint getDisplayHint() const { return Hint; }
416 virtual PathDiagnosticLocation getLocation() const = 0;
417 virtual void flattenLocations() = 0;
419 Kind getKind() const { return kind; }
421 void addRange(SourceRange R) {
427 void addRange(SourceLocation B, SourceLocation E) {
428 if (!B.isValid() || !E.isValid())
430 ranges.push_back(SourceRange(B,E));
433 /// Return the SourceRanges associated with this PathDiagnosticPiece.
434 ArrayRef<SourceRange> getRanges() const { return ranges; }
436 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
438 void setAsLastInMainSourceFile() {
439 LastInMainSourceFile = true;
442 bool isLastInMainSourceFile() const {
443 return LastInMainSourceFile;
446 virtual void dump() const = 0;
449 class PathPieces : public std::list<std::shared_ptr<PathDiagnosticPiece>> {
450 void flattenTo(PathPieces &Primary, PathPieces &Current,
451 bool ShouldFlattenMacros) const;
454 PathPieces flatten(bool ShouldFlattenMacros) const {
456 flattenTo(Result, Result, ShouldFlattenMacros);
463 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
465 PathDiagnosticLocation Pos;
468 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
470 PathDiagnosticPiece::Kind k,
471 bool addPosRange = true)
472 : PathDiagnosticPiece(s, k), Pos(pos) {
473 assert(Pos.isValid() && Pos.asLocation().isValid() &&
474 "PathDiagnosticSpotPiece's must have a valid location.");
475 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
478 PathDiagnosticLocation getLocation() const override { return Pos; }
479 void flattenLocations() override { Pos.flatten(); }
481 void Profile(llvm::FoldingSetNodeID &ID) const override;
483 static bool classof(const PathDiagnosticPiece *P) {
484 return P->getKind() == Event || P->getKind() == Macro ||
485 P->getKind() == Note;
489 /// Interface for classes constructing Stack hints.
491 /// If a PathDiagnosticEvent occurs in a different frame than the final
492 /// diagnostic the hints can be used to summarize the effect of the call.
493 class StackHintGenerator {
495 virtual ~StackHintGenerator() = 0;
497 /// Construct the Diagnostic message for the given ExplodedNode.
498 virtual std::string getMessage(const ExplodedNode *N) = 0;
501 /// Constructs a Stack hint for the given symbol.
503 /// The class knows how to construct the stack hint message based on
504 /// traversing the CallExpr associated with the call and checking if the given
505 /// symbol is returned or is one of the arguments.
506 /// The hint can be customized by redefining 'getMessageForX()' methods.
507 class StackHintGeneratorForSymbol : public StackHintGenerator {
513 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
514 ~StackHintGeneratorForSymbol() override = default;
516 /// Search the call expression for the symbol Sym and dispatch the
517 /// 'getMessageForX()' methods to construct a specific message.
518 std::string getMessage(const ExplodedNode *N) override;
520 /// Produces the message of the following form:
521 /// 'Msg via Nth parameter'
522 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
524 virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
528 virtual std::string getMessageForSymbolNotFound() {
533 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
534 Optional<bool> IsPrunable;
536 /// If the event occurs in a different frame than the final diagnostic,
537 /// supply a message that will be used to construct an extra hint on the
538 /// returns from all the calls on the stack from this event to the final
540 std::unique_ptr<StackHintGenerator> CallStackHint;
543 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
544 StringRef s, bool addPosRange = true,
545 StackHintGenerator *stackHint = nullptr)
546 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
547 CallStackHint(stackHint) {}
548 ~PathDiagnosticEventPiece() override;
550 /// Mark the diagnostic piece as being potentially prunable. This
551 /// flag may have been previously set, at which point it will not
552 /// be reset unless one specifies to do so.
553 void setPrunable(bool isPrunable, bool override = false) {
554 if (IsPrunable.hasValue() && !override)
556 IsPrunable = isPrunable;
559 /// Return true if the diagnostic piece is prunable.
560 bool isPrunable() const {
561 return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
564 bool hasCallStackHint() { return (bool)CallStackHint; }
566 /// Produce the hint for the given node. The node contains
567 /// information about the call for which the diagnostic can be generated.
568 std::string getCallStackMessage(const ExplodedNode *N) {
570 return CallStackHint->getMessage(N);
574 void dump() const override;
576 static bool classof(const PathDiagnosticPiece *P) {
577 return P->getKind() == Event;
581 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
583 const Decl *Callee = nullptr;
585 // Flag signifying that this diagnostic has only call enter and no matching
589 // Flag signifying that the callee function is an Objective-C autosynthesized
590 // property getter or setter.
591 bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
593 // The custom string, which should appear after the call Return Diagnostic.
594 // TODO: Should we allow multiple diagnostics?
595 std::string CallStackMessage;
597 PathDiagnosticCallPiece(const Decl *callerD,
598 const PathDiagnosticLocation &callReturnPos)
599 : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
600 callReturn(callReturnPos) {}
601 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
602 : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
606 PathDiagnosticLocation callEnter;
607 PathDiagnosticLocation callEnterWithin;
608 PathDiagnosticLocation callReturn;
611 ~PathDiagnosticCallPiece() override;
613 const Decl *getCaller() const { return Caller; }
615 const Decl *getCallee() const { return Callee; }
616 void setCallee(const CallEnter &CE, const SourceManager &SM);
618 bool hasCallStackMessage() { return !CallStackMessage.empty(); }
619 void setCallStackMessage(StringRef st) { CallStackMessage = st; }
621 PathDiagnosticLocation getLocation() const override { return callEnter; }
623 std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
624 std::shared_ptr<PathDiagnosticEventPiece>
625 getCallEnterWithinCallerEvent() const;
626 std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
628 void flattenLocations() override {
630 callReturn.flatten();
631 for (const auto &I : path)
632 I->flattenLocations();
635 static std::shared_ptr<PathDiagnosticCallPiece>
636 construct(const ExplodedNode *N, const CallExitEnd &CE,
637 const SourceManager &SM);
639 static PathDiagnosticCallPiece *construct(PathPieces &pieces,
642 void dump() const override;
644 void Profile(llvm::FoldingSetNodeID &ID) const override;
646 static bool classof(const PathDiagnosticPiece *P) {
647 return P->getKind() == Call;
651 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
652 std::vector<PathDiagnosticLocationPair> LPairs;
655 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
656 const PathDiagnosticLocation &endPos,
658 : PathDiagnosticPiece(s, ControlFlow) {
659 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
662 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
663 const PathDiagnosticLocation &endPos)
664 : PathDiagnosticPiece(ControlFlow) {
665 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
668 ~PathDiagnosticControlFlowPiece() override;
670 PathDiagnosticLocation getStartLocation() const {
671 assert(!LPairs.empty() &&
672 "PathDiagnosticControlFlowPiece needs at least one location.");
673 return LPairs[0].getStart();
676 PathDiagnosticLocation getEndLocation() const {
677 assert(!LPairs.empty() &&
678 "PathDiagnosticControlFlowPiece needs at least one location.");
679 return LPairs[0].getEnd();
682 void setStartLocation(const PathDiagnosticLocation &L) {
683 LPairs[0].setStart(L);
686 void setEndLocation(const PathDiagnosticLocation &L) {
690 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
692 PathDiagnosticLocation getLocation() const override {
693 return getStartLocation();
696 using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
698 iterator begin() { return LPairs.begin(); }
699 iterator end() { return LPairs.end(); }
701 void flattenLocations() override {
702 for (auto &I : *this)
706 using const_iterator =
707 std::vector<PathDiagnosticLocationPair>::const_iterator;
709 const_iterator begin() const { return LPairs.begin(); }
710 const_iterator end() const { return LPairs.end(); }
712 static bool classof(const PathDiagnosticPiece *P) {
713 return P->getKind() == ControlFlow;
716 void dump() const override;
718 void Profile(llvm::FoldingSetNodeID &ID) const override;
721 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
723 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
724 : PathDiagnosticSpotPiece(pos, "", Macro) {}
725 ~PathDiagnosticMacroPiece() override;
727 PathPieces subPieces;
729 bool containsEvent() const;
731 void flattenLocations() override {
732 PathDiagnosticSpotPiece::flattenLocations();
733 for (const auto &I : subPieces)
734 I->flattenLocations();
737 static bool classof(const PathDiagnosticPiece *P) {
738 return P->getKind() == Macro;
741 void dump() const override;
743 void Profile(llvm::FoldingSetNodeID &ID) const override;
746 class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
748 PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
749 bool AddPosRange = true)
750 : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
751 ~PathDiagnosticNotePiece() override;
753 static bool classof(const PathDiagnosticPiece *P) {
754 return P->getKind() == Note;
757 void dump() const override;
759 void Profile(llvm::FoldingSetNodeID &ID) const override;
762 /// File IDs mapped to sets of line numbers.
763 using FilesToLineNumsMap = std::map<unsigned, std::set<unsigned>>;
765 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
766 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
767 /// each which represent the pieces of the path.
768 class PathDiagnostic : public llvm::FoldingSetNode {
769 std::string CheckName;
770 const Decl *DeclWithIssue;
772 std::string VerboseDesc;
773 std::string ShortDesc;
774 std::string Category;
775 std::deque<std::string> OtherDesc;
777 /// Loc The location of the path diagnostic report.
778 PathDiagnosticLocation Loc;
781 SmallVector<PathPieces *, 3> pathStack;
783 /// Important bug uniqueing location.
784 /// The location info is useful to differentiate between bugs.
785 PathDiagnosticLocation UniqueingLoc;
786 const Decl *UniqueingDecl;
788 /// Lines executed in the path.
789 std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
792 PathDiagnostic() = delete;
793 PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
794 StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
795 StringRef category, PathDiagnosticLocation LocationToUnique,
796 const Decl *DeclToUnique,
797 std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
800 const PathPieces &path;
802 /// Return the path currently used by builders for constructing the
804 PathPieces &getActivePath() {
805 if (pathStack.empty())
807 return *pathStack.back();
810 /// Return a mutable version of 'path'.
811 PathPieces &getMutablePieces() {
815 /// Return the unrolled size of the path.
816 unsigned full_size();
818 void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
819 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
821 bool isWithinCall() const { return !pathStack.empty(); }
823 void setEndOfPath(std::shared_ptr<PathDiagnosticPiece> EndPiece) {
824 assert(!Loc.isValid() && "End location already set!");
825 Loc = EndPiece->getLocation();
826 assert(Loc.isValid() && "Invalid location for end-of-path piece");
827 getActivePath().push_back(std::move(EndPiece));
830 void appendToDesc(StringRef S) {
831 if (!ShortDesc.empty())
836 /// If the last piece of the report point to the header file, resets
837 /// the location of the report to be the last location in the main source
839 void resetDiagnosticLocationToMainFile();
841 StringRef getVerboseDescription() const { return VerboseDesc; }
843 StringRef getShortDescription() const {
844 return ShortDesc.empty() ? VerboseDesc : ShortDesc;
847 StringRef getCheckName() const { return CheckName; }
848 StringRef getBugType() const { return BugType; }
849 StringRef getCategory() const { return Category; }
851 /// Return the semantic context where an issue occurred. If the
852 /// issue occurs along a path, this represents the "central" area
853 /// where the bug manifests.
854 const Decl *getDeclWithIssue() const { return DeclWithIssue; }
856 using meta_iterator = std::deque<std::string>::const_iterator;
858 meta_iterator meta_begin() const { return OtherDesc.begin(); }
859 meta_iterator meta_end() const { return OtherDesc.end(); }
860 void addMeta(StringRef s) { OtherDesc.push_back(s); }
862 using filesmap_iterator = FilesToLineNumsMap::const_iterator;
864 filesmap_iterator executedLines_begin() const {
865 return ExecutedLines->begin();
868 filesmap_iterator executedLines_end() const { return ExecutedLines->end(); }
870 PathDiagnosticLocation getLocation() const {
874 /// Get the location on which the report should be uniqued.
875 PathDiagnosticLocation getUniqueingLoc() const {
879 /// Get the declaration containing the uniqueing location.
880 const Decl *getUniqueingDecl() const {
881 return UniqueingDecl;
884 void flattenLocations() {
886 for (const auto &I : pathImpl)
887 I->flattenLocations();
890 /// Profiles the diagnostic, independent of the path it references.
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;
896 /// Profiles the diagnostic, including its path.
898 /// Two diagnostics with the same issue along different paths will generate
899 /// different profiles.
900 void FullProfile(llvm::FoldingSetNodeID &ID) const;
907 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H