1 //===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the PathDiagnostic-related interfaces.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
14 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
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"
40 class AnalysisDeclContext;
45 class ConditionalOperator;
48 class LocationContext;
55 //===----------------------------------------------------------------------===//
56 // High-level interface for handlers of path-sensitive diagnostics.
57 //===----------------------------------------------------------------------===//
61 class PathDiagnosticConsumer {
63 class PDFileEntry : public llvm::FoldingSetNode {
65 PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
67 using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
69 /// A vector of <consumer,file> pairs.
72 /// A precomputed hash tag used for uniquing PDFileEntry objects.
73 const llvm::FoldingSetNodeID NodeID;
75 /// Used for profiling in the FoldingSet.
76 void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
80 llvm::BumpPtrAllocator Alloc;
81 llvm::FoldingSet<PDFileEntry> Set;
86 bool empty() const { return Set.empty(); }
88 void addDiagnostic(const PathDiagnostic &PD,
89 StringRef ConsumerName,
92 PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
96 virtual void anchor();
99 PathDiagnosticConsumer() = default;
100 virtual ~PathDiagnosticConsumer();
102 void FlushDiagnostics(FilesMade *FilesMade);
104 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
105 FilesMade *filesMade) = 0;
107 virtual StringRef getName() const = 0;
109 void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
111 enum PathGenerationScheme {
112 /// Only runs visitors, no output generated.
115 /// Used for HTML, SARIF, and text output.
118 /// Used for plist output, used for "arrows" generation.
122 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
124 bool shouldGenerateDiagnostics() const {
125 return getGenerationScheme() != None;
128 bool shouldAddPathEdges() const { return getGenerationScheme() == Extensive; }
130 virtual bool supportsLogicalOpControlFlow() const { return false; }
132 /// Return true if the PathDiagnosticConsumer supports individual
133 /// PathDiagnostics that span multiple files.
134 virtual bool supportsCrossFileDiagnostics() const { return false; }
137 bool flushed = false;
138 llvm::FoldingSet<PathDiagnostic> Diags;
141 //===----------------------------------------------------------------------===//
142 // Path-sensitive diagnostics.
143 //===----------------------------------------------------------------------===//
145 class PathDiagnosticRange : public SourceRange {
147 bool isPoint = false;
149 PathDiagnosticRange(SourceRange R, bool isP = false)
150 : SourceRange(R), isPoint(isP) {}
151 PathDiagnosticRange() = default;
154 using LocationOrAnalysisDeclContext =
155 llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
157 class PathDiagnosticLocation {
159 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
161 const Stmt *S = nullptr;
162 const Decl *D = nullptr;
163 const SourceManager *SM = nullptr;
165 PathDiagnosticRange Range;
167 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
168 : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
170 FullSourceLoc genLocation(
171 SourceLocation L = SourceLocation(),
172 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
174 PathDiagnosticRange genRange(
175 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
178 /// Create an invalid location.
179 PathDiagnosticLocation() = default;
181 /// Create a location corresponding to the given statement.
182 PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
183 LocationOrAnalysisDeclContext lac)
184 : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
185 S(K == StmtK ? s : nullptr), SM(&sm),
186 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 ProgramPoint.
275 static PathDiagnosticLocation create(const ProgramPoint &P,
276 const SourceManager &SMng);
278 /// Convert the given location into a single kind location.
279 static PathDiagnosticLocation createSingleLocation(
280 const PathDiagnosticLocation &PDL);
282 /// Construct a source location that corresponds to either the beginning
283 /// or the end of the given statement, or a nearby valid source location
284 /// if the statement does not have a valid source location of its own.
285 static SourceLocation
286 getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
287 bool UseEndOfStatement = false);
289 bool operator==(const PathDiagnosticLocation &X) const {
290 return K == X.K && Loc == X.Loc && Range == X.Range;
293 bool operator!=(const PathDiagnosticLocation &X) const {
294 return !(*this == X);
297 bool isValid() const {
298 return SM != nullptr;
301 FullSourceLoc asLocation() const {
305 PathDiagnosticRange asRange() const {
309 const Stmt *asStmt() const { assert(isValid()); return S; }
310 const Stmt *getStmtOrNull() const {
316 const Decl *asDecl() const { assert(isValid()); return D; }
318 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
320 bool hasValidLocation() const { return asLocation().isValid(); }
323 *this = PathDiagnosticLocation();
328 const SourceManager& getManager() const { assert(isValid()); return *SM; }
330 void Profile(llvm::FoldingSetNodeID &ID) const;
335 class PathDiagnosticLocationPair {
337 PathDiagnosticLocation Start, End;
340 PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
341 const PathDiagnosticLocation &end)
342 : Start(start), End(end) {}
344 const PathDiagnosticLocation &getStart() const { return Start; }
345 const PathDiagnosticLocation &getEnd() const { return End; }
347 void setStart(const PathDiagnosticLocation &L) { Start = L; }
348 void setEnd(const PathDiagnosticLocation &L) { End = L; }
355 void Profile(llvm::FoldingSetNodeID &ID) const {
361 //===----------------------------------------------------------------------===//
362 // Path "pieces" for path-sensitive diagnostics.
363 //===----------------------------------------------------------------------===//
365 class PathDiagnosticPiece: public llvm::FoldingSetNode {
367 enum Kind { ControlFlow, Event, Macro, Call, Note, PopUp };
368 enum DisplayHint { Above, Below };
371 const std::string str;
373 const DisplayHint Hint;
375 /// In the containing bug report, this piece is the last piece from
376 /// the main source file.
377 bool LastInMainSourceFile = false;
379 /// A constant string that can be used to tag the PathDiagnosticPiece,
380 /// typically with the identification of the creator. The actual pointer
381 /// value is meant to be an identifier; the string itself is useful for
385 std::vector<SourceRange> ranges;
386 std::vector<FixItHint> fixits;
389 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
390 PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
393 PathDiagnosticPiece() = delete;
394 PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
395 PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
396 virtual ~PathDiagnosticPiece();
398 StringRef getString() const { return str; }
400 /// Tag this PathDiagnosticPiece with the given C-string.
401 void setTag(const char *tag) { Tag = tag; }
403 /// Return the opaque tag (if any) on the PathDiagnosticPiece.
404 const void *getTag() const { return Tag.data(); }
406 /// Return the string representation of the tag. This is useful
408 StringRef getTagStr() const { return Tag; }
410 /// getDisplayHint - Return a hint indicating where the diagnostic should
411 /// be displayed by the PathDiagnosticConsumer.
412 DisplayHint getDisplayHint() const { return Hint; }
414 virtual PathDiagnosticLocation getLocation() const = 0;
415 virtual void flattenLocations() = 0;
417 Kind getKind() const { return kind; }
419 void addRange(SourceRange R) {
425 void addRange(SourceLocation B, SourceLocation E) {
426 if (!B.isValid() || !E.isValid())
428 ranges.push_back(SourceRange(B,E));
431 void addFixit(FixItHint F) {
435 /// Return the SourceRanges associated with this PathDiagnosticPiece.
436 ArrayRef<SourceRange> getRanges() const { return ranges; }
438 /// Return the fix-it hints associated with this PathDiagnosticPiece.
439 ArrayRef<FixItHint> getFixits() const { return fixits; }
441 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
443 void setAsLastInMainSourceFile() {
444 LastInMainSourceFile = true;
447 bool isLastInMainSourceFile() const {
448 return LastInMainSourceFile;
451 virtual void dump() const = 0;
454 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
456 class PathPieces : public std::list<PathDiagnosticPieceRef> {
457 void flattenTo(PathPieces &Primary, PathPieces &Current,
458 bool ShouldFlattenMacros) const;
461 PathPieces flatten(bool ShouldFlattenMacros) const {
463 flattenTo(Result, Result, ShouldFlattenMacros);
470 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
472 PathDiagnosticLocation Pos;
475 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
477 PathDiagnosticPiece::Kind k,
478 bool addPosRange = true)
479 : PathDiagnosticPiece(s, k), Pos(pos) {
480 assert(Pos.isValid() && Pos.hasValidLocation() &&
481 "PathDiagnosticSpotPiece's must have a valid location.");
482 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
485 PathDiagnosticLocation getLocation() const override { return Pos; }
486 void flattenLocations() override { Pos.flatten(); }
488 void Profile(llvm::FoldingSetNodeID &ID) const override;
490 static bool classof(const PathDiagnosticPiece *P) {
491 return P->getKind() == Event || P->getKind() == Macro ||
492 P->getKind() == Note || P->getKind() == PopUp;
496 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
497 Optional<bool> IsPrunable;
500 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
501 StringRef s, bool addPosRange = true)
502 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
503 ~PathDiagnosticEventPiece() override;
505 /// Mark the diagnostic piece as being potentially prunable. This
506 /// flag may have been previously set, at which point it will not
507 /// be reset unless one specifies to do so.
508 void setPrunable(bool isPrunable, bool override = false) {
509 if (IsPrunable.hasValue() && !override)
511 IsPrunable = isPrunable;
514 /// Return true if the diagnostic piece is prunable.
515 bool isPrunable() const {
516 return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
519 void dump() const override;
521 static bool classof(const PathDiagnosticPiece *P) {
522 return P->getKind() == Event;
526 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
528 const Decl *Callee = nullptr;
530 // Flag signifying that this diagnostic has only call enter and no matching
534 // Flag signifying that the callee function is an Objective-C autosynthesized
535 // property getter or setter.
536 bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
538 // The custom string, which should appear after the call Return Diagnostic.
539 // TODO: Should we allow multiple diagnostics?
540 std::string CallStackMessage;
542 PathDiagnosticCallPiece(const Decl *callerD,
543 const PathDiagnosticLocation &callReturnPos)
544 : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
545 callReturn(callReturnPos) {}
546 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
547 : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
551 PathDiagnosticLocation callEnter;
552 PathDiagnosticLocation callEnterWithin;
553 PathDiagnosticLocation callReturn;
556 ~PathDiagnosticCallPiece() override;
558 const Decl *getCaller() const { return Caller; }
560 const Decl *getCallee() const { return Callee; }
561 void setCallee(const CallEnter &CE, const SourceManager &SM);
563 bool hasCallStackMessage() { return !CallStackMessage.empty(); }
564 void setCallStackMessage(StringRef st) { CallStackMessage = st; }
566 PathDiagnosticLocation getLocation() const override { return callEnter; }
568 std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
569 std::shared_ptr<PathDiagnosticEventPiece>
570 getCallEnterWithinCallerEvent() const;
571 std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
573 void flattenLocations() override {
575 callReturn.flatten();
576 for (const auto &I : path)
577 I->flattenLocations();
580 static std::shared_ptr<PathDiagnosticCallPiece>
581 construct(const CallExitEnd &CE,
582 const SourceManager &SM);
584 static PathDiagnosticCallPiece *construct(PathPieces &pieces,
587 void dump() const override;
589 void Profile(llvm::FoldingSetNodeID &ID) const override;
591 static bool classof(const PathDiagnosticPiece *P) {
592 return P->getKind() == Call;
596 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
597 std::vector<PathDiagnosticLocationPair> LPairs;
600 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
601 const PathDiagnosticLocation &endPos,
603 : PathDiagnosticPiece(s, ControlFlow) {
604 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
607 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
608 const PathDiagnosticLocation &endPos)
609 : PathDiagnosticPiece(ControlFlow) {
610 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
613 ~PathDiagnosticControlFlowPiece() override;
615 PathDiagnosticLocation getStartLocation() const {
616 assert(!LPairs.empty() &&
617 "PathDiagnosticControlFlowPiece needs at least one location.");
618 return LPairs[0].getStart();
621 PathDiagnosticLocation getEndLocation() const {
622 assert(!LPairs.empty() &&
623 "PathDiagnosticControlFlowPiece needs at least one location.");
624 return LPairs[0].getEnd();
627 void setStartLocation(const PathDiagnosticLocation &L) {
628 LPairs[0].setStart(L);
631 void setEndLocation(const PathDiagnosticLocation &L) {
635 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
637 PathDiagnosticLocation getLocation() const override {
638 return getStartLocation();
641 using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
643 iterator begin() { return LPairs.begin(); }
644 iterator end() { return LPairs.end(); }
646 void flattenLocations() override {
647 for (auto &I : *this)
651 using const_iterator =
652 std::vector<PathDiagnosticLocationPair>::const_iterator;
654 const_iterator begin() const { return LPairs.begin(); }
655 const_iterator end() const { return LPairs.end(); }
657 static bool classof(const PathDiagnosticPiece *P) {
658 return P->getKind() == ControlFlow;
661 void dump() const override;
663 void Profile(llvm::FoldingSetNodeID &ID) const override;
666 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
668 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
669 : PathDiagnosticSpotPiece(pos, "", Macro) {}
670 ~PathDiagnosticMacroPiece() override;
672 PathPieces subPieces;
674 void flattenLocations() override {
675 PathDiagnosticSpotPiece::flattenLocations();
676 for (const auto &I : subPieces)
677 I->flattenLocations();
680 static bool classof(const PathDiagnosticPiece *P) {
681 return P->getKind() == Macro;
684 void dump() const override;
686 void Profile(llvm::FoldingSetNodeID &ID) const override;
689 class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
691 PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
692 bool AddPosRange = true)
693 : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
694 ~PathDiagnosticNotePiece() override;
696 static bool classof(const PathDiagnosticPiece *P) {
697 return P->getKind() == Note;
700 void dump() const override;
702 void Profile(llvm::FoldingSetNodeID &ID) const override;
705 class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
707 PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
708 bool AddPosRange = true)
709 : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
710 ~PathDiagnosticPopUpPiece() override;
712 static bool classof(const PathDiagnosticPiece *P) {
713 return P->getKind() == PopUp;
716 void dump() const override;
718 void Profile(llvm::FoldingSetNodeID &ID) const override;
721 /// File IDs mapped to sets of line numbers.
722 using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
724 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
725 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
726 /// each which represent the pieces of the path.
727 class PathDiagnostic : public llvm::FoldingSetNode {
728 std::string CheckerName;
729 const Decl *DeclWithIssue;
731 std::string VerboseDesc;
732 std::string ShortDesc;
733 std::string Category;
734 std::deque<std::string> OtherDesc;
736 /// Loc The location of the path diagnostic report.
737 PathDiagnosticLocation Loc;
740 SmallVector<PathPieces *, 3> pathStack;
742 /// Important bug uniqueing location.
743 /// The location info is useful to differentiate between bugs.
744 PathDiagnosticLocation UniqueingLoc;
745 const Decl *UniqueingDecl;
747 /// Lines executed in the path.
748 std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
751 PathDiagnostic() = delete;
752 PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
753 StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
754 StringRef category, PathDiagnosticLocation LocationToUnique,
755 const Decl *DeclToUnique,
756 std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
759 const PathPieces &path;
761 /// Return the path currently used by builders for constructing the
763 PathPieces &getActivePath() {
764 if (pathStack.empty())
766 return *pathStack.back();
769 /// Return a mutable version of 'path'.
770 PathPieces &getMutablePieces() {
774 /// Return the unrolled size of the path.
775 unsigned full_size();
777 void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
778 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
780 bool isWithinCall() const { return !pathStack.empty(); }
782 void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
783 assert(!Loc.isValid() && "End location already set!");
784 Loc = EndPiece->getLocation();
785 assert(Loc.isValid() && "Invalid location for end-of-path piece");
786 getActivePath().push_back(std::move(EndPiece));
789 void appendToDesc(StringRef S) {
790 if (!ShortDesc.empty())
795 StringRef getVerboseDescription() const { return VerboseDesc; }
797 StringRef getShortDescription() const {
798 return ShortDesc.empty() ? VerboseDesc : ShortDesc;
801 StringRef getCheckerName() const { return CheckerName; }
802 StringRef getBugType() const { return BugType; }
803 StringRef getCategory() const { return Category; }
805 using meta_iterator = std::deque<std::string>::const_iterator;
807 meta_iterator meta_begin() const { return OtherDesc.begin(); }
808 meta_iterator meta_end() const { return OtherDesc.end(); }
809 void addMeta(StringRef s) { OtherDesc.push_back(s); }
811 const FilesToLineNumsMap &getExecutedLines() const {
812 return *ExecutedLines;
815 FilesToLineNumsMap &getExecutedLines() {
816 return *ExecutedLines;
819 /// Return the semantic context where an issue occurred. If the
820 /// issue occurs along a path, this represents the "central" area
821 /// where the bug manifests.
822 const Decl *getDeclWithIssue() const { return DeclWithIssue; }
824 void setDeclWithIssue(const Decl *D) {
828 PathDiagnosticLocation getLocation() const {
832 void setLocation(PathDiagnosticLocation NewLoc) {
836 /// Get the location on which the report should be uniqued.
837 PathDiagnosticLocation getUniqueingLoc() const {
841 /// Get the declaration containing the uniqueing location.
842 const Decl *getUniqueingDecl() const {
843 return UniqueingDecl;
846 void flattenLocations() {
848 for (const auto &I : pathImpl)
849 I->flattenLocations();
852 /// Profiles the diagnostic, independent of the path it references.
854 /// This can be used to merge diagnostics that refer to the same issue
855 /// along different paths.
856 void Profile(llvm::FoldingSetNodeID &ID) const;
858 /// Profiles the diagnostic, including its path.
860 /// Two diagnostics with the same issue along different paths will generate
861 /// different profiles.
862 void FullProfile(llvm::FoldingSetNodeID &ID) const;
868 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H