PathDiagnostic.h revision a6215b93c45ee5931536b57d10b987747143313b
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 "llvm/ADT/FoldingSet.h" 19#include "llvm/ADT/PointerUnion.h" 20#include <deque> 21#include <iterator> 22#include <string> 23#include <vector> 24 25namespace clang { 26 27class AnalysisDeclContext; 28class BinaryOperator; 29class CompoundStmt; 30class Decl; 31class LocationContext; 32class MemberExpr; 33class ParentMap; 34class ProgramPoint; 35class SourceManager; 36class Stmt; 37 38namespace ento { 39 40class ExplodedNode; 41 42//===----------------------------------------------------------------------===// 43// High-level interface for handlers of path-sensitive diagnostics. 44//===----------------------------------------------------------------------===// 45 46class PathDiagnostic; 47 48class PathDiagnosticConsumer { 49 virtual void anchor(); 50public: 51 PathDiagnosticConsumer() : flushed(false) {} 52 virtual ~PathDiagnosticConsumer(); 53 54 void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); 55 56 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 57 SmallVectorImpl<std::string> *FilesMade) 58 = 0; 59 60 virtual StringRef getName() const = 0; 61 62 void HandlePathDiagnostic(PathDiagnostic *D); 63 64 enum PathGenerationScheme { Minimal, Extensive }; 65 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } 66 virtual bool supportsLogicalOpControlFlow() const { return false; } 67 virtual bool supportsAllBlockEdges() const { return false; } 68 virtual bool useVerboseDescription() const { return true; } 69 70protected: 71 bool flushed; 72 llvm::FoldingSet<PathDiagnostic> Diags; 73}; 74 75//===----------------------------------------------------------------------===// 76// Path-sensitive diagnostics. 77//===----------------------------------------------------------------------===// 78 79class PathDiagnosticRange : public SourceRange { 80public: 81 bool isPoint; 82 83 PathDiagnosticRange(const SourceRange &R, bool isP = false) 84 : SourceRange(R), isPoint(isP) {} 85 86 PathDiagnosticRange() : isPoint(false) {} 87}; 88 89typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> 90 LocationOrAnalysisDeclContext; 91 92class PathDiagnosticLocation { 93private: 94 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; 95 const Stmt *S; 96 const Decl *D; 97 const SourceManager *SM; 98 FullSourceLoc Loc; 99 PathDiagnosticRange Range; 100 101 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, 102 Kind kind) 103 : K(kind), S(0), D(0), SM(&sm), 104 Loc(genLocation(L)), Range(genRange()) { 105 assert(Loc.isValid()); 106 assert(Range.isValid()); 107 } 108 109 FullSourceLoc 110 genLocation(SourceLocation L = SourceLocation(), 111 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 112 113 PathDiagnosticRange 114 genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 115 116public: 117 /// Create an invalid location. 118 PathDiagnosticLocation() 119 : K(SingleLocK), S(0), D(0), SM(0) {} 120 121 /// Create a location corresponding to the given statement. 122 PathDiagnosticLocation(const Stmt *s, 123 const SourceManager &sm, 124 LocationOrAnalysisDeclContext lac) 125 : K(StmtK), S(s), D(0), SM(&sm), 126 Loc(genLocation(SourceLocation(), lac)), 127 Range(genRange(lac)) { 128 assert(S); 129 assert(Loc.isValid()); 130 assert(Range.isValid()); 131 } 132 133 /// Create a location corresponding to the given declaration. 134 PathDiagnosticLocation(const Decl *d, const SourceManager &sm) 135 : K(DeclK), S(0), D(d), SM(&sm), 136 Loc(genLocation()), Range(genRange()) { 137 assert(D); 138 assert(Loc.isValid()); 139 assert(Range.isValid()); 140 } 141 142 /// Create a location corresponding to the given declaration. 143 static PathDiagnosticLocation create(const Decl *D, 144 const SourceManager &SM) { 145 return PathDiagnosticLocation(D, SM); 146 } 147 148 /// Create a location for the beginning of the declaration. 149 static PathDiagnosticLocation createBegin(const Decl *D, 150 const SourceManager &SM); 151 152 /// Create a location for the beginning of the statement. 153 static PathDiagnosticLocation createBegin(const Stmt *S, 154 const SourceManager &SM, 155 const LocationOrAnalysisDeclContext LAC); 156 157 /// Create the location for the operator of the binary expression. 158 /// Assumes the statement has a valid location. 159 static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, 160 const SourceManager &SM); 161 162 /// For member expressions, return the location of the '.' or '->'. 163 /// Assumes the statement has a valid location. 164 static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, 165 const SourceManager &SM); 166 167 /// Create a location for the beginning of the compound statement. 168 /// Assumes the statement has a valid location. 169 static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, 170 const SourceManager &SM); 171 172 /// Create a location for the end of the compound statement. 173 /// Assumes the statement has a valid location. 174 static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, 175 const SourceManager &SM); 176 177 /// Create a location for the beginning of the enclosing declaration body. 178 /// Defaults to the beginning of the first statement in the declaration body. 179 static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, 180 const SourceManager &SM); 181 182 /// Constructs a location for the end of the enclosing declaration body. 183 /// Defaults to the end of brace. 184 static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, 185 const SourceManager &SM); 186 187 /// Create a location corresponding to the given valid ExplodedNode. 188 static PathDiagnosticLocation create(const ProgramPoint& P, 189 const SourceManager &SMng); 190 191 /// Create a location corresponding to the next valid ExplodedNode as end 192 /// of path location. 193 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N, 194 const SourceManager &SM); 195 196 /// Convert the given location into a single kind location. 197 static PathDiagnosticLocation createSingleLocation( 198 const PathDiagnosticLocation &PDL); 199 200 bool operator==(const PathDiagnosticLocation &X) const { 201 return K == X.K && Loc == X.Loc && Range == X.Range; 202 } 203 204 bool operator!=(const PathDiagnosticLocation &X) const { 205 return !(*this == X); 206 } 207 208 bool isValid() const { 209 return SM != 0; 210 } 211 212 FullSourceLoc asLocation() const { 213 return Loc; 214 } 215 216 PathDiagnosticRange asRange() const { 217 return Range; 218 } 219 220 const Stmt *asStmt() const { assert(isValid()); return S; } 221 const Decl *asDecl() const { assert(isValid()); return D; } 222 223 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 224 225 void invalidate() { 226 *this = PathDiagnosticLocation(); 227 } 228 229 void flatten(); 230 231 const SourceManager& getManager() const { assert(isValid()); return *SM; } 232 233 void Profile(llvm::FoldingSetNodeID &ID) const; 234}; 235 236class PathDiagnosticLocationPair { 237private: 238 PathDiagnosticLocation Start, End; 239public: 240 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 241 const PathDiagnosticLocation &end) 242 : Start(start), End(end) {} 243 244 const PathDiagnosticLocation &getStart() const { return Start; } 245 const PathDiagnosticLocation &getEnd() const { return End; } 246 247 void flatten() { 248 Start.flatten(); 249 End.flatten(); 250 } 251 252 void Profile(llvm::FoldingSetNodeID &ID) const { 253 Start.Profile(ID); 254 End.Profile(ID); 255 } 256}; 257 258//===----------------------------------------------------------------------===// 259// Path "pieces" for path-sensitive diagnostics. 260//===----------------------------------------------------------------------===// 261 262class PathDiagnosticPiece { 263public: 264 enum Kind { ControlFlow, Event, Macro, CallEnter, CallExit }; 265 enum DisplayHint { Above, Below }; 266 267private: 268 const std::string str; 269 const Kind kind; 270 const DisplayHint Hint; 271 std::vector<SourceRange> ranges; 272 273 // Do not implement: 274 PathDiagnosticPiece(); 275 PathDiagnosticPiece(const PathDiagnosticPiece &P); 276 PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); 277 278protected: 279 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); 280 281 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 282 283public: 284 virtual ~PathDiagnosticPiece(); 285 286 const std::string& getString() const { return str; } 287 288 /// getDisplayHint - Return a hint indicating where the diagnostic should 289 /// be displayed by the PathDiagnosticConsumer. 290 DisplayHint getDisplayHint() const { return Hint; } 291 292 virtual PathDiagnosticLocation getLocation() const = 0; 293 virtual void flattenLocations() = 0; 294 295 Kind getKind() const { return kind; } 296 297 void addRange(SourceRange R) { 298 if (!R.isValid()) 299 return; 300 ranges.push_back(R); 301 } 302 303 void addRange(SourceLocation B, SourceLocation E) { 304 if (!B.isValid() || !E.isValid()) 305 return; 306 ranges.push_back(SourceRange(B,E)); 307 } 308 309 typedef const SourceRange* range_iterator; 310 311 range_iterator ranges_begin() const { 312 return ranges.empty() ? NULL : &ranges[0]; 313 } 314 315 range_iterator ranges_end() const { 316 return ranges_begin() + ranges.size(); 317 } 318 319 static inline bool classof(const PathDiagnosticPiece *P) { 320 return true; 321 } 322 323 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 324}; 325 326class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 327private: 328 PathDiagnosticLocation Pos; 329public: 330 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 331 StringRef s, 332 PathDiagnosticPiece::Kind k, 333 bool addPosRange = true) 334 : PathDiagnosticPiece(s, k), Pos(pos) { 335 assert(Pos.isValid() && Pos.asLocation().isValid() && 336 "PathDiagnosticSpotPiece's must have a valid location."); 337 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); 338 } 339 340 PathDiagnosticLocation getLocation() const { return Pos; } 341 virtual void flattenLocations() { Pos.flatten(); } 342 343 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 344}; 345 346class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 347 348public: 349 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 350 StringRef s, bool addPosRange = true) 351 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} 352 353 ~PathDiagnosticEventPiece(); 354 355 static inline bool classof(const PathDiagnosticPiece *P) { 356 return P->getKind() == Event; 357 } 358}; 359 360class PathDiagnosticCallEnterPiece : public PathDiagnosticSpotPiece { 361public: 362 PathDiagnosticCallEnterPiece(const PathDiagnosticLocation &pos, 363 StringRef s) 364 : PathDiagnosticSpotPiece(pos, s, CallEnter, false) {} 365 366 ~PathDiagnosticCallEnterPiece(); 367 368 static inline bool classof(const PathDiagnosticPiece *P) { 369 return P->getKind() == CallEnter; 370 } 371}; 372 373class PathDiagnosticCallExitPiece : public PathDiagnosticSpotPiece { 374public: 375 PathDiagnosticCallExitPiece(const PathDiagnosticLocation &pos, 376 StringRef s) 377 : PathDiagnosticSpotPiece(pos, s, CallExit, false) {} 378 379 ~PathDiagnosticCallExitPiece(); 380 381 static inline bool classof(const PathDiagnosticPiece *P) { 382 return P->getKind() == CallExit; 383 } 384}; 385 386class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 387 std::vector<PathDiagnosticLocationPair> LPairs; 388public: 389 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 390 const PathDiagnosticLocation &endPos, 391 StringRef s) 392 : PathDiagnosticPiece(s, ControlFlow) { 393 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 394 } 395 396 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 397 const PathDiagnosticLocation &endPos) 398 : PathDiagnosticPiece(ControlFlow) { 399 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 400 } 401 402 ~PathDiagnosticControlFlowPiece(); 403 404 PathDiagnosticLocation getStartLocation() const { 405 assert(!LPairs.empty() && 406 "PathDiagnosticControlFlowPiece needs at least one location."); 407 return LPairs[0].getStart(); 408 } 409 410 PathDiagnosticLocation getEndLocation() const { 411 assert(!LPairs.empty() && 412 "PathDiagnosticControlFlowPiece needs at least one location."); 413 return LPairs[0].getEnd(); 414 } 415 416 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 417 418 virtual PathDiagnosticLocation getLocation() const { 419 return getStartLocation(); 420 } 421 422 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; 423 iterator begin() { return LPairs.begin(); } 424 iterator end() { return LPairs.end(); } 425 426 virtual void flattenLocations() { 427 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); 428 } 429 430 typedef std::vector<PathDiagnosticLocationPair>::const_iterator 431 const_iterator; 432 const_iterator begin() const { return LPairs.begin(); } 433 const_iterator end() const { return LPairs.end(); } 434 435 static inline bool classof(const PathDiagnosticPiece *P) { 436 return P->getKind() == ControlFlow; 437 } 438 439 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 440}; 441 442class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 443 std::vector<PathDiagnosticPiece*> SubPieces; 444public: 445 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 446 : PathDiagnosticSpotPiece(pos, "", Macro) {} 447 448 ~PathDiagnosticMacroPiece(); 449 450 bool containsEvent() const; 451 452 void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); } 453 454 typedef std::vector<PathDiagnosticPiece*>::iterator iterator; 455 iterator begin() { return SubPieces.begin(); } 456 iterator end() { return SubPieces.end(); } 457 458 virtual void flattenLocations() { 459 PathDiagnosticSpotPiece::flattenLocations(); 460 for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); 461 } 462 463 typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator; 464 const_iterator begin() const { return SubPieces.begin(); } 465 const_iterator end() const { return SubPieces.end(); } 466 467 static inline bool classof(const PathDiagnosticPiece *P) { 468 return P->getKind() == Macro; 469 } 470 471 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 472}; 473 474/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive 475/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, 476/// each which represent the pieces of the path. 477class PathDiagnostic : public llvm::FoldingSetNode { 478 std::deque<PathDiagnosticPiece*> path; 479 unsigned Size; 480 std::string BugType; 481 std::string Desc; 482 std::string Category; 483 std::deque<std::string> OtherDesc; 484 485public: 486 PathDiagnostic(); 487 488 PathDiagnostic(StringRef bugtype, StringRef desc, 489 StringRef category); 490 491 ~PathDiagnostic(); 492 493 StringRef getDescription() const { return Desc; } 494 StringRef getBugType() const { return BugType; } 495 StringRef getCategory() const { return Category; } 496 497 typedef std::deque<std::string>::const_iterator meta_iterator; 498 meta_iterator meta_begin() const { return OtherDesc.begin(); } 499 meta_iterator meta_end() const { return OtherDesc.end(); } 500 void addMeta(StringRef s) { OtherDesc.push_back(s); } 501 502 PathDiagnosticLocation getLocation() const { 503 assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); 504 return rbegin()->getLocation(); 505 } 506 507 void push_front(PathDiagnosticPiece *piece) { 508 assert(piece); 509 path.push_front(piece); 510 ++Size; 511 } 512 513 void push_back(PathDiagnosticPiece *piece) { 514 assert(piece); 515 path.push_back(piece); 516 ++Size; 517 } 518 519 PathDiagnosticPiece *back() { 520 return path.back(); 521 } 522 523 const PathDiagnosticPiece *back() const { 524 return path.back(); 525 } 526 527 unsigned size() const { return Size; } 528 bool empty() const { return Size == 0; } 529 530 void resetPath(bool deletePieces = true); 531 532 class iterator { 533 public: 534 typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy; 535 536 typedef PathDiagnosticPiece value_type; 537 typedef value_type& reference; 538 typedef value_type* pointer; 539 typedef ptrdiff_t difference_type; 540 typedef std::bidirectional_iterator_tag iterator_category; 541 542 private: 543 ImplTy I; 544 545 public: 546 iterator(const ImplTy& i) : I(i) {} 547 548 bool operator==(const iterator &X) const { return I == X.I; } 549 bool operator!=(const iterator &X) const { return I != X.I; } 550 551 PathDiagnosticPiece& operator*() const { return **I; } 552 PathDiagnosticPiece *operator->() const { return *I; } 553 554 iterator &operator++() { ++I; return *this; } 555 iterator &operator--() { --I; return *this; } 556 }; 557 558 class const_iterator { 559 public: 560 typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy; 561 562 typedef const PathDiagnosticPiece value_type; 563 typedef value_type& reference; 564 typedef value_type* pointer; 565 typedef ptrdiff_t difference_type; 566 typedef std::bidirectional_iterator_tag iterator_category; 567 568 private: 569 ImplTy I; 570 571 public: 572 const_iterator(const ImplTy& i) : I(i) {} 573 574 bool operator==(const const_iterator &X) const { return I == X.I; } 575 bool operator!=(const const_iterator &X) const { return I != X.I; } 576 577 reference operator*() const { return **I; } 578 pointer operator->() const { return *I; } 579 580 const_iterator &operator++() { ++I; return *this; } 581 const_iterator &operator--() { --I; return *this; } 582 }; 583 584 typedef std::reverse_iterator<iterator> reverse_iterator; 585 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 586 587 // forward iterator creation methods. 588 589 iterator begin() { return path.begin(); } 590 iterator end() { return path.end(); } 591 592 const_iterator begin() const { return path.begin(); } 593 const_iterator end() const { return path.end(); } 594 595 // reverse iterator creation methods. 596 reverse_iterator rbegin() { return reverse_iterator(end()); } 597 const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } 598 reverse_iterator rend() { return reverse_iterator(begin()); } 599 const_reverse_iterator rend() const { return const_reverse_iterator(begin());} 600 601 void flattenLocations() { 602 for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); 603 } 604 605 void Profile(llvm::FoldingSetNodeID &ID) const; 606 607 void FullProfile(llvm::FoldingSetNodeID &ID) const; 608}; 609 610} // end GR namespace 611 612} //end clang namespace 613 614#endif 615