PathDiagnostic.h revision 097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898
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/SourceLocation.h" 18#include "clang/Analysis/ProgramPoint.h" 19#include "llvm/ADT/FoldingSet.h" 20#include "llvm/ADT/IntrusiveRefCntPtr.h" 21#include "llvm/ADT/PointerUnion.h" 22#include <deque> 23#include <iterator> 24#include <string> 25#include <vector> 26 27namespace clang { 28 29class AnalysisDeclContext; 30class BinaryOperator; 31class CompoundStmt; 32class Decl; 33class LocationContext; 34class MemberExpr; 35class ParentMap; 36class ProgramPoint; 37class SourceManager; 38class Stmt; 39 40namespace ento { 41 42class ExplodedNode; 43 44//===----------------------------------------------------------------------===// 45// High-level interface for handlers of path-sensitive diagnostics. 46//===----------------------------------------------------------------------===// 47 48class PathDiagnostic; 49 50class PathDiagnosticConsumer { 51 virtual void anchor(); 52public: 53 PathDiagnosticConsumer() : flushed(false) {} 54 virtual ~PathDiagnosticConsumer(); 55 56 void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); 57 58 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 59 SmallVectorImpl<std::string> *FilesMade) 60 = 0; 61 62 virtual StringRef getName() const = 0; 63 64 void HandlePathDiagnostic(PathDiagnostic *D); 65 66 enum PathGenerationScheme { Minimal, Extensive }; 67 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } 68 virtual bool supportsLogicalOpControlFlow() const { return false; } 69 virtual bool supportsAllBlockEdges() const { return false; } 70 virtual bool useVerboseDescription() const { return true; } 71 72 /// Return true if the PathDiagnosticConsumer supports individual 73 /// PathDiagnostics that span multiple files. 74 virtual bool supportsCrossFileDiagnostics() const { return false; } 75 76protected: 77 bool flushed; 78 llvm::FoldingSet<PathDiagnostic> Diags; 79}; 80 81//===----------------------------------------------------------------------===// 82// Path-sensitive diagnostics. 83//===----------------------------------------------------------------------===// 84 85class PathDiagnosticRange : public SourceRange { 86public: 87 bool isPoint; 88 89 PathDiagnosticRange(const SourceRange &R, bool isP = false) 90 : SourceRange(R), isPoint(isP) {} 91 92 PathDiagnosticRange() : isPoint(false) {} 93}; 94 95typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> 96 LocationOrAnalysisDeclContext; 97 98class PathDiagnosticLocation { 99private: 100 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; 101 const Stmt *S; 102 const Decl *D; 103 const SourceManager *SM; 104 FullSourceLoc Loc; 105 PathDiagnosticRange Range; 106 107 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, 108 Kind kind) 109 : K(kind), S(0), D(0), SM(&sm), 110 Loc(genLocation(L)), Range(genRange()) { 111 assert(Loc.isValid()); 112 assert(Range.isValid()); 113 } 114 115 FullSourceLoc 116 genLocation(SourceLocation L = SourceLocation(), 117 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 118 119 PathDiagnosticRange 120 genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; 121 122public: 123 /// Create an invalid location. 124 PathDiagnosticLocation() 125 : K(SingleLocK), S(0), D(0), SM(0) {} 126 127 /// Create a location corresponding to the given statement. 128 PathDiagnosticLocation(const Stmt *s, 129 const SourceManager &sm, 130 LocationOrAnalysisDeclContext lac) 131 : K(StmtK), S(s), D(0), SM(&sm), 132 Loc(genLocation(SourceLocation(), lac)), 133 Range(genRange(lac)) { 134 assert(S); 135 assert(Loc.isValid()); 136 assert(Range.isValid()); 137 } 138 139 /// Create a location corresponding to the given declaration. 140 PathDiagnosticLocation(const Decl *d, const SourceManager &sm) 141 : K(DeclK), S(0), D(d), SM(&sm), 142 Loc(genLocation()), Range(genRange()) { 143 assert(D); 144 assert(Loc.isValid()); 145 assert(Range.isValid()); 146 } 147 148 /// Create a location corresponding to the given declaration. 149 static PathDiagnosticLocation create(const Decl *D, 150 const SourceManager &SM) { 151 return PathDiagnosticLocation(D, SM); 152 } 153 154 /// Create a location for the beginning of the declaration. 155 static PathDiagnosticLocation createBegin(const Decl *D, 156 const SourceManager &SM); 157 158 /// Create a location for the beginning of the statement. 159 static PathDiagnosticLocation createBegin(const Stmt *S, 160 const SourceManager &SM, 161 const LocationOrAnalysisDeclContext LAC); 162 163 /// Create the location for the operator of the binary expression. 164 /// Assumes the statement has a valid location. 165 static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, 166 const SourceManager &SM); 167 168 /// For member expressions, return the location of the '.' or '->'. 169 /// Assumes the statement has a valid location. 170 static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, 171 const SourceManager &SM); 172 173 /// Create a location for the beginning of the compound statement. 174 /// Assumes the statement has a valid location. 175 static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, 176 const SourceManager &SM); 177 178 /// Create a location for the end of the compound statement. 179 /// Assumes the statement has a valid location. 180 static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, 181 const SourceManager &SM); 182 183 /// Create a location for the beginning of the enclosing declaration body. 184 /// Defaults to the beginning of the first statement in the declaration body. 185 static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, 186 const SourceManager &SM); 187 188 /// Constructs a location for the end of the enclosing declaration body. 189 /// Defaults to the end of brace. 190 static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, 191 const SourceManager &SM); 192 193 /// Create a location corresponding to the given valid ExplodedNode. 194 static PathDiagnosticLocation create(const ProgramPoint& P, 195 const SourceManager &SMng); 196 197 /// Create a location corresponding to the next valid ExplodedNode as end 198 /// of path location. 199 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N, 200 const SourceManager &SM); 201 202 /// Convert the given location into a single kind location. 203 static PathDiagnosticLocation createSingleLocation( 204 const PathDiagnosticLocation &PDL); 205 206 bool operator==(const PathDiagnosticLocation &X) const { 207 return K == X.K && Loc == X.Loc && Range == X.Range; 208 } 209 210 bool operator!=(const PathDiagnosticLocation &X) const { 211 return !(*this == X); 212 } 213 214 bool isValid() const { 215 return SM != 0; 216 } 217 218 FullSourceLoc asLocation() const { 219 return Loc; 220 } 221 222 PathDiagnosticRange asRange() const { 223 return Range; 224 } 225 226 const Stmt *asStmt() const { assert(isValid()); return S; } 227 const Decl *asDecl() const { assert(isValid()); return D; } 228 229 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 230 231 void invalidate() { 232 *this = PathDiagnosticLocation(); 233 } 234 235 void flatten(); 236 237 const SourceManager& getManager() const { assert(isValid()); return *SM; } 238 239 void Profile(llvm::FoldingSetNodeID &ID) const; 240}; 241 242class PathDiagnosticLocationPair { 243private: 244 PathDiagnosticLocation Start, End; 245public: 246 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 247 const PathDiagnosticLocation &end) 248 : Start(start), End(end) {} 249 250 const PathDiagnosticLocation &getStart() const { return Start; } 251 const PathDiagnosticLocation &getEnd() const { return End; } 252 253 void flatten() { 254 Start.flatten(); 255 End.flatten(); 256 } 257 258 void Profile(llvm::FoldingSetNodeID &ID) const { 259 Start.Profile(ID); 260 End.Profile(ID); 261 } 262}; 263 264//===----------------------------------------------------------------------===// 265// Path "pieces" for path-sensitive diagnostics. 266//===----------------------------------------------------------------------===// 267 268class PathDiagnosticPiece : public RefCountedBaseVPTR { 269public: 270 enum Kind { ControlFlow, Event, Macro, Call }; 271 enum DisplayHint { Above, Below }; 272 273private: 274 const std::string str; 275 const Kind kind; 276 const DisplayHint Hint; 277 std::vector<SourceRange> ranges; 278 279 // Do not implement: 280 PathDiagnosticPiece(); 281 PathDiagnosticPiece(const PathDiagnosticPiece &P); 282 PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); 283 284protected: 285 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); 286 287 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 288 289public: 290 virtual ~PathDiagnosticPiece(); 291 292 const std::string& getString() const { return str; } 293 294 /// getDisplayHint - Return a hint indicating where the diagnostic should 295 /// be displayed by the PathDiagnosticConsumer. 296 DisplayHint getDisplayHint() const { return Hint; } 297 298 virtual PathDiagnosticLocation getLocation() const = 0; 299 virtual void flattenLocations() = 0; 300 301 Kind getKind() const { return kind; } 302 303 void addRange(SourceRange R) { 304 if (!R.isValid()) 305 return; 306 ranges.push_back(R); 307 } 308 309 void addRange(SourceLocation B, SourceLocation E) { 310 if (!B.isValid() || !E.isValid()) 311 return; 312 ranges.push_back(SourceRange(B,E)); 313 } 314 315 typedef const SourceRange* range_iterator; 316 317 range_iterator ranges_begin() const { 318 return ranges.empty() ? NULL : &ranges[0]; 319 } 320 321 range_iterator ranges_end() const { 322 return ranges_begin() + ranges.size(); 323 } 324 325 static inline bool classof(const PathDiagnosticPiece *P) { 326 return true; 327 } 328 329 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 330}; 331 332 333class PathPieces : 334 public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > { 335public: 336 ~PathPieces(); 337}; 338 339class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 340private: 341 PathDiagnosticLocation Pos; 342public: 343 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 344 StringRef s, 345 PathDiagnosticPiece::Kind k, 346 bool addPosRange = true) 347 : PathDiagnosticPiece(s, k), Pos(pos) { 348 assert(Pos.isValid() && Pos.asLocation().isValid() && 349 "PathDiagnosticSpotPiece's must have a valid location."); 350 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); 351 } 352 353 PathDiagnosticLocation getLocation() const { return Pos; } 354 virtual void flattenLocations() { Pos.flatten(); } 355 356 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 357}; 358 359class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 360 bool IsPrunable; 361public: 362 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 363 StringRef s, bool addPosRange = true) 364 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), 365 IsPrunable(false) {} 366 367 ~PathDiagnosticEventPiece(); 368 369 void setPrunable(bool isPrunable) { IsPrunable = isPrunable; } 370 bool isPrunable() const { return IsPrunable; } 371 372 static inline bool classof(const PathDiagnosticPiece *P) { 373 return P->getKind() == Event; 374 } 375}; 376 377class PathDiagnosticCallPiece : public PathDiagnosticPiece { 378 PathDiagnosticCallPiece(const Decl *callerD, 379 const PathDiagnosticLocation &callReturnPos) 380 : PathDiagnosticPiece(Call), Caller(callerD), 381 Callee(0), callReturn(callReturnPos) {} 382 383 PathDiagnosticCallPiece(PathPieces &oldPath) 384 : PathDiagnosticPiece(Call), Caller(0), Callee(0), path(oldPath) {} 385 386 const Decl *Caller; 387 const Decl *Callee; 388public: 389 PathDiagnosticLocation callEnter; 390 PathDiagnosticLocation callEnterWithin; 391 PathDiagnosticLocation callReturn; 392 PathPieces path; 393 394 virtual ~PathDiagnosticCallPiece(); 395 396 const Decl *getCaller() const { return Caller; } 397 398 const Decl *getCallee() const { return Callee; } 399 void setCallee(const CallEnter &CE, const SourceManager &SM); 400 401 virtual PathDiagnosticLocation getLocation() const { 402 return callEnter; 403 } 404 405 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; 406 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 407 getCallEnterWithinCallerEvent() const; 408 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; 409 410 virtual void flattenLocations() { 411 callEnter.flatten(); 412 callReturn.flatten(); 413 for (PathPieces::iterator I = path.begin(), 414 E = path.end(); I != E; ++I) (*I)->flattenLocations(); 415 } 416 417 static PathDiagnosticCallPiece *construct(const ExplodedNode *N, 418 const CallExit &CE, 419 const SourceManager &SM); 420 421 static PathDiagnosticCallPiece *construct(PathPieces &pieces); 422 423 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 424 425 static inline bool classof(const PathDiagnosticPiece *P) { 426 return P->getKind() == Call; 427 } 428}; 429 430class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 431 std::vector<PathDiagnosticLocationPair> LPairs; 432public: 433 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 434 const PathDiagnosticLocation &endPos, 435 StringRef s) 436 : PathDiagnosticPiece(s, ControlFlow) { 437 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 438 } 439 440 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 441 const PathDiagnosticLocation &endPos) 442 : PathDiagnosticPiece(ControlFlow) { 443 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 444 } 445 446 ~PathDiagnosticControlFlowPiece(); 447 448 PathDiagnosticLocation getStartLocation() const { 449 assert(!LPairs.empty() && 450 "PathDiagnosticControlFlowPiece needs at least one location."); 451 return LPairs[0].getStart(); 452 } 453 454 PathDiagnosticLocation getEndLocation() const { 455 assert(!LPairs.empty() && 456 "PathDiagnosticControlFlowPiece needs at least one location."); 457 return LPairs[0].getEnd(); 458 } 459 460 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 461 462 virtual PathDiagnosticLocation getLocation() const { 463 return getStartLocation(); 464 } 465 466 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; 467 iterator begin() { return LPairs.begin(); } 468 iterator end() { return LPairs.end(); } 469 470 virtual void flattenLocations() { 471 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); 472 } 473 474 typedef std::vector<PathDiagnosticLocationPair>::const_iterator 475 const_iterator; 476 const_iterator begin() const { return LPairs.begin(); } 477 const_iterator end() const { return LPairs.end(); } 478 479 static inline bool classof(const PathDiagnosticPiece *P) { 480 return P->getKind() == ControlFlow; 481 } 482 483 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 484}; 485 486class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 487public: 488 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 489 : PathDiagnosticSpotPiece(pos, "", Macro) {} 490 491 ~PathDiagnosticMacroPiece(); 492 493 PathPieces subPieces; 494 495 bool containsEvent() const; 496 497 virtual void flattenLocations() { 498 PathDiagnosticSpotPiece::flattenLocations(); 499 for (PathPieces::iterator I = subPieces.begin(), 500 E = subPieces.end(); I != E; ++I) (*I)->flattenLocations(); 501 } 502 503 static inline bool classof(const PathDiagnosticPiece *P) { 504 return P->getKind() == Macro; 505 } 506 507 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 508}; 509 510/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive 511/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, 512/// each which represent the pieces of the path. 513class PathDiagnostic : public llvm::FoldingSetNode { 514 std::string BugType; 515 std::string Desc; 516 std::string Category; 517 std::deque<std::string> OtherDesc; 518 PathPieces pathImpl; 519 llvm::SmallVector<PathPieces *, 3> pathStack; 520public: 521 const PathPieces &path; 522 523 /// Return the path currently used by builders for constructing the 524 /// PathDiagnostic. 525 PathPieces &getActivePath() { 526 if (pathStack.empty()) 527 return pathImpl; 528 return *pathStack.back(); 529 } 530 531 /// Return a mutable version of 'path'. 532 PathPieces &getMutablePieces() { 533 return pathImpl; 534 } 535 536 /// Return the unrolled size of the path. 537 unsigned full_size(); 538 539 void pushActivePath(PathPieces *p) { pathStack.push_back(p); } 540 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } 541 542 PathDiagnostic(); 543 PathDiagnostic(StringRef bugtype, StringRef desc, 544 StringRef category); 545 546 ~PathDiagnostic(); 547 548 StringRef getDescription() const { return Desc; } 549 StringRef getBugType() const { return BugType; } 550 StringRef getCategory() const { return Category; } 551 552 553 typedef std::deque<std::string>::const_iterator meta_iterator; 554 meta_iterator meta_begin() const { return OtherDesc.begin(); } 555 meta_iterator meta_end() const { return OtherDesc.end(); } 556 void addMeta(StringRef s) { OtherDesc.push_back(s); } 557 558 PathDiagnosticLocation getLocation() const; 559 560 void flattenLocations() { 561 for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 562 I != E; ++I) (*I)->flattenLocations(); 563 } 564 565 void Profile(llvm::FoldingSetNodeID &ID) const; 566 567 void FullProfile(llvm::FoldingSetNodeID &ID) const; 568}; 569 570} // end GR namespace 571 572} //end clang namespace 573 574#endif 575