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