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