PathDiagnostic.h revision 33e8491d7cf757812b9f8d126e0368c3ac0d2dd6
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 bool isValid() const { 124 return SM != 0; 125 } 126 127 FullSourceLoc asLocation() const; 128 PathDiagnosticRange asRange() const; 129 const Stmt *asStmt() const { assert(isValid()); return S; } 130 const Decl *asDecl() const { assert(isValid()); return D; } 131 132 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 133 134 void invalidate() { 135 *this = PathDiagnosticLocation(); 136 } 137 138 void flatten(); 139 140 const SourceManager& getManager() const { assert(isValid()); return *SM; } 141 142 void Profile(llvm::FoldingSetNodeID &ID) const; 143}; 144 145class PathDiagnosticLocationPair { 146private: 147 PathDiagnosticLocation Start, End; 148public: 149 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 150 const PathDiagnosticLocation &end) 151 : Start(start), End(end) {} 152 153 const PathDiagnosticLocation &getStart() const { return Start; } 154 const PathDiagnosticLocation &getEnd() const { return End; } 155 156 void flatten() { 157 Start.flatten(); 158 End.flatten(); 159 } 160 161 void Profile(llvm::FoldingSetNodeID &ID) const { 162 Start.Profile(ID); 163 End.Profile(ID); 164 } 165}; 166 167//===----------------------------------------------------------------------===// 168// Path "pieces" for path-sensitive diagnostics. 169//===----------------------------------------------------------------------===// 170 171class PathDiagnosticPiece { 172public: 173 enum Kind { ControlFlow, Event, Macro }; 174 enum DisplayHint { Above, Below }; 175 176private: 177 const std::string str; 178 std::vector<FixItHint> FixItHints; 179 const Kind kind; 180 const DisplayHint Hint; 181 std::vector<SourceRange> ranges; 182 183 // Do not implement: 184 PathDiagnosticPiece(); 185 PathDiagnosticPiece(const PathDiagnosticPiece &P); 186 PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); 187 188protected: 189 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); 190 191 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 192 193public: 194 virtual ~PathDiagnosticPiece(); 195 196 const std::string& getString() const { return str; } 197 198 /// getDisplayHint - Return a hint indicating where the diagnostic should 199 /// be displayed by the PathDiagnosticClient. 200 DisplayHint getDisplayHint() const { return Hint; } 201 202 virtual PathDiagnosticLocation getLocation() const = 0; 203 virtual void flattenLocations() = 0; 204 205 Kind getKind() const { return kind; } 206 207 void addRange(SourceRange R) { ranges.push_back(R); } 208 209 void addRange(SourceLocation B, SourceLocation E) { 210 ranges.push_back(SourceRange(B,E)); 211 } 212 213 void addFixItHint(const FixItHint& Hint) { 214 FixItHints.push_back(Hint); 215 } 216 217 typedef const SourceRange* range_iterator; 218 219 range_iterator ranges_begin() const { 220 return ranges.empty() ? NULL : &ranges[0]; 221 } 222 223 range_iterator ranges_end() const { 224 return ranges_begin() + ranges.size(); 225 } 226 227 typedef const FixItHint *fixit_iterator; 228 229 fixit_iterator fixit_begin() const { 230 return FixItHints.empty()? 0 : &FixItHints[0]; 231 } 232 233 fixit_iterator fixit_end() const { 234 return FixItHints.empty()? 0 235 : &FixItHints[0] + FixItHints.size(); 236 } 237 238 static inline bool classof(const PathDiagnosticPiece *P) { 239 return true; 240 } 241 242 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 243}; 244 245class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 246private: 247 PathDiagnosticLocation Pos; 248public: 249 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 250 StringRef s, 251 PathDiagnosticPiece::Kind k, 252 bool addPosRange = true) 253 : PathDiagnosticPiece(s, k), Pos(pos) { 254 assert(Pos.asLocation().isValid() && 255 "PathDiagnosticSpotPiece's must have a valid location."); 256 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); 257 } 258 259 PathDiagnosticLocation getLocation() const { return Pos; } 260 virtual void flattenLocations() { Pos.flatten(); } 261 262 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 263}; 264 265class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 266 267public: 268 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 269 StringRef s, bool addPosRange = true) 270 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} 271 272 ~PathDiagnosticEventPiece(); 273 274 static inline bool classof(const PathDiagnosticPiece *P) { 275 return P->getKind() == Event; 276 } 277}; 278 279class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 280 std::vector<PathDiagnosticLocationPair> LPairs; 281public: 282 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 283 const PathDiagnosticLocation &endPos, 284 StringRef s) 285 : PathDiagnosticPiece(s, ControlFlow) { 286 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 287 } 288 289 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 290 const PathDiagnosticLocation &endPos) 291 : PathDiagnosticPiece(ControlFlow) { 292 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 293 } 294 295 ~PathDiagnosticControlFlowPiece(); 296 297 PathDiagnosticLocation getStartLocation() const { 298 assert(!LPairs.empty() && 299 "PathDiagnosticControlFlowPiece needs at least one location."); 300 return LPairs[0].getStart(); 301 } 302 303 PathDiagnosticLocation getEndLocation() const { 304 assert(!LPairs.empty() && 305 "PathDiagnosticControlFlowPiece needs at least one location."); 306 return LPairs[0].getEnd(); 307 } 308 309 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 310 311 virtual PathDiagnosticLocation getLocation() const { 312 return getStartLocation(); 313 } 314 315 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; 316 iterator begin() { return LPairs.begin(); } 317 iterator end() { return LPairs.end(); } 318 319 virtual void flattenLocations() { 320 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); 321 } 322 323 typedef std::vector<PathDiagnosticLocationPair>::const_iterator 324 const_iterator; 325 const_iterator begin() const { return LPairs.begin(); } 326 const_iterator end() const { return LPairs.end(); } 327 328 static inline bool classof(const PathDiagnosticPiece *P) { 329 return P->getKind() == ControlFlow; 330 } 331 332 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 333}; 334 335class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 336 std::vector<PathDiagnosticPiece*> SubPieces; 337public: 338 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 339 : PathDiagnosticSpotPiece(pos, "", Macro) {} 340 341 ~PathDiagnosticMacroPiece(); 342 343 bool containsEvent() const; 344 345 void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); } 346 347 typedef std::vector<PathDiagnosticPiece*>::iterator iterator; 348 iterator begin() { return SubPieces.begin(); } 349 iterator end() { return SubPieces.end(); } 350 351 virtual void flattenLocations() { 352 PathDiagnosticSpotPiece::flattenLocations(); 353 for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations(); 354 } 355 356 typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator; 357 const_iterator begin() const { return SubPieces.begin(); } 358 const_iterator end() const { return SubPieces.end(); } 359 360 static inline bool classof(const PathDiagnosticPiece *P) { 361 return P->getKind() == Macro; 362 } 363 364 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 365}; 366 367/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive 368/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, 369/// each which represent the pieces of the path. 370class PathDiagnostic : public llvm::FoldingSetNode { 371 std::deque<PathDiagnosticPiece*> path; 372 unsigned Size; 373 std::string BugType; 374 std::string Desc; 375 std::string Category; 376 std::deque<std::string> OtherDesc; 377 378public: 379 PathDiagnostic(); 380 381 PathDiagnostic(StringRef bugtype, StringRef desc, 382 StringRef category); 383 384 ~PathDiagnostic(); 385 386 StringRef getDescription() const { return Desc; } 387 StringRef getBugType() const { return BugType; } 388 StringRef getCategory() const { return Category; } 389 390 typedef std::deque<std::string>::const_iterator meta_iterator; 391 meta_iterator meta_begin() const { return OtherDesc.begin(); } 392 meta_iterator meta_end() const { return OtherDesc.end(); } 393 void addMeta(StringRef s) { OtherDesc.push_back(s); } 394 395 PathDiagnosticLocation getLocation() const { 396 assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); 397 return rbegin()->getLocation(); 398 } 399 400 void push_front(PathDiagnosticPiece *piece) { 401 assert(piece); 402 path.push_front(piece); 403 ++Size; 404 } 405 406 void push_back(PathDiagnosticPiece *piece) { 407 assert(piece); 408 path.push_back(piece); 409 ++Size; 410 } 411 412 PathDiagnosticPiece *back() { 413 return path.back(); 414 } 415 416 const PathDiagnosticPiece *back() const { 417 return path.back(); 418 } 419 420 unsigned size() const { return Size; } 421 bool empty() const { return Size == 0; } 422 423 void resetPath(bool deletePieces = true); 424 425 class iterator { 426 public: 427 typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy; 428 429 typedef PathDiagnosticPiece value_type; 430 typedef value_type& reference; 431 typedef value_type* pointer; 432 typedef ptrdiff_t difference_type; 433 typedef std::bidirectional_iterator_tag iterator_category; 434 435 private: 436 ImplTy I; 437 438 public: 439 iterator(const ImplTy& i) : I(i) {} 440 441 bool operator==(const iterator &X) const { return I == X.I; } 442 bool operator!=(const iterator &X) const { return I != X.I; } 443 444 PathDiagnosticPiece& operator*() const { return **I; } 445 PathDiagnosticPiece *operator->() const { return *I; } 446 447 iterator &operator++() { ++I; return *this; } 448 iterator &operator--() { --I; return *this; } 449 }; 450 451 class const_iterator { 452 public: 453 typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy; 454 455 typedef const PathDiagnosticPiece value_type; 456 typedef value_type& reference; 457 typedef value_type* pointer; 458 typedef ptrdiff_t difference_type; 459 typedef std::bidirectional_iterator_tag iterator_category; 460 461 private: 462 ImplTy I; 463 464 public: 465 const_iterator(const ImplTy& i) : I(i) {} 466 467 bool operator==(const const_iterator &X) const { return I == X.I; } 468 bool operator!=(const const_iterator &X) const { return I != X.I; } 469 470 reference operator*() const { return **I; } 471 pointer operator->() const { return *I; } 472 473 const_iterator &operator++() { ++I; return *this; } 474 const_iterator &operator--() { --I; return *this; } 475 }; 476 477 typedef std::reverse_iterator<iterator> reverse_iterator; 478 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 479 480 // forward iterator creation methods. 481 482 iterator begin() { return path.begin(); } 483 iterator end() { return path.end(); } 484 485 const_iterator begin() const { return path.begin(); } 486 const_iterator end() const { return path.end(); } 487 488 // reverse iterator creation methods. 489 reverse_iterator rbegin() { return reverse_iterator(end()); } 490 const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } 491 reverse_iterator rend() { return reverse_iterator(begin()); } 492 const_reverse_iterator rend() const { return const_reverse_iterator(begin());} 493 494 void flattenLocations() { 495 for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations(); 496 } 497 498 void Profile(llvm::FoldingSetNodeID &ID) const; 499}; 500 501} // end GR namespace 502 503} //end clang namespace 504 505#endif 506