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_PATH_DIAGNOSTIC_H
15 #define LLVM_CLANG_PATH_DIAGNOSTIC_H
17 #include "clang/Analysis/ProgramPoint.h"
18 #include "clang/Basic/SourceLocation.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/IntrusiveRefCntPtr.h"
21 #include "llvm/ADT/Optional.h"
22 #include "llvm/ADT/PointerUnion.h"
31 class AnalysisDeclContext;
35 class LocationContext;
46 typedef const SymExpr* SymbolRef;
48 //===----------------------------------------------------------------------===//
49 // High-level interface for handlers of path-sensitive diagnostics.
50 //===----------------------------------------------------------------------===//
54 class PathDiagnosticConsumer {
56 class PDFileEntry : public llvm::FoldingSetNode {
58 PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
60 typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles;
62 /// \brief A vector of <consumer,file> pairs.
65 /// \brief A precomputed hash tag used for uniquing PDFileEntry objects.
66 const llvm::FoldingSetNodeID NodeID;
68 /// \brief Used for profiling in the FoldingSet.
69 void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
72 struct FilesMade : public llvm::FoldingSet<PDFileEntry> {
73 llvm::BumpPtrAllocator Alloc;
75 void addDiagnostic(const PathDiagnostic &PD,
76 StringRef ConsumerName,
79 PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
83 virtual void anchor();
85 PathDiagnosticConsumer() : flushed(false) {}
86 virtual ~PathDiagnosticConsumer();
88 void FlushDiagnostics(FilesMade *FilesMade);
90 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
91 FilesMade *filesMade) = 0;
93 virtual StringRef getName() const = 0;
95 void HandlePathDiagnostic(PathDiagnostic *D);
97 enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive };
98 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
99 virtual bool supportsLogicalOpControlFlow() const { return false; }
100 virtual bool supportsAllBlockEdges() const { return false; }
102 /// Return true if the PathDiagnosticConsumer supports individual
103 /// PathDiagnostics that span multiple files.
104 virtual bool supportsCrossFileDiagnostics() const { return false; }
108 llvm::FoldingSet<PathDiagnostic> Diags;
111 //===----------------------------------------------------------------------===//
112 // Path-sensitive diagnostics.
113 //===----------------------------------------------------------------------===//
115 class PathDiagnosticRange : public SourceRange {
119 PathDiagnosticRange(const SourceRange &R, bool isP = false)
120 : SourceRange(R), isPoint(isP) {}
122 PathDiagnosticRange() : isPoint(false) {}
125 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
126 LocationOrAnalysisDeclContext;
128 class PathDiagnosticLocation {
130 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
133 const SourceManager *SM;
135 PathDiagnosticRange Range;
137 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
139 : K(kind), S(0), D(0), SM(&sm),
140 Loc(genLocation(L)), Range(genRange()) {
144 genLocation(SourceLocation L = SourceLocation(),
145 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
148 genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
151 /// Create an invalid location.
152 PathDiagnosticLocation()
153 : K(SingleLocK), S(0), D(0), SM(0) {}
155 /// Create a location corresponding to the given statement.
156 PathDiagnosticLocation(const Stmt *s,
157 const SourceManager &sm,
158 LocationOrAnalysisDeclContext lac)
159 : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
160 S(K == StmtK ? s : 0),
162 Loc(genLocation(SourceLocation(), lac)),
163 Range(genRange(lac)) {
164 assert(K == SingleLocK || S);
165 assert(K == SingleLocK || Loc.isValid());
166 assert(K == SingleLocK || Range.isValid());
169 /// Create a location corresponding to the given declaration.
170 PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
171 : K(DeclK), S(0), D(d), SM(&sm),
172 Loc(genLocation()), Range(genRange()) {
174 assert(Loc.isValid());
175 assert(Range.isValid());
178 /// Create a location at an explicit offset in the source.
180 /// This should only be used if there are no more appropriate constructors.
181 PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
182 : K(SingleLocK), S(0), D(0), SM(&sm), Loc(loc, sm), Range(genRange()) {
183 assert(Loc.isValid());
184 assert(Range.isValid());
187 /// Create a location corresponding to the given declaration.
188 static PathDiagnosticLocation create(const Decl *D,
189 const SourceManager &SM) {
190 return PathDiagnosticLocation(D, SM);
193 /// Create a location for the beginning of the declaration.
194 static PathDiagnosticLocation createBegin(const Decl *D,
195 const SourceManager &SM);
197 /// Create a location for the beginning of the statement.
198 static PathDiagnosticLocation createBegin(const Stmt *S,
199 const SourceManager &SM,
200 const LocationOrAnalysisDeclContext LAC);
202 /// Create a location for the end of the statement.
204 /// If the statement is a CompoundStatement, the location will point to the
205 /// closing brace instead of following it.
206 static PathDiagnosticLocation createEnd(const Stmt *S,
207 const SourceManager &SM,
208 const LocationOrAnalysisDeclContext LAC);
210 /// Create the location for the operator of the binary expression.
211 /// Assumes the statement has a valid location.
212 static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
213 const SourceManager &SM);
215 /// For member expressions, return the location of the '.' or '->'.
216 /// Assumes the statement has a valid location.
217 static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
218 const SourceManager &SM);
220 /// Create a location for the beginning of the compound statement.
221 /// Assumes the statement has a valid location.
222 static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
223 const SourceManager &SM);
225 /// Create a location for the end of the compound statement.
226 /// Assumes the statement has a valid location.
227 static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
228 const SourceManager &SM);
230 /// Create a location for the beginning of the enclosing declaration body.
231 /// Defaults to the beginning of the first statement in the declaration body.
232 static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
233 const SourceManager &SM);
235 /// Constructs a location for the end of the enclosing declaration body.
236 /// Defaults to the end of brace.
237 static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
238 const SourceManager &SM);
240 /// Create a location corresponding to the given valid ExplodedNode.
241 static PathDiagnosticLocation create(const ProgramPoint& P,
242 const SourceManager &SMng);
244 /// Create a location corresponding to the next valid ExplodedNode as end
245 /// of path location.
246 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
247 const SourceManager &SM);
249 /// Convert the given location into a single kind location.
250 static PathDiagnosticLocation createSingleLocation(
251 const PathDiagnosticLocation &PDL);
253 bool operator==(const PathDiagnosticLocation &X) const {
254 return K == X.K && Loc == X.Loc && Range == X.Range;
257 bool operator!=(const PathDiagnosticLocation &X) const {
258 return !(*this == X);
261 bool isValid() const {
265 FullSourceLoc asLocation() const {
269 PathDiagnosticRange asRange() const {
273 const Stmt *asStmt() const { assert(isValid()); return S; }
274 const Decl *asDecl() const { assert(isValid()); return D; }
276 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
279 *this = PathDiagnosticLocation();
284 const SourceManager& getManager() const { assert(isValid()); return *SM; }
286 void Profile(llvm::FoldingSetNodeID &ID) const;
288 /// \brief Given an exploded node, retrieve the statement that should be used
289 /// for the diagnostic location.
290 static const Stmt *getStmt(const ExplodedNode *N);
292 /// \brief Retrieve the statement corresponding to the sucessor node.
293 static const Stmt *getNextStmt(const ExplodedNode *N);
296 class PathDiagnosticLocationPair {
298 PathDiagnosticLocation Start, End;
300 PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
301 const PathDiagnosticLocation &end)
302 : Start(start), End(end) {}
304 const PathDiagnosticLocation &getStart() const { return Start; }
305 const PathDiagnosticLocation &getEnd() const { return End; }
307 void setStart(const PathDiagnosticLocation &L) { Start = L; }
308 void setEnd(const PathDiagnosticLocation &L) { End = L; }
315 void Profile(llvm::FoldingSetNodeID &ID) const {
321 //===----------------------------------------------------------------------===//
322 // Path "pieces" for path-sensitive diagnostics.
323 //===----------------------------------------------------------------------===//
325 class PathDiagnosticPiece : public RefCountedBaseVPTR {
327 enum Kind { ControlFlow, Event, Macro, Call };
328 enum DisplayHint { Above, Below };
331 const std::string str;
333 const DisplayHint Hint;
335 /// A constant string that can be used to tag the PathDiagnosticPiece,
336 /// typically with the identification of the creator. The actual pointer
337 /// value is meant to be an identifier; the string itself is useful for
341 std::vector<SourceRange> ranges;
343 PathDiagnosticPiece() LLVM_DELETED_FUNCTION;
344 PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
345 void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
348 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
350 PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
353 virtual ~PathDiagnosticPiece();
355 StringRef getString() const { return str; }
357 /// Tag this PathDiagnosticPiece with the given C-string.
358 void setTag(const char *tag) { Tag = tag; }
360 /// Return the opaque tag (if any) on the PathDiagnosticPiece.
361 const void *getTag() const { return Tag.data(); }
363 /// Return the string representation of the tag. This is useful
365 StringRef getTagStr() const { return Tag; }
367 /// getDisplayHint - Return a hint indicating where the diagnostic should
368 /// be displayed by the PathDiagnosticConsumer.
369 DisplayHint getDisplayHint() const { return Hint; }
371 virtual PathDiagnosticLocation getLocation() const = 0;
372 virtual void flattenLocations() = 0;
374 Kind getKind() const { return kind; }
376 void addRange(SourceRange R) {
382 void addRange(SourceLocation B, SourceLocation E) {
383 if (!B.isValid() || !E.isValid())
385 ranges.push_back(SourceRange(B,E));
388 /// Return the SourceRanges associated with this PathDiagnosticPiece.
389 ArrayRef<SourceRange> getRanges() const { return ranges; }
391 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
395 class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
396 void flattenTo(PathPieces &Primary, PathPieces &Current,
397 bool ShouldFlattenMacros) const;
401 PathPieces flatten(bool ShouldFlattenMacros) const {
403 flattenTo(Result, Result, ShouldFlattenMacros);
408 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
410 PathDiagnosticLocation Pos;
412 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
414 PathDiagnosticPiece::Kind k,
415 bool addPosRange = true)
416 : PathDiagnosticPiece(s, k), Pos(pos) {
417 assert(Pos.isValid() && Pos.asLocation().isValid() &&
418 "PathDiagnosticSpotPiece's must have a valid location.");
419 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
422 PathDiagnosticLocation getLocation() const { return Pos; }
423 virtual void flattenLocations() { Pos.flatten(); }
425 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
427 static bool classof(const PathDiagnosticPiece *P) {
428 return P->getKind() == Event || P->getKind() == Macro;
432 /// \brief Interface for classes constructing Stack hints.
434 /// If a PathDiagnosticEvent occurs in a different frame than the final
435 /// diagnostic the hints can be used to summarize the effect of the call.
436 class StackHintGenerator {
438 virtual ~StackHintGenerator() = 0;
440 /// \brief Construct the Diagnostic message for the given ExplodedNode.
441 virtual std::string getMessage(const ExplodedNode *N) = 0;
444 /// \brief Constructs a Stack hint for the given symbol.
446 /// The class knows how to construct the stack hint message based on
447 /// traversing the CallExpr associated with the call and checking if the given
448 /// symbol is returned or is one of the arguments.
449 /// The hint can be customized by redefining 'getMessageForX()' methods.
450 class StackHintGeneratorForSymbol : public StackHintGenerator {
456 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
457 virtual ~StackHintGeneratorForSymbol() {}
459 /// \brief Search the call expression for the symbol Sym and dispatch the
460 /// 'getMessageForX()' methods to construct a specific message.
461 virtual std::string getMessage(const ExplodedNode *N);
463 /// Produces the message of the following form:
464 /// 'Msg via Nth parameter'
465 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
466 virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
469 virtual std::string getMessageForSymbolNotFound() {
474 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
475 Optional<bool> IsPrunable;
477 /// If the event occurs in a different frame than the final diagnostic,
478 /// supply a message that will be used to construct an extra hint on the
479 /// returns from all the calls on the stack from this event to the final
481 OwningPtr<StackHintGenerator> CallStackHint;
484 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
485 StringRef s, bool addPosRange = true,
486 StackHintGenerator *stackHint = 0)
487 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
488 CallStackHint(stackHint) {}
490 ~PathDiagnosticEventPiece();
492 /// Mark the diagnostic piece as being potentially prunable. This
493 /// flag may have been previously set, at which point it will not
494 /// be reset unless one specifies to do so.
495 void setPrunable(bool isPrunable, bool override = false) {
496 if (IsPrunable.hasValue() && !override)
498 IsPrunable = isPrunable;
501 /// Return true if the diagnostic piece is prunable.
502 bool isPrunable() const {
503 return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
506 bool hasCallStackHint() {
507 return (CallStackHint != 0);
510 /// Produce the hint for the given node. The node contains
511 /// information about the call for which the diagnostic can be generated.
512 std::string getCallStackMessage(const ExplodedNode *N) {
514 return CallStackHint->getMessage(N);
518 static inline bool classof(const PathDiagnosticPiece *P) {
519 return P->getKind() == Event;
523 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
524 PathDiagnosticCallPiece(const Decl *callerD,
525 const PathDiagnosticLocation &callReturnPos)
526 : PathDiagnosticPiece(Call), Caller(callerD), Callee(0),
527 NoExit(false), callReturn(callReturnPos) {}
529 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
530 : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
531 NoExit(true), path(oldPath) {}
536 // Flag signifying that this diagnostic has only call enter and no matching
540 // The custom string, which should appear after the call Return Diagnostic.
541 // TODO: Should we allow multiple diagnostics?
542 std::string CallStackMessage;
545 PathDiagnosticLocation callEnter;
546 PathDiagnosticLocation callEnterWithin;
547 PathDiagnosticLocation callReturn;
550 virtual ~PathDiagnosticCallPiece();
552 const Decl *getCaller() const { return Caller; }
554 const Decl *getCallee() const { return Callee; }
555 void setCallee(const CallEnter &CE, const SourceManager &SM);
557 bool hasCallStackMessage() { return !CallStackMessage.empty(); }
558 void setCallStackMessage(StringRef st) {
559 CallStackMessage = st;
562 virtual PathDiagnosticLocation getLocation() const {
566 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
567 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
568 getCallEnterWithinCallerEvent() const;
569 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
571 virtual void flattenLocations() {
573 callReturn.flatten();
574 for (PathPieces::iterator I = path.begin(),
575 E = path.end(); I != E; ++I) (*I)->flattenLocations();
578 static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
579 const CallExitEnd &CE,
580 const SourceManager &SM);
582 static PathDiagnosticCallPiece *construct(PathPieces &pieces,
585 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
587 static inline bool classof(const PathDiagnosticPiece *P) {
588 return P->getKind() == Call;
592 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
593 std::vector<PathDiagnosticLocationPair> LPairs;
595 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
596 const PathDiagnosticLocation &endPos,
598 : PathDiagnosticPiece(s, ControlFlow) {
599 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
602 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
603 const PathDiagnosticLocation &endPos)
604 : PathDiagnosticPiece(ControlFlow) {
605 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
608 ~PathDiagnosticControlFlowPiece();
610 PathDiagnosticLocation getStartLocation() const {
611 assert(!LPairs.empty() &&
612 "PathDiagnosticControlFlowPiece needs at least one location.");
613 return LPairs[0].getStart();
616 PathDiagnosticLocation getEndLocation() const {
617 assert(!LPairs.empty() &&
618 "PathDiagnosticControlFlowPiece needs at least one location.");
619 return LPairs[0].getEnd();
622 void setStartLocation(const PathDiagnosticLocation &L) {
623 LPairs[0].setStart(L);
626 void setEndLocation(const PathDiagnosticLocation &L) {
630 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
632 virtual PathDiagnosticLocation getLocation() const {
633 return getStartLocation();
636 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
637 iterator begin() { return LPairs.begin(); }
638 iterator end() { return LPairs.end(); }
640 virtual void flattenLocations() {
641 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
644 typedef std::vector<PathDiagnosticLocationPair>::const_iterator
646 const_iterator begin() const { return LPairs.begin(); }
647 const_iterator end() const { return LPairs.end(); }
649 static inline bool classof(const PathDiagnosticPiece *P) {
650 return P->getKind() == ControlFlow;
653 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
656 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
658 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
659 : PathDiagnosticSpotPiece(pos, "", Macro) {}
661 ~PathDiagnosticMacroPiece();
663 PathPieces subPieces;
665 bool containsEvent() const;
667 virtual void flattenLocations() {
668 PathDiagnosticSpotPiece::flattenLocations();
669 for (PathPieces::iterator I = subPieces.begin(),
670 E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
673 static inline bool classof(const PathDiagnosticPiece *P) {
674 return P->getKind() == Macro;
677 virtual void Profile(llvm::FoldingSetNodeID &ID) const;
680 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
681 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
682 /// each which represent the pieces of the path.
683 class PathDiagnostic : public llvm::FoldingSetNode {
684 const Decl *DeclWithIssue;
686 std::string VerboseDesc;
687 std::string ShortDesc;
688 std::string Category;
689 std::deque<std::string> OtherDesc;
690 PathDiagnosticLocation Loc;
692 SmallVector<PathPieces *, 3> pathStack;
694 /// \brief Important bug uniqueing location.
695 /// The location info is useful to differentiate between bugs.
696 PathDiagnosticLocation UniqueingLoc;
697 const Decl *UniqueingDecl;
699 PathDiagnostic() LLVM_DELETED_FUNCTION;
701 PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
702 StringRef verboseDesc, StringRef shortDesc,
703 StringRef category, PathDiagnosticLocation LocationToUnique,
704 const Decl *DeclToUnique);
708 const PathPieces &path;
710 /// Return the path currently used by builders for constructing the
712 PathPieces &getActivePath() {
713 if (pathStack.empty())
715 return *pathStack.back();
718 /// Return a mutable version of 'path'.
719 PathPieces &getMutablePieces() {
723 /// Return the unrolled size of the path.
724 unsigned full_size();
726 void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
727 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
729 bool isWithinCall() const { return !pathStack.empty(); }
731 void setEndOfPath(PathDiagnosticPiece *EndPiece) {
732 assert(!Loc.isValid() && "End location already set!");
733 Loc = EndPiece->getLocation();
734 assert(Loc.isValid() && "Invalid location for end-of-path piece");
735 getActivePath().push_back(EndPiece);
741 Loc = PathDiagnosticLocation();
744 StringRef getVerboseDescription() const { return VerboseDesc; }
745 StringRef getShortDescription() const {
746 return ShortDesc.empty() ? VerboseDesc : ShortDesc;
748 StringRef getBugType() const { return BugType; }
749 StringRef getCategory() const { return Category; }
751 /// Return the semantic context where an issue occurred. If the
752 /// issue occurs along a path, this represents the "central" area
753 /// where the bug manifests.
754 const Decl *getDeclWithIssue() const { return DeclWithIssue; }
756 typedef std::deque<std::string>::const_iterator meta_iterator;
757 meta_iterator meta_begin() const { return OtherDesc.begin(); }
758 meta_iterator meta_end() const { return OtherDesc.end(); }
759 void addMeta(StringRef s) { OtherDesc.push_back(s); }
761 PathDiagnosticLocation getLocation() const {
762 assert(Loc.isValid() && "No end-of-path location set yet!");
766 /// \brief Get the location on which the report should be uniqued.
767 PathDiagnosticLocation getUniqueingLoc() const {
771 /// \brief Get the declaration containing the uniqueing location.
772 const Decl *getUniqueingDecl() const {
773 return UniqueingDecl;
776 void flattenLocations() {
778 for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
779 I != E; ++I) (*I)->flattenLocations();
782 /// Profiles the diagnostic, independent of the path it references.
784 /// This can be used to merge diagnostics that refer to the same issue
785 /// along different paths.
786 void Profile(llvm::FoldingSetNodeID &ID) const;
788 /// Profiles the diagnostic, including its path.
790 /// Two diagnostics with the same issue along different paths will generate
791 /// different profiles.
792 void FullProfile(llvm::FoldingSetNodeID &ID) const;
795 } // end GR namespace
797 } //end clang namespace