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, SARIF, 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, const SourceManager &sm,
182 LocationOrAnalysisDeclContext lac)
183 : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
184 S(K == StmtK ? s : nullptr), SM(&sm),
185 Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
186 assert(K == SingleLocK || S);
187 assert(K == SingleLocK || Loc.isValid());
188 assert(K == SingleLocK || Range.isValid());
191 /// Create a location corresponding to the given declaration.
192 PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
193 : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
195 assert(Loc.isValid());
196 assert(Range.isValid());
199 /// Create a location at an explicit offset in the source.
201 /// This should only be used if there are no more appropriate constructors.
202 PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
203 : SM(&sm), Loc(loc, sm), Range(genRange()) {
204 assert(Loc.isValid());
205 assert(Range.isValid());
208 /// Create a location corresponding to the given declaration.
209 static PathDiagnosticLocation create(const Decl *D,
210 const SourceManager &SM) {
211 return PathDiagnosticLocation(D, SM);
214 /// Create a location for the beginning of the declaration.
215 static PathDiagnosticLocation createBegin(const Decl *D,
216 const SourceManager &SM);
218 /// Create a location for the beginning of the declaration.
219 /// The third argument is ignored, useful for generic treatment
220 /// of statements and declarations.
221 static PathDiagnosticLocation
222 createBegin(const Decl *D, const SourceManager &SM,
223 const LocationOrAnalysisDeclContext LAC) {
224 return createBegin(D, SM);
227 /// Create a location for the beginning of the statement.
228 static PathDiagnosticLocation createBegin(const Stmt *S,
229 const SourceManager &SM,
230 const LocationOrAnalysisDeclContext LAC);
232 /// Create a location for the end of the statement.
234 /// If the statement is a CompoundStatement, the location will point to the
235 /// closing brace instead of following it.
236 static PathDiagnosticLocation createEnd(const Stmt *S,
237 const SourceManager &SM,
238 const LocationOrAnalysisDeclContext LAC);
240 /// Create the location for the operator of the binary expression.
241 /// Assumes the statement has a valid location.
242 static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
243 const SourceManager &SM);
244 static PathDiagnosticLocation createConditionalColonLoc(
245 const ConditionalOperator *CO,
246 const SourceManager &SM);
248 /// For member expressions, return the location of the '.' or '->'.
249 /// Assumes the statement has a valid location.
250 static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
251 const SourceManager &SM);
253 /// Create a location for the beginning of the compound statement.
254 /// Assumes the statement has a valid location.
255 static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
256 const SourceManager &SM);
258 /// Create a location for the end of the compound statement.
259 /// Assumes the statement has a valid location.
260 static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
261 const SourceManager &SM);
263 /// Create a location for the beginning of the enclosing declaration body.
264 /// Defaults to the beginning of the first statement in the declaration body.
265 static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
266 const SourceManager &SM);
268 /// Constructs a location for the end of the enclosing declaration body.
269 /// Defaults to the end of brace.
270 static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
271 const SourceManager &SM);
273 /// Create a location corresponding to the given valid ExplodedNode.
274 static PathDiagnosticLocation create(const ProgramPoint &P,
275 const SourceManager &SMng);
277 /// Create a location corresponding to the next valid ExplodedNode as end
278 /// of path location.
279 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
280 const SourceManager &SM);
282 /// Convert the given location into a single kind location.
283 static PathDiagnosticLocation createSingleLocation(
284 const PathDiagnosticLocation &PDL);
286 bool operator==(const PathDiagnosticLocation &X) const {
287 return K == X.K && Loc == X.Loc && Range == X.Range;
290 bool operator!=(const PathDiagnosticLocation &X) const {
291 return !(*this == X);
294 bool isValid() const {
295 return SM != nullptr;
298 FullSourceLoc asLocation() const {
302 PathDiagnosticRange asRange() const {
306 const Stmt *asStmt() const { assert(isValid()); return S; }
307 const Stmt *getStmtOrNull() const {
313 const Decl *asDecl() const { assert(isValid()); return D; }
315 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
318 *this = PathDiagnosticLocation();
323 const SourceManager& getManager() const { assert(isValid()); return *SM; }
325 void Profile(llvm::FoldingSetNodeID &ID) const;
329 /// Given an exploded node, retrieve the statement that should be used
330 /// for the diagnostic location.
331 static const Stmt *getStmt(const ExplodedNode *N);
333 /// Retrieve the statement corresponding to the successor node.
334 static const Stmt *getNextStmt(const ExplodedNode *N);
337 class PathDiagnosticLocationPair {
339 PathDiagnosticLocation Start, End;
342 PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
343 const PathDiagnosticLocation &end)
344 : Start(start), End(end) {}
346 const PathDiagnosticLocation &getStart() const { return Start; }
347 const PathDiagnosticLocation &getEnd() const { return End; }
349 void setStart(const PathDiagnosticLocation &L) { Start = L; }
350 void setEnd(const PathDiagnosticLocation &L) { End = L; }
357 void Profile(llvm::FoldingSetNodeID &ID) const {
363 //===----------------------------------------------------------------------===//
364 // Path "pieces" for path-sensitive diagnostics.
365 //===----------------------------------------------------------------------===//
367 class PathDiagnosticPiece: public llvm::FoldingSetNode {
369 enum Kind { ControlFlow, Event, Macro, Call, Note };
370 enum DisplayHint { Above, Below };
373 const std::string str;
375 const DisplayHint Hint;
377 /// In the containing bug report, this piece is the last piece from
378 /// the main source file.
379 bool LastInMainSourceFile = false;
381 /// A constant string that can be used to tag the PathDiagnosticPiece,
382 /// typically with the identification of the creator. The actual pointer
383 /// value is meant to be an identifier; the string itself is useful for
387 std::vector<SourceRange> ranges;
390 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
391 PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
394 PathDiagnosticPiece() = delete;
395 PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
396 PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
397 virtual ~PathDiagnosticPiece();
399 StringRef getString() const { return str; }
401 /// Tag this PathDiagnosticPiece with the given C-string.
402 void setTag(const char *tag) { Tag = tag; }
404 /// Return the opaque tag (if any) on the PathDiagnosticPiece.
405 const void *getTag() const { return Tag.data(); }
407 /// Return the string representation of the tag. This is useful
409 StringRef getTagStr() const { return Tag; }
411 /// getDisplayHint - Return a hint indicating where the diagnostic should
412 /// be displayed by the PathDiagnosticConsumer.
413 DisplayHint getDisplayHint() const { return Hint; }
415 virtual PathDiagnosticLocation getLocation() const = 0;
416 virtual void flattenLocations() = 0;
418 Kind getKind() const { return kind; }
420 void addRange(SourceRange R) {
426 void addRange(SourceLocation B, SourceLocation E) {
427 if (!B.isValid() || !E.isValid())
429 ranges.push_back(SourceRange(B,E));
432 /// Return the SourceRanges associated with this PathDiagnosticPiece.
433 ArrayRef<SourceRange> getRanges() const { return ranges; }
435 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
437 void setAsLastInMainSourceFile() {
438 LastInMainSourceFile = true;
441 bool isLastInMainSourceFile() const {
442 return LastInMainSourceFile;
445 virtual void dump() const = 0;
448 class PathPieces : public std::list<std::shared_ptr<PathDiagnosticPiece>> {
449 void flattenTo(PathPieces &Primary, PathPieces &Current,
450 bool ShouldFlattenMacros) const;
453 PathPieces flatten(bool ShouldFlattenMacros) const {
455 flattenTo(Result, Result, ShouldFlattenMacros);
462 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
464 PathDiagnosticLocation Pos;
467 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
469 PathDiagnosticPiece::Kind k,
470 bool addPosRange = true)
471 : PathDiagnosticPiece(s, k), Pos(pos) {
472 assert(Pos.isValid() && Pos.asLocation().isValid() &&
473 "PathDiagnosticSpotPiece's must have a valid location.");
474 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
477 PathDiagnosticLocation getLocation() const override { return Pos; }
478 void flattenLocations() override { Pos.flatten(); }
480 void Profile(llvm::FoldingSetNodeID &ID) const override;
482 static bool classof(const PathDiagnosticPiece *P) {
483 return P->getKind() == Event || P->getKind() == Macro ||
484 P->getKind() == Note;
488 /// Interface for classes constructing Stack hints.
490 /// If a PathDiagnosticEvent occurs in a different frame than the final
491 /// diagnostic the hints can be used to summarize the effect of the call.
492 class StackHintGenerator {
494 virtual ~StackHintGenerator() = 0;
496 /// Construct the Diagnostic message for the given ExplodedNode.
497 virtual std::string getMessage(const ExplodedNode *N) = 0;
500 /// Constructs a Stack hint for the given symbol.
502 /// The class knows how to construct the stack hint message based on
503 /// traversing the CallExpr associated with the call and checking if the given
504 /// symbol is returned or is one of the arguments.
505 /// The hint can be customized by redefining 'getMessageForX()' methods.
506 class StackHintGeneratorForSymbol : public StackHintGenerator {
512 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
513 ~StackHintGeneratorForSymbol() override = default;
515 /// Search the call expression for the symbol Sym and dispatch the
516 /// 'getMessageForX()' methods to construct a specific message.
517 std::string getMessage(const ExplodedNode *N) override;
519 /// Produces the message of the following form:
520 /// 'Msg via Nth parameter'
521 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
523 virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
527 virtual std::string getMessageForSymbolNotFound() {
532 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
533 Optional<bool> IsPrunable;
535 /// If the event occurs in a different frame than the final diagnostic,
536 /// supply a message that will be used to construct an extra hint on the
537 /// returns from all the calls on the stack from this event to the final
539 std::unique_ptr<StackHintGenerator> CallStackHint;
542 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
543 StringRef s, bool addPosRange = true,
544 StackHintGenerator *stackHint = nullptr)
545 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
546 CallStackHint(stackHint) {}
547 ~PathDiagnosticEventPiece() override;
549 /// Mark the diagnostic piece as being potentially prunable. This
550 /// flag may have been previously set, at which point it will not
551 /// be reset unless one specifies to do so.
552 void setPrunable(bool isPrunable, bool override = false) {
553 if (IsPrunable.hasValue() && !override)
555 IsPrunable = isPrunable;
558 /// Return true if the diagnostic piece is prunable.
559 bool isPrunable() const {
560 return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
563 bool hasCallStackHint() { return (bool)CallStackHint; }
565 /// Produce the hint for the given node. The node contains
566 /// information about the call for which the diagnostic can be generated.
567 std::string getCallStackMessage(const ExplodedNode *N) {
569 return CallStackHint->getMessage(N);
573 void dump() const override;
575 static bool classof(const PathDiagnosticPiece *P) {
576 return P->getKind() == Event;
580 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
582 const Decl *Callee = nullptr;
584 // Flag signifying that this diagnostic has only call enter and no matching
588 // Flag signifying that the callee function is an Objective-C autosynthesized
589 // property getter or setter.
590 bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
592 // The custom string, which should appear after the call Return Diagnostic.
593 // TODO: Should we allow multiple diagnostics?
594 std::string CallStackMessage;
596 PathDiagnosticCallPiece(const Decl *callerD,
597 const PathDiagnosticLocation &callReturnPos)
598 : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
599 callReturn(callReturnPos) {}
600 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
601 : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
605 PathDiagnosticLocation callEnter;
606 PathDiagnosticLocation callEnterWithin;
607 PathDiagnosticLocation callReturn;
610 ~PathDiagnosticCallPiece() override;
612 const Decl *getCaller() const { return Caller; }
614 const Decl *getCallee() const { return Callee; }
615 void setCallee(const CallEnter &CE, const SourceManager &SM);
617 bool hasCallStackMessage() { return !CallStackMessage.empty(); }
618 void setCallStackMessage(StringRef st) { CallStackMessage = st; }
620 PathDiagnosticLocation getLocation() const override { return callEnter; }
622 std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
623 std::shared_ptr<PathDiagnosticEventPiece>
624 getCallEnterWithinCallerEvent() const;
625 std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
627 void flattenLocations() override {
629 callReturn.flatten();
630 for (const auto &I : path)
631 I->flattenLocations();
634 static std::shared_ptr<PathDiagnosticCallPiece>
635 construct(const CallExitEnd &CE,
636 const SourceManager &SM);
638 static PathDiagnosticCallPiece *construct(PathPieces &pieces,
641 void dump() const override;
643 void Profile(llvm::FoldingSetNodeID &ID) const override;
645 static bool classof(const PathDiagnosticPiece *P) {
646 return P->getKind() == Call;
650 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
651 std::vector<PathDiagnosticLocationPair> LPairs;
654 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
655 const PathDiagnosticLocation &endPos,
657 : PathDiagnosticPiece(s, ControlFlow) {
658 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
661 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
662 const PathDiagnosticLocation &endPos)
663 : PathDiagnosticPiece(ControlFlow) {
664 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
667 ~PathDiagnosticControlFlowPiece() override;
669 PathDiagnosticLocation getStartLocation() const {
670 assert(!LPairs.empty() &&
671 "PathDiagnosticControlFlowPiece needs at least one location.");
672 return LPairs[0].getStart();
675 PathDiagnosticLocation getEndLocation() const {
676 assert(!LPairs.empty() &&
677 "PathDiagnosticControlFlowPiece needs at least one location.");
678 return LPairs[0].getEnd();
681 void setStartLocation(const PathDiagnosticLocation &L) {
682 LPairs[0].setStart(L);
685 void setEndLocation(const PathDiagnosticLocation &L) {
689 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
691 PathDiagnosticLocation getLocation() const override {
692 return getStartLocation();
695 using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
697 iterator begin() { return LPairs.begin(); }
698 iterator end() { return LPairs.end(); }
700 void flattenLocations() override {
701 for (auto &I : *this)
705 using const_iterator =
706 std::vector<PathDiagnosticLocationPair>::const_iterator;
708 const_iterator begin() const { return LPairs.begin(); }
709 const_iterator end() const { return LPairs.end(); }
711 static bool classof(const PathDiagnosticPiece *P) {
712 return P->getKind() == ControlFlow;
715 void dump() const override;
717 void Profile(llvm::FoldingSetNodeID &ID) const override;
720 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
722 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
723 : PathDiagnosticSpotPiece(pos, "", Macro) {}
724 ~PathDiagnosticMacroPiece() override;
726 PathPieces subPieces;
728 bool containsEvent() const;
730 void flattenLocations() override {
731 PathDiagnosticSpotPiece::flattenLocations();
732 for (const auto &I : subPieces)
733 I->flattenLocations();
736 static bool classof(const PathDiagnosticPiece *P) {
737 return P->getKind() == Macro;
740 void dump() const override;
742 void Profile(llvm::FoldingSetNodeID &ID) const override;
745 class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
747 PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
748 bool AddPosRange = true)
749 : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
750 ~PathDiagnosticNotePiece() override;
752 static bool classof(const PathDiagnosticPiece *P) {
753 return P->getKind() == Note;
756 void dump() const override;
758 void Profile(llvm::FoldingSetNodeID &ID) const override;
761 /// File IDs mapped to sets of line numbers.
762 using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
764 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
765 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
766 /// each which represent the pieces of the path.
767 class PathDiagnostic : public llvm::FoldingSetNode {
768 std::string CheckName;
769 const Decl *DeclWithIssue;
771 std::string VerboseDesc;
772 std::string ShortDesc;
773 std::string Category;
774 std::deque<std::string> OtherDesc;
776 /// Loc The location of the path diagnostic report.
777 PathDiagnosticLocation Loc;
780 SmallVector<PathPieces *, 3> pathStack;
782 /// Important bug uniqueing location.
783 /// The location info is useful to differentiate between bugs.
784 PathDiagnosticLocation UniqueingLoc;
785 const Decl *UniqueingDecl;
787 /// Lines executed in the path.
788 std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
791 PathDiagnostic() = delete;
792 PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
793 StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
794 StringRef category, PathDiagnosticLocation LocationToUnique,
795 const Decl *DeclToUnique,
796 std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
799 const PathPieces &path;
801 /// Return the path currently used by builders for constructing the
803 PathPieces &getActivePath() {
804 if (pathStack.empty())
806 return *pathStack.back();
809 /// Return a mutable version of 'path'.
810 PathPieces &getMutablePieces() {
814 /// Return the unrolled size of the path.
815 unsigned full_size();
817 void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
818 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
820 bool isWithinCall() const { return !pathStack.empty(); }
822 void setEndOfPath(std::shared_ptr<PathDiagnosticPiece> EndPiece) {
823 assert(!Loc.isValid() && "End location already set!");
824 Loc = EndPiece->getLocation();
825 assert(Loc.isValid() && "Invalid location for end-of-path piece");
826 getActivePath().push_back(std::move(EndPiece));
829 void appendToDesc(StringRef S) {
830 if (!ShortDesc.empty())
835 /// If the last piece of the report point to the header file, resets
836 /// the location of the report to be the last location in the main source
838 void resetDiagnosticLocationToMainFile();
840 StringRef getVerboseDescription() const { return VerboseDesc; }
842 StringRef getShortDescription() const {
843 return ShortDesc.empty() ? VerboseDesc : ShortDesc;
846 StringRef getCheckName() const { return CheckName; }
847 StringRef getBugType() const { return BugType; }
848 StringRef getCategory() const { return Category; }
850 /// Return the semantic context where an issue occurred. If the
851 /// issue occurs along a path, this represents the "central" area
852 /// where the bug manifests.
853 const Decl *getDeclWithIssue() const { return DeclWithIssue; }
855 using meta_iterator = std::deque<std::string>::const_iterator;
857 meta_iterator meta_begin() const { return OtherDesc.begin(); }
858 meta_iterator meta_end() const { return OtherDesc.end(); }
859 void addMeta(StringRef s) { OtherDesc.push_back(s); }
861 const FilesToLineNumsMap &getExecutedLines() const {
862 return *ExecutedLines;
865 FilesToLineNumsMap &getExecutedLines() {
866 return *ExecutedLines;
869 PathDiagnosticLocation getLocation() const {
873 /// Get the location on which the report should be uniqued.
874 PathDiagnosticLocation getUniqueingLoc() const {
878 /// Get the declaration containing the uniqueing location.
879 const Decl *getUniqueingDecl() const {
880 return UniqueingDecl;
883 void flattenLocations() {
885 for (const auto &I : pathImpl)
886 I->flattenLocations();
889 /// Profiles the diagnostic, independent of the path it references.
891 /// This can be used to merge diagnostics that refer to the same issue
892 /// along different paths.
893 void Profile(llvm::FoldingSetNodeID &ID) const;
895 /// Profiles the diagnostic, including its path.
897 /// Two diagnostics with the same issue along different paths will generate
898 /// different profiles.
899 void FullProfile(llvm::FoldingSetNodeID &ID) const;
906 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H