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