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