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