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