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