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/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" 23 #include <deque> 24 #include <list> 25 #include <iterator> 26 #include <string> 27 #include <vector> 28 29 namespace clang { 30 31 class AnalysisDeclContext; 32 class BinaryOperator; 33 class CompoundStmt; 34 class Decl; 35 class LocationContext; 36 class MemberExpr; 37 class ParentMap; 38 class ProgramPoint; 39 class SourceManager; 40 class Stmt; 41 42 namespace ento { 43 44 class ExplodedNode; 45 class SymExpr; 46 typedef const SymExpr* SymbolRef; 47 48 //===----------------------------------------------------------------------===// 49 // High-level interface for handlers of path-sensitive diagnostics. 50 //===----------------------------------------------------------------------===// 51 52 class PathDiagnostic; 53 54 class PathDiagnosticConsumer { 55 public: 56 class PDFileEntry : public llvm::FoldingSetNode { 57 public: 58 PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {} 59 60 typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles; 61 62 /// \brief A vector of <consumer,file> pairs. 63 ConsumerFiles files; 64 65 /// \brief A precomputed hash tag used for uniquing PDFileEntry objects. 66 const llvm::FoldingSetNodeID NodeID; 67 68 /// \brief Used for profiling in the FoldingSet. 69 void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; } 70 }; 71 72 struct FilesMade : public llvm::FoldingSet<PDFileEntry> { 73 llvm::BumpPtrAllocator Alloc; 74 75 void addDiagnostic(const PathDiagnostic &PD, 76 StringRef ConsumerName, 77 StringRef fileName); 78 79 PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD); 80 }; 81 82 private: 83 virtual void anchor(); 84 public: 85 PathDiagnosticConsumer() : flushed(false) {} 86 virtual ~PathDiagnosticConsumer(); 87 88 void FlushDiagnostics(FilesMade *FilesMade); 89 90 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 91 FilesMade *filesMade) = 0; 92 93 virtual StringRef getName() const = 0; 94 95 void HandlePathDiagnostic(PathDiagnostic *D); 96 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; } 101 102 /// Return true if the PathDiagnosticConsumer supports individual 103 /// PathDiagnostics that span multiple files. 104 virtual bool supportsCrossFileDiagnostics() const { return false; } 105 106 protected: 107 bool flushed; 108 llvm::FoldingSet<PathDiagnostic> Diags; 109 }; 110 111 //===----------------------------------------------------------------------===// 112 // Path-sensitive diagnostics. 113 //===----------------------------------------------------------------------===// 114 115 class PathDiagnosticRange : public SourceRange { 116 public: 117 bool isPoint; 118 119 PathDiagnosticRange(const SourceRange &R, bool isP = false) 120 : SourceRange(R), isPoint(isP) {} 121 122 PathDiagnosticRange() : isPoint(false) {} 123 }; 124 125 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> 126 LocationOrAnalysisDeclContext; 127 128 class PathDiagnosticLocation { 129 private: 130 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; 131 const Stmt *S; 132 const Decl *D; 133 const SourceManager *SM; 134 FullSourceLoc Loc; 135 PathDiagnosticRange Range; 136 137 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, 138 Kind kind) 139 : K(kind), S(0), D(0), SM(&sm), 140 Loc(genLocation(L)), Range(genRange()) { 141 } 142 143 FullSourceLoc 144 genLocation(SourceLocation L = SourceLocation(), 145 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 146 147 PathDiagnosticRange 148 genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 149 150 public: 151 /// Create an invalid location. 152 PathDiagnosticLocation() 153 : K(SingleLocK), S(0), D(0), SM(0) {} 154 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), 161 D(0), SM(&sm), 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()); 167 } 168 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()) { 173 assert(D); 174 assert(Loc.isValid()); 175 assert(Range.isValid()); 176 } 177 178 /// Create a location at an explicit offset in the source. 179 /// 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()); 185 } 186 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); 191 } 192 193 /// Create a location for the beginning of the declaration. 194 static PathDiagnosticLocation createBegin(const Decl *D, 195 const SourceManager &SM); 196 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); 201 202 /// Create a location for the end of the statement. 203 /// 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); 209 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); 214 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); 219 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); 224 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); 229 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); 234 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); 239 240 /// Create a location corresponding to the given valid ExplodedNode. 241 static PathDiagnosticLocation create(const ProgramPoint& P, 242 const SourceManager &SMng); 243 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); 248 249 /// Convert the given location into a single kind location. 250 static PathDiagnosticLocation createSingleLocation( 251 const PathDiagnosticLocation &PDL); 252 253 bool operator==(const PathDiagnosticLocation &X) const { 254 return K == X.K && Loc == X.Loc && Range == X.Range; 255 } 256 257 bool operator!=(const PathDiagnosticLocation &X) const { 258 return !(*this == X); 259 } 260 261 bool isValid() const { 262 return SM != 0; 263 } 264 265 FullSourceLoc asLocation() const { 266 return Loc; 267 } 268 269 PathDiagnosticRange asRange() const { 270 return Range; 271 } 272 273 const Stmt *asStmt() const { assert(isValid()); return S; } 274 const Decl *asDecl() const { assert(isValid()); return D; } 275 276 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 277 278 void invalidate() { 279 *this = PathDiagnosticLocation(); 280 } 281 282 void flatten(); 283 284 const SourceManager& getManager() const { assert(isValid()); return *SM; } 285 286 void Profile(llvm::FoldingSetNodeID &ID) const; 287 288 void dump() const; 289 290 /// \brief Given an exploded node, retrieve the statement that should be used 291 /// for the diagnostic location. 292 static const Stmt *getStmt(const ExplodedNode *N); 293 294 /// \brief Retrieve the statement corresponding to the sucessor node. 295 static const Stmt *getNextStmt(const ExplodedNode *N); 296 }; 297 298 class PathDiagnosticLocationPair { 299 private: 300 PathDiagnosticLocation Start, End; 301 public: 302 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 303 const PathDiagnosticLocation &end) 304 : Start(start), End(end) {} 305 306 const PathDiagnosticLocation &getStart() const { return Start; } 307 const PathDiagnosticLocation &getEnd() const { return End; } 308 309 void setStart(const PathDiagnosticLocation &L) { Start = L; } 310 void setEnd(const PathDiagnosticLocation &L) { End = L; } 311 312 void flatten() { 313 Start.flatten(); 314 End.flatten(); 315 } 316 317 void Profile(llvm::FoldingSetNodeID &ID) const { 318 Start.Profile(ID); 319 End.Profile(ID); 320 } 321 }; 322 323 //===----------------------------------------------------------------------===// 324 // Path "pieces" for path-sensitive diagnostics. 325 //===----------------------------------------------------------------------===// 326 327 class PathDiagnosticPiece : public RefCountedBaseVPTR { 328 public: 329 enum Kind { ControlFlow, Event, Macro, Call }; 330 enum DisplayHint { Above, Below }; 331 332 private: 333 const std::string str; 334 const Kind kind; 335 const DisplayHint Hint; 336 337 /// \brief In the containing bug report, this piece is the last piece from 338 /// the main source file. 339 bool LastInMainSourceFile; 340 341 /// A constant string that can be used to tag the PathDiagnosticPiece, 342 /// typically with the identification of the creator. The actual pointer 343 /// value is meant to be an identifier; the string itself is useful for 344 /// debugging. 345 StringRef Tag; 346 347 std::vector<SourceRange> ranges; 348 349 PathDiagnosticPiece() LLVM_DELETED_FUNCTION; 350 PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION; 351 void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION; 352 353 protected: 354 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); 355 356 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 357 358 public: 359 virtual ~PathDiagnosticPiece(); 360 361 StringRef getString() const { return str; } 362 363 /// Tag this PathDiagnosticPiece with the given C-string. 364 void setTag(const char *tag) { Tag = tag; } 365 366 /// Return the opaque tag (if any) on the PathDiagnosticPiece. 367 const void *getTag() const { return Tag.data(); } 368 369 /// Return the string representation of the tag. This is useful 370 /// for debugging. 371 StringRef getTagStr() const { return Tag; } 372 373 /// getDisplayHint - Return a hint indicating where the diagnostic should 374 /// be displayed by the PathDiagnosticConsumer. 375 DisplayHint getDisplayHint() const { return Hint; } 376 377 virtual PathDiagnosticLocation getLocation() const = 0; 378 virtual void flattenLocations() = 0; 379 380 Kind getKind() const { return kind; } 381 382 void addRange(SourceRange R) { 383 if (!R.isValid()) 384 return; 385 ranges.push_back(R); 386 } 387 388 void addRange(SourceLocation B, SourceLocation E) { 389 if (!B.isValid() || !E.isValid()) 390 return; 391 ranges.push_back(SourceRange(B,E)); 392 } 393 394 /// Return the SourceRanges associated with this PathDiagnosticPiece. 395 ArrayRef<SourceRange> getRanges() const { return ranges; } 396 397 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 398 399 void setAsLastInMainSourceFile() { 400 LastInMainSourceFile = true; 401 } 402 403 bool isLastInMainSourceFile() const { 404 return LastInMainSourceFile; 405 } 406 407 virtual void dump() const = 0; 408 }; 409 410 411 class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > { 412 void flattenTo(PathPieces &Primary, PathPieces &Current, 413 bool ShouldFlattenMacros) const; 414 public: 415 ~PathPieces(); 416 417 PathPieces flatten(bool ShouldFlattenMacros) const { 418 PathPieces Result; 419 flattenTo(Result, Result, ShouldFlattenMacros); 420 return Result; 421 } 422 423 LLVM_ATTRIBUTE_USED void dump() const; 424 }; 425 426 class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 427 private: 428 PathDiagnosticLocation Pos; 429 public: 430 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 431 StringRef s, 432 PathDiagnosticPiece::Kind k, 433 bool addPosRange = true) 434 : PathDiagnosticPiece(s, k), Pos(pos) { 435 assert(Pos.isValid() && Pos.asLocation().isValid() && 436 "PathDiagnosticSpotPiece's must have a valid location."); 437 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); 438 } 439 440 PathDiagnosticLocation getLocation() const { return Pos; } 441 virtual void flattenLocations() { Pos.flatten(); } 442 443 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 444 445 static bool classof(const PathDiagnosticPiece *P) { 446 return P->getKind() == Event || P->getKind() == Macro; 447 } 448 }; 449 450 /// \brief Interface for classes constructing Stack hints. 451 /// 452 /// If a PathDiagnosticEvent occurs in a different frame than the final 453 /// diagnostic the hints can be used to summarize the effect of the call. 454 class StackHintGenerator { 455 public: 456 virtual ~StackHintGenerator() = 0; 457 458 /// \brief Construct the Diagnostic message for the given ExplodedNode. 459 virtual std::string getMessage(const ExplodedNode *N) = 0; 460 }; 461 462 /// \brief Constructs a Stack hint for the given symbol. 463 /// 464 /// The class knows how to construct the stack hint message based on 465 /// traversing the CallExpr associated with the call and checking if the given 466 /// symbol is returned or is one of the arguments. 467 /// The hint can be customized by redefining 'getMessageForX()' methods. 468 class StackHintGeneratorForSymbol : public StackHintGenerator { 469 private: 470 SymbolRef Sym; 471 std::string Msg; 472 473 public: 474 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} 475 virtual ~StackHintGeneratorForSymbol() {} 476 477 /// \brief Search the call expression for the symbol Sym and dispatch the 478 /// 'getMessageForX()' methods to construct a specific message. 479 virtual std::string getMessage(const ExplodedNode *N); 480 481 /// Produces the message of the following form: 482 /// 'Msg via Nth parameter' 483 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); 484 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 485 return Msg; 486 } 487 virtual std::string getMessageForSymbolNotFound() { 488 return Msg; 489 } 490 }; 491 492 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 493 Optional<bool> IsPrunable; 494 495 /// If the event occurs in a different frame than the final diagnostic, 496 /// supply a message that will be used to construct an extra hint on the 497 /// returns from all the calls on the stack from this event to the final 498 /// diagnostic. 499 OwningPtr<StackHintGenerator> CallStackHint; 500 501 public: 502 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 503 StringRef s, bool addPosRange = true, 504 StackHintGenerator *stackHint = 0) 505 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), 506 CallStackHint(stackHint) {} 507 508 ~PathDiagnosticEventPiece(); 509 510 /// Mark the diagnostic piece as being potentially prunable. This 511 /// flag may have been previously set, at which point it will not 512 /// be reset unless one specifies to do so. 513 void setPrunable(bool isPrunable, bool override = false) { 514 if (IsPrunable.hasValue() && !override) 515 return; 516 IsPrunable = isPrunable; 517 } 518 519 /// Return true if the diagnostic piece is prunable. 520 bool isPrunable() const { 521 return IsPrunable.hasValue() ? IsPrunable.getValue() : false; 522 } 523 524 bool hasCallStackHint() { 525 return CallStackHint.isValid(); 526 } 527 528 /// Produce the hint for the given node. The node contains 529 /// information about the call for which the diagnostic can be generated. 530 std::string getCallStackMessage(const ExplodedNode *N) { 531 if (CallStackHint) 532 return CallStackHint->getMessage(N); 533 return ""; 534 } 535 536 virtual void dump() const; 537 538 static inline bool classof(const PathDiagnosticPiece *P) { 539 return P->getKind() == Event; 540 } 541 }; 542 543 class PathDiagnosticCallPiece : public PathDiagnosticPiece { 544 PathDiagnosticCallPiece(const Decl *callerD, 545 const PathDiagnosticLocation &callReturnPos) 546 : PathDiagnosticPiece(Call), Caller(callerD), Callee(0), 547 NoExit(false), callReturn(callReturnPos) {} 548 549 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) 550 : PathDiagnosticPiece(Call), Caller(caller), Callee(0), 551 NoExit(true), path(oldPath) {} 552 553 const Decl *Caller; 554 const Decl *Callee; 555 556 // Flag signifying that this diagnostic has only call enter and no matching 557 // call exit. 558 bool NoExit; 559 560 // The custom string, which should appear after the call Return Diagnostic. 561 // TODO: Should we allow multiple diagnostics? 562 std::string CallStackMessage; 563 564 public: 565 PathDiagnosticLocation callEnter; 566 PathDiagnosticLocation callEnterWithin; 567 PathDiagnosticLocation callReturn; 568 PathPieces path; 569 570 virtual ~PathDiagnosticCallPiece(); 571 572 const Decl *getCaller() const { return Caller; } 573 574 const Decl *getCallee() const { return Callee; } 575 void setCallee(const CallEnter &CE, const SourceManager &SM); 576 577 bool hasCallStackMessage() { return !CallStackMessage.empty(); } 578 void setCallStackMessage(StringRef st) { 579 CallStackMessage = st; 580 } 581 582 virtual PathDiagnosticLocation getLocation() const { 583 return callEnter; 584 } 585 586 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; 587 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 588 getCallEnterWithinCallerEvent() const; 589 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; 590 591 virtual void flattenLocations() { 592 callEnter.flatten(); 593 callReturn.flatten(); 594 for (PathPieces::iterator I = path.begin(), 595 E = path.end(); I != E; ++I) (*I)->flattenLocations(); 596 } 597 598 static PathDiagnosticCallPiece *construct(const ExplodedNode *N, 599 const CallExitEnd &CE, 600 const SourceManager &SM); 601 602 static PathDiagnosticCallPiece *construct(PathPieces &pieces, 603 const Decl *caller); 604 605 virtual void dump() const; 606 607 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 608 609 static inline bool classof(const PathDiagnosticPiece *P) { 610 return P->getKind() == Call; 611 } 612 }; 613 614 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 615 std::vector<PathDiagnosticLocationPair> LPairs; 616 public: 617 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 618 const PathDiagnosticLocation &endPos, 619 StringRef s) 620 : PathDiagnosticPiece(s, ControlFlow) { 621 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 622 } 623 624 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 625 const PathDiagnosticLocation &endPos) 626 : PathDiagnosticPiece(ControlFlow) { 627 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 628 } 629 630 ~PathDiagnosticControlFlowPiece(); 631 632 PathDiagnosticLocation getStartLocation() const { 633 assert(!LPairs.empty() && 634 "PathDiagnosticControlFlowPiece needs at least one location."); 635 return LPairs[0].getStart(); 636 } 637 638 PathDiagnosticLocation getEndLocation() const { 639 assert(!LPairs.empty() && 640 "PathDiagnosticControlFlowPiece needs at least one location."); 641 return LPairs[0].getEnd(); 642 } 643 644 void setStartLocation(const PathDiagnosticLocation &L) { 645 LPairs[0].setStart(L); 646 } 647 648 void setEndLocation(const PathDiagnosticLocation &L) { 649 LPairs[0].setEnd(L); 650 } 651 652 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 653 654 virtual PathDiagnosticLocation getLocation() const { 655 return getStartLocation(); 656 } 657 658 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; 659 iterator begin() { return LPairs.begin(); } 660 iterator end() { return LPairs.end(); } 661 662 virtual void flattenLocations() { 663 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); 664 } 665 666 typedef std::vector<PathDiagnosticLocationPair>::const_iterator 667 const_iterator; 668 const_iterator begin() const { return LPairs.begin(); } 669 const_iterator end() const { return LPairs.end(); } 670 671 static inline bool classof(const PathDiagnosticPiece *P) { 672 return P->getKind() == ControlFlow; 673 } 674 675 virtual void dump() const; 676 677 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 678 }; 679 680 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 681 public: 682 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 683 : PathDiagnosticSpotPiece(pos, "", Macro) {} 684 685 ~PathDiagnosticMacroPiece(); 686 687 PathPieces subPieces; 688 689 bool containsEvent() const; 690 691 virtual void flattenLocations() { 692 PathDiagnosticSpotPiece::flattenLocations(); 693 for (PathPieces::iterator I = subPieces.begin(), 694 E = subPieces.end(); I != E; ++I) (*I)->flattenLocations(); 695 } 696 697 static inline bool classof(const PathDiagnosticPiece *P) { 698 return P->getKind() == Macro; 699 } 700 701 virtual void dump() const; 702 703 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 704 }; 705 706 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive 707 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, 708 /// each which represent the pieces of the path. 709 class PathDiagnostic : public llvm::FoldingSetNode { 710 const Decl *DeclWithIssue; 711 std::string BugType; 712 std::string VerboseDesc; 713 std::string ShortDesc; 714 std::string Category; 715 std::deque<std::string> OtherDesc; 716 717 /// \brief Loc The location of the path diagnostic report. 718 PathDiagnosticLocation Loc; 719 720 PathPieces pathImpl; 721 SmallVector<PathPieces *, 3> pathStack; 722 723 /// \brief Important bug uniqueing location. 724 /// The location info is useful to differentiate between bugs. 725 PathDiagnosticLocation UniqueingLoc; 726 const Decl *UniqueingDecl; 727 728 PathDiagnostic() LLVM_DELETED_FUNCTION; 729 public: 730 PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype, 731 StringRef verboseDesc, StringRef shortDesc, 732 StringRef category, PathDiagnosticLocation LocationToUnique, 733 const Decl *DeclToUnique); 734 735 ~PathDiagnostic(); 736 737 const PathPieces &path; 738 739 /// Return the path currently used by builders for constructing the 740 /// PathDiagnostic. 741 PathPieces &getActivePath() { 742 if (pathStack.empty()) 743 return pathImpl; 744 return *pathStack.back(); 745 } 746 747 /// Return a mutable version of 'path'. 748 PathPieces &getMutablePieces() { 749 return pathImpl; 750 } 751 752 /// Return the unrolled size of the path. 753 unsigned full_size(); 754 755 void pushActivePath(PathPieces *p) { pathStack.push_back(p); } 756 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } 757 758 bool isWithinCall() const { return !pathStack.empty(); } 759 760 void setEndOfPath(PathDiagnosticPiece *EndPiece) { 761 assert(!Loc.isValid() && "End location already set!"); 762 Loc = EndPiece->getLocation(); 763 assert(Loc.isValid() && "Invalid location for end-of-path piece"); 764 getActivePath().push_back(EndPiece); 765 } 766 767 void appendToDesc(StringRef S) { 768 if (!ShortDesc.empty()) 769 ShortDesc.append(S); 770 VerboseDesc.append(S); 771 } 772 773 void resetPath() { 774 pathStack.clear(); 775 pathImpl.clear(); 776 Loc = PathDiagnosticLocation(); 777 } 778 779 /// \brief If the last piece of the report point to the header file, resets 780 /// the location of the report to be the last location in the main source 781 /// file. 782 void resetDiagnosticLocationToMainFile(); 783 784 StringRef getVerboseDescription() const { return VerboseDesc; } 785 StringRef getShortDescription() const { 786 return ShortDesc.empty() ? VerboseDesc : ShortDesc; 787 } 788 StringRef getBugType() const { return BugType; } 789 StringRef getCategory() const { return Category; } 790 791 /// Return the semantic context where an issue occurred. If the 792 /// issue occurs along a path, this represents the "central" area 793 /// where the bug manifests. 794 const Decl *getDeclWithIssue() const { return DeclWithIssue; } 795 796 typedef std::deque<std::string>::const_iterator meta_iterator; 797 meta_iterator meta_begin() const { return OtherDesc.begin(); } 798 meta_iterator meta_end() const { return OtherDesc.end(); } 799 void addMeta(StringRef s) { OtherDesc.push_back(s); } 800 801 PathDiagnosticLocation getLocation() const { 802 assert(Loc.isValid() && "No report location set yet!"); 803 return Loc; 804 } 805 806 /// \brief Get the location on which the report should be uniqued. 807 PathDiagnosticLocation getUniqueingLoc() const { 808 return UniqueingLoc; 809 } 810 811 /// \brief Get the declaration containing the uniqueing location. 812 const Decl *getUniqueingDecl() const { 813 return UniqueingDecl; 814 } 815 816 void flattenLocations() { 817 Loc.flatten(); 818 for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 819 I != E; ++I) (*I)->flattenLocations(); 820 } 821 822 /// Profiles the diagnostic, independent of the path it references. 823 /// 824 /// This can be used to merge diagnostics that refer to the same issue 825 /// along different paths. 826 void Profile(llvm::FoldingSetNodeID &ID) const; 827 828 /// Profiles the diagnostic, including its path. 829 /// 830 /// Two diagnostics with the same issue along different paths will generate 831 /// different profiles. 832 void FullProfile(llvm::FoldingSetNodeID &ID) const; 833 }; 834 835 } // end GR namespace 836 837 } //end clang namespace 838 839 #endif 840