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