PathDiagnostic.h revision 2b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3c
1//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines the PathDiagnostic-related interfaces. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H 15#define LLVM_CLANG_PATH_DIAGNOSTIC_H 16 17#include "clang/Basic/SourceLocation.h" 18#include "clang/Analysis/ProgramPoint.h" 19#include "llvm/ADT/FoldingSet.h" 20#include "llvm/ADT/IntrusiveRefCntPtr.h" 21#include "llvm/ADT/PointerUnion.h" 22#include "llvm/ADT/Optional.h" 23#include <deque> 24#include <iterator> 25#include <string> 26#include <vector> 27 28namespace clang { 29 30class AnalysisDeclContext; 31class BinaryOperator; 32class CompoundStmt; 33class Decl; 34class LocationContext; 35class MemberExpr; 36class ParentMap; 37class ProgramPoint; 38class SourceManager; 39class Stmt; 40 41namespace ento { 42 43class ExplodedNode; 44class SymExpr; 45typedef const SymExpr* SymbolRef; 46 47//===----------------------------------------------------------------------===// 48// High-level interface for handlers of path-sensitive diagnostics. 49//===----------------------------------------------------------------------===// 50 51class PathDiagnostic; 52 53class PathDiagnosticConsumer { 54public: 55 typedef std::vector<std::pair<StringRef, std::string> > FilesMade; 56 57private: 58 virtual void anchor(); 59public: 60 PathDiagnosticConsumer() : flushed(false) {} 61 virtual ~PathDiagnosticConsumer(); 62 63 void FlushDiagnostics(FilesMade *FilesMade); 64 65 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 66 FilesMade *filesMade) = 0; 67 68 virtual StringRef getName() const = 0; 69 70 void HandlePathDiagnostic(PathDiagnostic *D); 71 72 enum PathGenerationScheme { None, Minimal, Extensive }; 73 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } 74 virtual bool supportsLogicalOpControlFlow() const { return false; } 75 virtual bool supportsAllBlockEdges() const { return false; } 76 virtual bool useVerboseDescription() const { return true; } 77 78 /// Return true if the PathDiagnosticConsumer supports individual 79 /// PathDiagnostics that span multiple files. 80 virtual bool supportsCrossFileDiagnostics() const { return false; } 81 82protected: 83 bool flushed; 84 llvm::FoldingSet<PathDiagnostic> Diags; 85}; 86 87//===----------------------------------------------------------------------===// 88// Path-sensitive diagnostics. 89//===----------------------------------------------------------------------===// 90 91class PathDiagnosticRange : public SourceRange { 92public: 93 bool isPoint; 94 95 PathDiagnosticRange(const SourceRange &R, bool isP = false) 96 : SourceRange(R), isPoint(isP) {} 97 98 PathDiagnosticRange() : isPoint(false) {} 99}; 100 101typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> 102 LocationOrAnalysisDeclContext; 103 104class PathDiagnosticLocation { 105private: 106 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; 107 const Stmt *S; 108 const Decl *D; 109 const SourceManager *SM; 110 FullSourceLoc Loc; 111 PathDiagnosticRange Range; 112 113 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, 114 Kind kind) 115 : K(kind), S(0), D(0), SM(&sm), 116 Loc(genLocation(L)), Range(genRange()) { 117 assert(Loc.isValid()); 118 assert(Range.isValid()); 119 } 120 121 FullSourceLoc 122 genLocation(SourceLocation L = SourceLocation(), 123 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 124 125 PathDiagnosticRange 126 genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 127 128public: 129 /// Create an invalid location. 130 PathDiagnosticLocation() 131 : K(SingleLocK), S(0), D(0), SM(0) {} 132 133 /// Create a location corresponding to the given statement. 134 PathDiagnosticLocation(const Stmt *s, 135 const SourceManager &sm, 136 LocationOrAnalysisDeclContext lac) 137 : K(StmtK), S(s), D(0), SM(&sm), 138 Loc(genLocation(SourceLocation(), lac)), 139 Range(genRange(lac)) { 140 assert(S); 141 assert(Loc.isValid()); 142 assert(Range.isValid()); 143 } 144 145 /// Create a location corresponding to the given declaration. 146 PathDiagnosticLocation(const Decl *d, const SourceManager &sm) 147 : K(DeclK), S(0), D(d), SM(&sm), 148 Loc(genLocation()), Range(genRange()) { 149 assert(D); 150 assert(Loc.isValid()); 151 assert(Range.isValid()); 152 } 153 154 /// Create a location at an explicit offset in the source. 155 /// 156 /// This should only be used if there are no more appropriate constructors. 157 PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm) 158 : K(SingleLocK), S(0), D(0), SM(&sm), Loc(loc, sm), Range(genRange()) { 159 assert(Loc.isValid()); 160 assert(Range.isValid()); 161 } 162 163 /// Create a location corresponding to the given declaration. 164 static PathDiagnosticLocation create(const Decl *D, 165 const SourceManager &SM) { 166 return PathDiagnosticLocation(D, SM); 167 } 168 169 /// Create a location for the beginning of the declaration. 170 static PathDiagnosticLocation createBegin(const Decl *D, 171 const SourceManager &SM); 172 173 /// Create a location for the beginning of the statement. 174 static PathDiagnosticLocation createBegin(const Stmt *S, 175 const SourceManager &SM, 176 const LocationOrAnalysisDeclContext LAC); 177 178 /// Create a location for the end of the statement. 179 /// 180 /// If the statement is a CompoundStatement, the location will point to the 181 /// closing brace instead of following it. 182 static PathDiagnosticLocation createEnd(const Stmt *S, 183 const SourceManager &SM, 184 const LocationOrAnalysisDeclContext LAC); 185 186 /// Create the location for the operator of the binary expression. 187 /// Assumes the statement has a valid location. 188 static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, 189 const SourceManager &SM); 190 191 /// For member expressions, return the location of the '.' or '->'. 192 /// Assumes the statement has a valid location. 193 static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, 194 const SourceManager &SM); 195 196 /// Create a location for the beginning of the compound statement. 197 /// Assumes the statement has a valid location. 198 static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, 199 const SourceManager &SM); 200 201 /// Create a location for the end of the compound statement. 202 /// Assumes the statement has a valid location. 203 static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, 204 const SourceManager &SM); 205 206 /// Create a location for the beginning of the enclosing declaration body. 207 /// Defaults to the beginning of the first statement in the declaration body. 208 static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, 209 const SourceManager &SM); 210 211 /// Constructs a location for the end of the enclosing declaration body. 212 /// Defaults to the end of brace. 213 static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, 214 const SourceManager &SM); 215 216 /// Create a location corresponding to the given valid ExplodedNode. 217 static PathDiagnosticLocation create(const ProgramPoint& P, 218 const SourceManager &SMng); 219 220 /// Create a location corresponding to the next valid ExplodedNode as end 221 /// of path location. 222 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N, 223 const SourceManager &SM); 224 225 /// Convert the given location into a single kind location. 226 static PathDiagnosticLocation createSingleLocation( 227 const PathDiagnosticLocation &PDL); 228 229 bool operator==(const PathDiagnosticLocation &X) const { 230 return K == X.K && Loc == X.Loc && Range == X.Range; 231 } 232 233 bool operator!=(const PathDiagnosticLocation &X) const { 234 return !(*this == X); 235 } 236 237 bool isValid() const { 238 return SM != 0; 239 } 240 241 FullSourceLoc asLocation() const { 242 return Loc; 243 } 244 245 PathDiagnosticRange asRange() const { 246 return Range; 247 } 248 249 const Stmt *asStmt() const { assert(isValid()); return S; } 250 const Decl *asDecl() const { assert(isValid()); return D; } 251 252 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 253 254 void invalidate() { 255 *this = PathDiagnosticLocation(); 256 } 257 258 void flatten(); 259 260 const SourceManager& getManager() const { assert(isValid()); return *SM; } 261 262 void Profile(llvm::FoldingSetNodeID &ID) const; 263}; 264 265class PathDiagnosticLocationPair { 266private: 267 PathDiagnosticLocation Start, End; 268public: 269 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 270 const PathDiagnosticLocation &end) 271 : Start(start), End(end) {} 272 273 const PathDiagnosticLocation &getStart() const { return Start; } 274 const PathDiagnosticLocation &getEnd() const { return End; } 275 276 void flatten() { 277 Start.flatten(); 278 End.flatten(); 279 } 280 281 void Profile(llvm::FoldingSetNodeID &ID) const { 282 Start.Profile(ID); 283 End.Profile(ID); 284 } 285}; 286 287//===----------------------------------------------------------------------===// 288// Path "pieces" for path-sensitive diagnostics. 289//===----------------------------------------------------------------------===// 290 291class PathDiagnosticPiece : public RefCountedBaseVPTR { 292public: 293 enum Kind { ControlFlow, Event, Macro, Call }; 294 enum DisplayHint { Above, Below }; 295 296private: 297 const std::string str; 298 const Kind kind; 299 const DisplayHint Hint; 300 std::vector<SourceRange> ranges; 301 302 // Do not implement: 303 PathDiagnosticPiece(); 304 PathDiagnosticPiece(const PathDiagnosticPiece &P); 305 PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); 306 307protected: 308 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); 309 310 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 311 312public: 313 virtual ~PathDiagnosticPiece(); 314 315 const std::string& getString() const { return str; } 316 317 /// getDisplayHint - Return a hint indicating where the diagnostic should 318 /// be displayed by the PathDiagnosticConsumer. 319 DisplayHint getDisplayHint() const { return Hint; } 320 321 virtual PathDiagnosticLocation getLocation() const = 0; 322 virtual void flattenLocations() = 0; 323 324 Kind getKind() const { return kind; } 325 326 void addRange(SourceRange R) { 327 if (!R.isValid()) 328 return; 329 ranges.push_back(R); 330 } 331 332 void addRange(SourceLocation B, SourceLocation E) { 333 if (!B.isValid() || !E.isValid()) 334 return; 335 ranges.push_back(SourceRange(B,E)); 336 } 337 338 /// Return the SourceRanges associated with this PathDiagnosticPiece. 339 ArrayRef<SourceRange> getRanges() const { return ranges; } 340 341 static inline bool classof(const PathDiagnosticPiece *P) { 342 return true; 343 } 344 345 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 346}; 347 348 349class PathPieces : public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > { 350 void flattenTo(PathPieces &Primary, PathPieces &Current, 351 bool ShouldFlattenMacros) const; 352public: 353 ~PathPieces(); 354 355 PathPieces flatten(bool ShouldFlattenMacros) const { 356 PathPieces Result; 357 flattenTo(Result, Result, ShouldFlattenMacros); 358 return Result; 359 } 360}; 361 362class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 363private: 364 PathDiagnosticLocation Pos; 365public: 366 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 367 StringRef s, 368 PathDiagnosticPiece::Kind k, 369 bool addPosRange = true) 370 : PathDiagnosticPiece(s, k), Pos(pos) { 371 assert(Pos.isValid() && Pos.asLocation().isValid() && 372 "PathDiagnosticSpotPiece's must have a valid location."); 373 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); 374 } 375 376 PathDiagnosticLocation getLocation() const { return Pos; } 377 virtual void flattenLocations() { Pos.flatten(); } 378 379 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 380}; 381 382/// \brief Interface for classes constructing Stack hints. 383/// 384/// If a PathDiagnosticEvent occurs in a different frame than the final 385/// diagnostic the hints can be used to summarize the effect of the call. 386class StackHintGenerator { 387public: 388 virtual ~StackHintGenerator() = 0; 389 390 /// \brief Construct the Diagnostic message for the given ExplodedNode. 391 virtual std::string getMessage(const ExplodedNode *N) = 0; 392}; 393 394/// \brief Constructs a Stack hint for the given symbol. 395/// 396/// The class knows how to construct the stack hint message based on 397/// traversing the CallExpr associated with the call and checking if the given 398/// symbol is returned or is one of the arguments. 399/// The hint can be customized by redefining 'getMessageForX()' methods. 400class StackHintGeneratorForSymbol : public StackHintGenerator { 401private: 402 SymbolRef Sym; 403 std::string Msg; 404 405public: 406 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} 407 virtual ~StackHintGeneratorForSymbol() {} 408 409 /// \brief Search the call expression for the symbol Sym and dispatch the 410 /// 'getMessageForX()' methods to construct a specific message. 411 virtual std::string getMessage(const ExplodedNode *N); 412 413 /// Prints the ordinal form of the given integer, 414 /// only valid for ValNo : ValNo > 0. 415 void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out); 416 417 /// Produces the message of the following form: 418 /// 'Msg via Nth parameter' 419 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); 420 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 421 return Msg; 422 } 423 virtual std::string getMessageForSymbolNotFound() { 424 return Msg; 425 } 426}; 427 428class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 429 llvm::Optional<bool> IsPrunable; 430 431 /// If the event occurs in a different frame than the final diagnostic, 432 /// supply a message that will be used to construct an extra hint on the 433 /// returns from all the calls on the stack from this event to the final 434 /// diagnostic. 435 llvm::OwningPtr<StackHintGenerator> CallStackHint; 436 437public: 438 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 439 StringRef s, bool addPosRange = true, 440 StackHintGenerator *stackHint = 0) 441 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), 442 CallStackHint(stackHint) {} 443 444 ~PathDiagnosticEventPiece(); 445 446 /// Mark the diagnostic piece as being potentially prunable. This 447 /// flag may have been previously set, at which point it will not 448 /// be reset unless one specifies to do so. 449 void setPrunable(bool isPrunable, bool override = false) { 450 if (IsPrunable.hasValue() && !override) 451 return; 452 IsPrunable = isPrunable; 453 } 454 455 /// Return true if the diagnostic piece is prunable. 456 bool isPrunable() const { 457 return IsPrunable.hasValue() ? IsPrunable.getValue() : false; 458 } 459 460 bool hasCallStackHint() { 461 return (CallStackHint != 0); 462 } 463 464 /// Produce the hint for the given node. The node contains 465 /// information about the call for which the diagnostic can be generated. 466 std::string getCallStackMessage(const ExplodedNode *N) { 467 if (CallStackHint) 468 return CallStackHint->getMessage(N); 469 return ""; 470 } 471 472 static inline bool classof(const PathDiagnosticPiece *P) { 473 return P->getKind() == Event; 474 } 475}; 476 477class PathDiagnosticCallPiece : public PathDiagnosticPiece { 478 PathDiagnosticCallPiece(const Decl *callerD, 479 const PathDiagnosticLocation &callReturnPos) 480 : PathDiagnosticPiece(Call), Caller(callerD), Callee(0), 481 NoExit(false), callReturn(callReturnPos) {} 482 483 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) 484 : PathDiagnosticPiece(Call), Caller(caller), Callee(0), 485 NoExit(true), path(oldPath) {} 486 487 const Decl *Caller; 488 const Decl *Callee; 489 490 // Flag signifying that this diagnostic has only call enter and no matching 491 // call exit. 492 bool NoExit; 493 494 // The custom string, which should appear after the call Return Diagnostic. 495 // TODO: Should we allow multiple diagnostics? 496 std::string CallStackMessage; 497 498public: 499 PathDiagnosticLocation callEnter; 500 PathDiagnosticLocation callEnterWithin; 501 PathDiagnosticLocation callReturn; 502 PathPieces path; 503 504 virtual ~PathDiagnosticCallPiece(); 505 506 const Decl *getCaller() const { return Caller; } 507 508 const Decl *getCallee() const { return Callee; } 509 void setCallee(const CallEnter &CE, const SourceManager &SM); 510 511 bool hasCallStackMessage() { return !CallStackMessage.empty(); } 512 void setCallStackMessage(StringRef st) { 513 CallStackMessage = st; 514 } 515 516 virtual PathDiagnosticLocation getLocation() const { 517 return callEnter; 518 } 519 520 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; 521 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 522 getCallEnterWithinCallerEvent() const; 523 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; 524 525 virtual void flattenLocations() { 526 callEnter.flatten(); 527 callReturn.flatten(); 528 for (PathPieces::iterator I = path.begin(), 529 E = path.end(); I != E; ++I) (*I)->flattenLocations(); 530 } 531 532 static PathDiagnosticCallPiece *construct(const ExplodedNode *N, 533 const CallExitEnd &CE, 534 const SourceManager &SM); 535 536 static PathDiagnosticCallPiece *construct(PathPieces &pieces, 537 const Decl *caller); 538 539 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 540 541 static inline bool classof(const PathDiagnosticPiece *P) { 542 return P->getKind() == Call; 543 } 544}; 545 546class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 547 std::vector<PathDiagnosticLocationPair> LPairs; 548public: 549 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 550 const PathDiagnosticLocation &endPos, 551 StringRef s) 552 : PathDiagnosticPiece(s, ControlFlow) { 553 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 554 } 555 556 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 557 const PathDiagnosticLocation &endPos) 558 : PathDiagnosticPiece(ControlFlow) { 559 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 560 } 561 562 ~PathDiagnosticControlFlowPiece(); 563 564 PathDiagnosticLocation getStartLocation() const { 565 assert(!LPairs.empty() && 566 "PathDiagnosticControlFlowPiece needs at least one location."); 567 return LPairs[0].getStart(); 568 } 569 570 PathDiagnosticLocation getEndLocation() const { 571 assert(!LPairs.empty() && 572 "PathDiagnosticControlFlowPiece needs at least one location."); 573 return LPairs[0].getEnd(); 574 } 575 576 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 577 578 virtual PathDiagnosticLocation getLocation() const { 579 return getStartLocation(); 580 } 581 582 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; 583 iterator begin() { return LPairs.begin(); } 584 iterator end() { return LPairs.end(); } 585 586 virtual void flattenLocations() { 587 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); 588 } 589 590 typedef std::vector<PathDiagnosticLocationPair>::const_iterator 591 const_iterator; 592 const_iterator begin() const { return LPairs.begin(); } 593 const_iterator end() const { return LPairs.end(); } 594 595 static inline bool classof(const PathDiagnosticPiece *P) { 596 return P->getKind() == ControlFlow; 597 } 598 599 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 600}; 601 602class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 603public: 604 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 605 : PathDiagnosticSpotPiece(pos, "", Macro) {} 606 607 ~PathDiagnosticMacroPiece(); 608 609 PathPieces subPieces; 610 611 bool containsEvent() const; 612 613 virtual void flattenLocations() { 614 PathDiagnosticSpotPiece::flattenLocations(); 615 for (PathPieces::iterator I = subPieces.begin(), 616 E = subPieces.end(); I != E; ++I) (*I)->flattenLocations(); 617 } 618 619 static inline bool classof(const PathDiagnosticPiece *P) { 620 return P->getKind() == Macro; 621 } 622 623 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 624}; 625 626/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive 627/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, 628/// each which represent the pieces of the path. 629class PathDiagnostic : public llvm::FoldingSetNode { 630 const Decl *DeclWithIssue; 631 std::string BugType; 632 std::string Desc; 633 std::string Category; 634 std::deque<std::string> OtherDesc; 635 PathPieces pathImpl; 636 llvm::SmallVector<PathPieces *, 3> pathStack; 637 638 PathDiagnostic(); // Do not implement. 639public: 640 const PathPieces &path; 641 642 /// Return the path currently used by builders for constructing the 643 /// PathDiagnostic. 644 PathPieces &getActivePath() { 645 if (pathStack.empty()) 646 return pathImpl; 647 return *pathStack.back(); 648 } 649 650 /// Return a mutable version of 'path'. 651 PathPieces &getMutablePieces() { 652 return pathImpl; 653 } 654 655 /// Return the unrolled size of the path. 656 unsigned full_size(); 657 658 void pushActivePath(PathPieces *p) { pathStack.push_back(p); } 659 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } 660 661 bool isWithinCall() const { return !pathStack.empty(); } 662 663 // PathDiagnostic(); 664 PathDiagnostic(const Decl *DeclWithIssue, 665 StringRef bugtype, 666 StringRef desc, 667 StringRef category); 668 669 ~PathDiagnostic(); 670 671 StringRef getDescription() const { return Desc; } 672 StringRef getBugType() const { return BugType; } 673 StringRef getCategory() const { return Category; } 674 675 /// Return the semantic context where an issue occurred. If the 676 /// issue occurs along a path, this represents the "central" area 677 /// where the bug manifests. 678 const Decl *getDeclWithIssue() const { return DeclWithIssue; } 679 680 typedef std::deque<std::string>::const_iterator meta_iterator; 681 meta_iterator meta_begin() const { return OtherDesc.begin(); } 682 meta_iterator meta_end() const { return OtherDesc.end(); } 683 void addMeta(StringRef s) { OtherDesc.push_back(s); } 684 685 PathDiagnosticLocation getLocation() const; 686 687 void flattenLocations() { 688 for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 689 I != E; ++I) (*I)->flattenLocations(); 690 } 691 692 void Profile(llvm::FoldingSetNodeID &ID) const; 693 694 void FullProfile(llvm::FoldingSetNodeID &ID) const; 695}; 696 697} // end GR namespace 698 699} //end clang namespace 700 701#endif 702