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 24 namespace clang { 25 26 class Decl; 27 class SourceManager; 28 class Stmt; 29 30 namespace ento { 31 32 //===----------------------------------------------------------------------===// 33 // High-level interface for handlers of path-sensitive diagnostics. 34 //===----------------------------------------------------------------------===// 35 36 class PathDiagnostic; 37 38 class PathDiagnosticClient : public DiagnosticClient { 39 public: PathDiagnosticClient()40 PathDiagnosticClient() {} 41 ~PathDiagnosticClient()42 virtual ~PathDiagnosticClient() {} 43 44 virtual void 45 FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade = 0) = 0; 46 FlushDiagnostics(llvm::SmallVectorImpl<std::string> & FilesMade)47 void FlushDiagnostics(llvm::SmallVectorImpl<std::string> &FilesMade) { 48 FlushDiagnostics(&FilesMade); 49 } 50 51 virtual llvm::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 }; getGenerationScheme()58 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } supportsLogicalOpControlFlow()59 virtual bool supportsLogicalOpControlFlow() const { return false; } supportsAllBlockEdges()60 virtual bool supportsAllBlockEdges() const { return false; } useVerboseDescription()61 virtual bool useVerboseDescription() const { return true; } 62 }; 63 64 //===----------------------------------------------------------------------===// 65 // Path-sensitive diagnostics. 66 //===----------------------------------------------------------------------===// 67 68 class PathDiagnosticRange : public SourceRange { 69 public: 70 const bool isPoint; 71 72 PathDiagnosticRange(const SourceRange &R, bool isP = false) SourceRange(R)73 : SourceRange(R), isPoint(isP) {} 74 }; 75 76 class PathDiagnosticLocation { 77 private: 78 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; 79 SourceRange R; 80 const Stmt *S; 81 const Decl *D; 82 const SourceManager *SM; 83 public: PathDiagnosticLocation()84 PathDiagnosticLocation() 85 : K(SingleLocK), S(0), D(0), SM(0) {} 86 PathDiagnosticLocation(FullSourceLoc L)87 PathDiagnosticLocation(FullSourceLoc L) 88 : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {} 89 PathDiagnosticLocation(const Stmt * s,const SourceManager & sm)90 PathDiagnosticLocation(const Stmt *s, const SourceManager &sm) 91 : K(StmtK), S(s), D(0), SM(&sm) {} 92 PathDiagnosticLocation(SourceRange r,const SourceManager & sm)93 PathDiagnosticLocation(SourceRange r, const SourceManager &sm) 94 : K(RangeK), R(r), S(0), D(0), SM(&sm) {} 95 PathDiagnosticLocation(const Decl * d,const SourceManager & sm)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 isValid()116 bool isValid() const { 117 return SM != 0; 118 } 119 getSourceManager()120 const SourceManager& getSourceManager() const { assert(isValid());return *SM;} 121 122 FullSourceLoc asLocation() const; 123 PathDiagnosticRange asRange() const; asStmt()124 const Stmt *asStmt() const { assert(isValid()); return S; } asDecl()125 const Decl *asDecl() const { assert(isValid()); return D; } 126 hasRange()127 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 128 invalidate()129 void invalidate() { 130 *this = PathDiagnosticLocation(); 131 } 132 133 void flatten(); 134 getManager()135 const SourceManager& getManager() const { assert(isValid()); return *SM; } 136 137 void Profile(llvm::FoldingSetNodeID &ID) const; 138 }; 139 140 class PathDiagnosticLocationPair { 141 private: 142 PathDiagnosticLocation Start, End; 143 public: PathDiagnosticLocationPair(const PathDiagnosticLocation & start,const PathDiagnosticLocation & end)144 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 145 const PathDiagnosticLocation &end) 146 : Start(start), End(end) {} 147 getStart()148 const PathDiagnosticLocation &getStart() const { return Start; } getEnd()149 const PathDiagnosticLocation &getEnd() const { return End; } 150 flatten()151 void flatten() { 152 Start.flatten(); 153 End.flatten(); 154 } 155 Profile(llvm::FoldingSetNodeID & ID)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 166 class PathDiagnosticPiece { 167 public: 168 enum Kind { ControlFlow, Event, Macro }; 169 enum DisplayHint { Above, Below }; 170 171 private: 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 183 protected: 184 PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below); 185 186 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 187 188 public: 189 virtual ~PathDiagnosticPiece(); 190 getString()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. getDisplayHint()195 DisplayHint getDisplayHint() const { return Hint; } 196 197 virtual PathDiagnosticLocation getLocation() const = 0; 198 virtual void flattenLocations() = 0; 199 getKind()200 Kind getKind() const { return kind; } 201 addRange(SourceRange R)202 void addRange(SourceRange R) { ranges.push_back(R); } 203 addRange(SourceLocation B,SourceLocation E)204 void addRange(SourceLocation B, SourceLocation E) { 205 ranges.push_back(SourceRange(B,E)); 206 } 207 addFixItHint(const FixItHint & Hint)208 void addFixItHint(const FixItHint& Hint) { 209 FixItHints.push_back(Hint); 210 } 211 212 typedef const SourceRange* range_iterator; 213 ranges_begin()214 range_iterator ranges_begin() const { 215 return ranges.empty() ? NULL : &ranges[0]; 216 } 217 ranges_end()218 range_iterator ranges_end() const { 219 return ranges_begin() + ranges.size(); 220 } 221 222 typedef const FixItHint *fixit_iterator; 223 fixit_begin()224 fixit_iterator fixit_begin() const { 225 return FixItHints.empty()? 0 : &FixItHints[0]; 226 } 227 fixit_end()228 fixit_iterator fixit_end() const { 229 return FixItHints.empty()? 0 230 : &FixItHints[0] + FixItHints.size(); 231 } 232 classof(const PathDiagnosticPiece * P)233 static inline bool classof(const PathDiagnosticPiece* P) { 234 return true; 235 } 236 237 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 238 }; 239 240 class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 241 private: 242 PathDiagnosticLocation Pos; 243 public: 244 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 245 llvm::StringRef s, 246 PathDiagnosticPiece::Kind k, 247 bool addPosRange = true) PathDiagnosticPiece(s,k)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 getLocation()254 PathDiagnosticLocation getLocation() const { return Pos; } flattenLocations()255 virtual void flattenLocations() { Pos.flatten(); } 256 257 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 258 }; 259 260 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 261 262 public: 263 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 264 llvm::StringRef s, bool addPosRange = true) PathDiagnosticSpotPiece(pos,s,Event,addPosRange)265 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} 266 267 ~PathDiagnosticEventPiece(); 268 classof(const PathDiagnosticPiece * P)269 static inline bool classof(const PathDiagnosticPiece* P) { 270 return P->getKind() == Event; 271 } 272 }; 273 274 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 275 std::vector<PathDiagnosticLocationPair> LPairs; 276 public: PathDiagnosticControlFlowPiece(const PathDiagnosticLocation & startPos,const PathDiagnosticLocation & endPos,llvm::StringRef s)277 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 278 const PathDiagnosticLocation &endPos, 279 llvm::StringRef s) 280 : PathDiagnosticPiece(s, ControlFlow) { 281 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 282 } 283 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation & startPos,const PathDiagnosticLocation & endPos)284 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 285 const PathDiagnosticLocation &endPos) 286 : PathDiagnosticPiece(ControlFlow) { 287 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 288 } 289 290 ~PathDiagnosticControlFlowPiece(); 291 getStartLocation()292 PathDiagnosticLocation getStartLocation() const { 293 assert(!LPairs.empty() && 294 "PathDiagnosticControlFlowPiece needs at least one location."); 295 return LPairs[0].getStart(); 296 } 297 getEndLocation()298 PathDiagnosticLocation getEndLocation() const { 299 assert(!LPairs.empty() && 300 "PathDiagnosticControlFlowPiece needs at least one location."); 301 return LPairs[0].getEnd(); 302 } 303 push_back(const PathDiagnosticLocationPair & X)304 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 305 getLocation()306 virtual PathDiagnosticLocation getLocation() const { 307 return getStartLocation(); 308 } 309 310 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; begin()311 iterator begin() { return LPairs.begin(); } end()312 iterator end() { return LPairs.end(); } 313 flattenLocations()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; begin()320 const_iterator begin() const { return LPairs.begin(); } end()321 const_iterator end() const { return LPairs.end(); } 322 classof(const PathDiagnosticPiece * P)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 330 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 331 std::vector<PathDiagnosticPiece*> SubPieces; 332 public: PathDiagnosticMacroPiece(const PathDiagnosticLocation & pos)333 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 334 : PathDiagnosticSpotPiece(pos, "", Macro) {} 335 336 ~PathDiagnosticMacroPiece(); 337 338 bool containsEvent() const; 339 push_back(PathDiagnosticPiece * P)340 void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); } 341 342 typedef std::vector<PathDiagnosticPiece*>::iterator iterator; begin()343 iterator begin() { return SubPieces.begin(); } end()344 iterator end() { return SubPieces.end(); } 345 flattenLocations()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; begin()352 const_iterator begin() const { return SubPieces.begin(); } end()353 const_iterator end() const { return SubPieces.end(); } 354 classof(const PathDiagnosticPiece * P)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. 365 class 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 373 public: 374 PathDiagnostic(); 375 376 PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, 377 llvm::StringRef category); 378 379 ~PathDiagnostic(); 380 getDescription()381 llvm::StringRef getDescription() const { return Desc; } getBugType()382 llvm::StringRef getBugType() const { return BugType; } getCategory()383 llvm::StringRef getCategory() const { return Category; } 384 385 typedef std::deque<std::string>::const_iterator meta_iterator; meta_begin()386 meta_iterator meta_begin() const { return OtherDesc.begin(); } meta_end()387 meta_iterator meta_end() const { return OtherDesc.end(); } addMeta(llvm::StringRef s)388 void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); } 389 getLocation()390 PathDiagnosticLocation getLocation() const { 391 assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic."); 392 return rbegin()->getLocation(); 393 } 394 push_front(PathDiagnosticPiece * piece)395 void push_front(PathDiagnosticPiece* piece) { 396 assert(piece); 397 path.push_front(piece); 398 ++Size; 399 } 400 push_back(PathDiagnosticPiece * piece)401 void push_back(PathDiagnosticPiece* piece) { 402 assert(piece); 403 path.push_back(piece); 404 ++Size; 405 } 406 back()407 PathDiagnosticPiece* back() { 408 return path.back(); 409 } 410 back()411 const PathDiagnosticPiece* back() const { 412 return path.back(); 413 } 414 size()415 unsigned size() const { return Size; } empty()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: iterator(const ImplTy & i)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: const_iterator(const ImplTy & i)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 begin()477 iterator begin() { return path.begin(); } end()478 iterator end() { return path.end(); } 479 begin()480 const_iterator begin() const { return path.begin(); } end()481 const_iterator end() const { return path.end(); } 482 483 // reverse iterator creation methods. rbegin()484 reverse_iterator rbegin() { return reverse_iterator(end()); } rbegin()485 const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } rend()486 reverse_iterator rend() { return reverse_iterator(begin()); } rend()487 const_reverse_iterator rend() const { return const_reverse_iterator(begin());} 488 flattenLocations()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