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