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