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