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