clang API Documentation
00001 //===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the PathDiagnostic-related interfaces. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H 00015 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H 00016 00017 #include "clang/Analysis/ProgramPoint.h" 00018 #include "clang/Basic/SourceLocation.h" 00019 #include "llvm/ADT/FoldingSet.h" 00020 #include "llvm/ADT/IntrusiveRefCntPtr.h" 00021 #include "llvm/ADT/Optional.h" 00022 #include "llvm/ADT/PointerUnion.h" 00023 #include <deque> 00024 #include <iterator> 00025 #include <list> 00026 #include <string> 00027 #include <vector> 00028 00029 namespace clang { 00030 class ConditionalOperator; 00031 class AnalysisDeclContext; 00032 class BinaryOperator; 00033 class CompoundStmt; 00034 class Decl; 00035 class LocationContext; 00036 class MemberExpr; 00037 class ParentMap; 00038 class ProgramPoint; 00039 class SourceManager; 00040 class Stmt; 00041 class CallExpr; 00042 00043 namespace ento { 00044 00045 class ExplodedNode; 00046 class SymExpr; 00047 typedef const SymExpr* SymbolRef; 00048 00049 //===----------------------------------------------------------------------===// 00050 // High-level interface for handlers of path-sensitive diagnostics. 00051 //===----------------------------------------------------------------------===// 00052 00053 class PathDiagnostic; 00054 00055 class PathDiagnosticConsumer { 00056 public: 00057 class PDFileEntry : public llvm::FoldingSetNode { 00058 public: 00059 PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {} 00060 00061 typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles; 00062 00063 /// \brief A vector of <consumer,file> pairs. 00064 ConsumerFiles files; 00065 00066 /// \brief A precomputed hash tag used for uniquing PDFileEntry objects. 00067 const llvm::FoldingSetNodeID NodeID; 00068 00069 /// \brief Used for profiling in the FoldingSet. 00070 void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; } 00071 }; 00072 00073 struct FilesMade : public llvm::FoldingSet<PDFileEntry> { 00074 llvm::BumpPtrAllocator Alloc; 00075 00076 ~FilesMade(); 00077 00078 void addDiagnostic(const PathDiagnostic &PD, 00079 StringRef ConsumerName, 00080 StringRef fileName); 00081 00082 PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD); 00083 }; 00084 00085 private: 00086 virtual void anchor(); 00087 public: 00088 PathDiagnosticConsumer() : flushed(false) {} 00089 virtual ~PathDiagnosticConsumer(); 00090 00091 void FlushDiagnostics(FilesMade *FilesMade); 00092 00093 virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 00094 FilesMade *filesMade) = 0; 00095 00096 virtual StringRef getName() const = 0; 00097 00098 void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D); 00099 00100 enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; 00101 virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } 00102 virtual bool supportsLogicalOpControlFlow() const { return false; } 00103 00104 /// Return true if the PathDiagnosticConsumer supports individual 00105 /// PathDiagnostics that span multiple files. 00106 virtual bool supportsCrossFileDiagnostics() const { return false; } 00107 00108 protected: 00109 bool flushed; 00110 llvm::FoldingSet<PathDiagnostic> Diags; 00111 }; 00112 00113 //===----------------------------------------------------------------------===// 00114 // Path-sensitive diagnostics. 00115 //===----------------------------------------------------------------------===// 00116 00117 class PathDiagnosticRange : public SourceRange { 00118 public: 00119 bool isPoint; 00120 00121 PathDiagnosticRange(const SourceRange &R, bool isP = false) 00122 : SourceRange(R), isPoint(isP) {} 00123 00124 PathDiagnosticRange() : isPoint(false) {} 00125 }; 00126 00127 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> 00128 LocationOrAnalysisDeclContext; 00129 00130 class PathDiagnosticLocation { 00131 private: 00132 enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; 00133 const Stmt *S; 00134 const Decl *D; 00135 const SourceManager *SM; 00136 FullSourceLoc Loc; 00137 PathDiagnosticRange Range; 00138 00139 PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, 00140 Kind kind) 00141 : K(kind), S(nullptr), D(nullptr), SM(&sm), 00142 Loc(genLocation(L)), Range(genRange()) { 00143 } 00144 00145 FullSourceLoc genLocation( 00146 SourceLocation L = SourceLocation(), 00147 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const; 00148 00149 PathDiagnosticRange genRange( 00150 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const; 00151 00152 public: 00153 /// Create an invalid location. 00154 PathDiagnosticLocation() 00155 : K(SingleLocK), S(nullptr), D(nullptr), SM(nullptr) {} 00156 00157 /// Create a location corresponding to the given statement. 00158 PathDiagnosticLocation(const Stmt *s, 00159 const SourceManager &sm, 00160 LocationOrAnalysisDeclContext lac) 00161 : K(s->getLocStart().isValid() ? StmtK : SingleLocK), 00162 S(K == StmtK ? s : nullptr), 00163 D(nullptr), SM(&sm), 00164 Loc(genLocation(SourceLocation(), lac)), 00165 Range(genRange(lac)) { 00166 assert(K == SingleLocK || S); 00167 assert(K == SingleLocK || Loc.isValid()); 00168 assert(K == SingleLocK || Range.isValid()); 00169 } 00170 00171 /// Create a location corresponding to the given declaration. 00172 PathDiagnosticLocation(const Decl *d, const SourceManager &sm) 00173 : K(DeclK), S(nullptr), D(d), SM(&sm), 00174 Loc(genLocation()), Range(genRange()) { 00175 assert(D); 00176 assert(Loc.isValid()); 00177 assert(Range.isValid()); 00178 } 00179 00180 /// Create a location at an explicit offset in the source. 00181 /// 00182 /// This should only be used if there are no more appropriate constructors. 00183 PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm) 00184 : K(SingleLocK), S(nullptr), D(nullptr), SM(&sm), Loc(loc, sm), 00185 Range(genRange()) { 00186 assert(Loc.isValid()); 00187 assert(Range.isValid()); 00188 } 00189 00190 /// Create a location corresponding to the given declaration. 00191 static PathDiagnosticLocation create(const Decl *D, 00192 const SourceManager &SM) { 00193 return PathDiagnosticLocation(D, SM); 00194 } 00195 00196 /// Create a location for the beginning of the declaration. 00197 static PathDiagnosticLocation createBegin(const Decl *D, 00198 const SourceManager &SM); 00199 00200 /// Create a location for the beginning of the statement. 00201 static PathDiagnosticLocation createBegin(const Stmt *S, 00202 const SourceManager &SM, 00203 const LocationOrAnalysisDeclContext LAC); 00204 00205 /// Create a location for the end of the statement. 00206 /// 00207 /// If the statement is a CompoundStatement, the location will point to the 00208 /// closing brace instead of following it. 00209 static PathDiagnosticLocation createEnd(const Stmt *S, 00210 const SourceManager &SM, 00211 const LocationOrAnalysisDeclContext LAC); 00212 00213 /// Create the location for the operator of the binary expression. 00214 /// Assumes the statement has a valid location. 00215 static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, 00216 const SourceManager &SM); 00217 static PathDiagnosticLocation createConditionalColonLoc( 00218 const ConditionalOperator *CO, 00219 const SourceManager &SM); 00220 00221 /// For member expressions, return the location of the '.' or '->'. 00222 /// Assumes the statement has a valid location. 00223 static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, 00224 const SourceManager &SM); 00225 00226 /// Create a location for the beginning of the compound statement. 00227 /// Assumes the statement has a valid location. 00228 static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, 00229 const SourceManager &SM); 00230 00231 /// Create a location for the end of the compound statement. 00232 /// Assumes the statement has a valid location. 00233 static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, 00234 const SourceManager &SM); 00235 00236 /// Create a location for the beginning of the enclosing declaration body. 00237 /// Defaults to the beginning of the first statement in the declaration body. 00238 static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, 00239 const SourceManager &SM); 00240 00241 /// Constructs a location for the end of the enclosing declaration body. 00242 /// Defaults to the end of brace. 00243 static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, 00244 const SourceManager &SM); 00245 00246 /// Create a location corresponding to the given valid ExplodedNode. 00247 static PathDiagnosticLocation create(const ProgramPoint& P, 00248 const SourceManager &SMng); 00249 00250 /// Create a location corresponding to the next valid ExplodedNode as end 00251 /// of path location. 00252 static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N, 00253 const SourceManager &SM); 00254 00255 /// Convert the given location into a single kind location. 00256 static PathDiagnosticLocation createSingleLocation( 00257 const PathDiagnosticLocation &PDL); 00258 00259 bool operator==(const PathDiagnosticLocation &X) const { 00260 return K == X.K && Loc == X.Loc && Range == X.Range; 00261 } 00262 00263 bool operator!=(const PathDiagnosticLocation &X) const { 00264 return !(*this == X); 00265 } 00266 00267 bool isValid() const { 00268 return SM != nullptr; 00269 } 00270 00271 FullSourceLoc asLocation() const { 00272 return Loc; 00273 } 00274 00275 PathDiagnosticRange asRange() const { 00276 return Range; 00277 } 00278 00279 const Stmt *asStmt() const { assert(isValid()); return S; } 00280 const Decl *asDecl() const { assert(isValid()); return D; } 00281 00282 bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } 00283 00284 void invalidate() { 00285 *this = PathDiagnosticLocation(); 00286 } 00287 00288 void flatten(); 00289 00290 const SourceManager& getManager() const { assert(isValid()); return *SM; } 00291 00292 void Profile(llvm::FoldingSetNodeID &ID) const; 00293 00294 void dump() const; 00295 00296 /// \brief Given an exploded node, retrieve the statement that should be used 00297 /// for the diagnostic location. 00298 static const Stmt *getStmt(const ExplodedNode *N); 00299 00300 /// \brief Retrieve the statement corresponding to the successor node. 00301 static const Stmt *getNextStmt(const ExplodedNode *N); 00302 }; 00303 00304 class PathDiagnosticLocationPair { 00305 private: 00306 PathDiagnosticLocation Start, End; 00307 public: 00308 PathDiagnosticLocationPair(const PathDiagnosticLocation &start, 00309 const PathDiagnosticLocation &end) 00310 : Start(start), End(end) {} 00311 00312 const PathDiagnosticLocation &getStart() const { return Start; } 00313 const PathDiagnosticLocation &getEnd() const { return End; } 00314 00315 void setStart(const PathDiagnosticLocation &L) { Start = L; } 00316 void setEnd(const PathDiagnosticLocation &L) { End = L; } 00317 00318 void flatten() { 00319 Start.flatten(); 00320 End.flatten(); 00321 } 00322 00323 void Profile(llvm::FoldingSetNodeID &ID) const { 00324 Start.Profile(ID); 00325 End.Profile(ID); 00326 } 00327 }; 00328 00329 //===----------------------------------------------------------------------===// 00330 // Path "pieces" for path-sensitive diagnostics. 00331 //===----------------------------------------------------------------------===// 00332 00333 class PathDiagnosticPiece : public RefCountedBaseVPTR { 00334 public: 00335 enum Kind { ControlFlow, Event, Macro, Call }; 00336 enum DisplayHint { Above, Below }; 00337 00338 private: 00339 const std::string str; 00340 const Kind kind; 00341 const DisplayHint Hint; 00342 00343 /// \brief In the containing bug report, this piece is the last piece from 00344 /// the main source file. 00345 bool LastInMainSourceFile; 00346 00347 /// A constant string that can be used to tag the PathDiagnosticPiece, 00348 /// typically with the identification of the creator. The actual pointer 00349 /// value is meant to be an identifier; the string itself is useful for 00350 /// debugging. 00351 StringRef Tag; 00352 00353 std::vector<SourceRange> ranges; 00354 00355 PathDiagnosticPiece() LLVM_DELETED_FUNCTION; 00356 PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION; 00357 void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION; 00358 00359 protected: 00360 PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); 00361 00362 PathDiagnosticPiece(Kind k, DisplayHint hint = Below); 00363 00364 public: 00365 virtual ~PathDiagnosticPiece(); 00366 00367 StringRef getString() const { return str; } 00368 00369 /// Tag this PathDiagnosticPiece with the given C-string. 00370 void setTag(const char *tag) { Tag = tag; } 00371 00372 /// Return the opaque tag (if any) on the PathDiagnosticPiece. 00373 const void *getTag() const { return Tag.data(); } 00374 00375 /// Return the string representation of the tag. This is useful 00376 /// for debugging. 00377 StringRef getTagStr() const { return Tag; } 00378 00379 /// getDisplayHint - Return a hint indicating where the diagnostic should 00380 /// be displayed by the PathDiagnosticConsumer. 00381 DisplayHint getDisplayHint() const { return Hint; } 00382 00383 virtual PathDiagnosticLocation getLocation() const = 0; 00384 virtual void flattenLocations() = 0; 00385 00386 Kind getKind() const { return kind; } 00387 00388 void addRange(SourceRange R) { 00389 if (!R.isValid()) 00390 return; 00391 ranges.push_back(R); 00392 } 00393 00394 void addRange(SourceLocation B, SourceLocation E) { 00395 if (!B.isValid() || !E.isValid()) 00396 return; 00397 ranges.push_back(SourceRange(B,E)); 00398 } 00399 00400 /// Return the SourceRanges associated with this PathDiagnosticPiece. 00401 ArrayRef<SourceRange> getRanges() const { return ranges; } 00402 00403 virtual void Profile(llvm::FoldingSetNodeID &ID) const; 00404 00405 void setAsLastInMainSourceFile() { 00406 LastInMainSourceFile = true; 00407 } 00408 00409 bool isLastInMainSourceFile() const { 00410 return LastInMainSourceFile; 00411 } 00412 00413 virtual void dump() const = 0; 00414 }; 00415 00416 00417 class PathPieces : public std::list<IntrusiveRefCntPtr<PathDiagnosticPiece> > { 00418 void flattenTo(PathPieces &Primary, PathPieces &Current, 00419 bool ShouldFlattenMacros) const; 00420 public: 00421 ~PathPieces(); 00422 00423 PathPieces flatten(bool ShouldFlattenMacros) const { 00424 PathPieces Result; 00425 flattenTo(Result, Result, ShouldFlattenMacros); 00426 return Result; 00427 } 00428 00429 void dump() const; 00430 }; 00431 00432 class PathDiagnosticSpotPiece : public PathDiagnosticPiece { 00433 private: 00434 PathDiagnosticLocation Pos; 00435 public: 00436 PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, 00437 StringRef s, 00438 PathDiagnosticPiece::Kind k, 00439 bool addPosRange = true) 00440 : PathDiagnosticPiece(s, k), Pos(pos) { 00441 assert(Pos.isValid() && Pos.asLocation().isValid() && 00442 "PathDiagnosticSpotPiece's must have a valid location."); 00443 if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); 00444 } 00445 00446 PathDiagnosticLocation getLocation() const override { return Pos; } 00447 void flattenLocations() override { Pos.flatten(); } 00448 00449 void Profile(llvm::FoldingSetNodeID &ID) const override; 00450 00451 static bool classof(const PathDiagnosticPiece *P) { 00452 return P->getKind() == Event || P->getKind() == Macro; 00453 } 00454 }; 00455 00456 /// \brief Interface for classes constructing Stack hints. 00457 /// 00458 /// If a PathDiagnosticEvent occurs in a different frame than the final 00459 /// diagnostic the hints can be used to summarize the effect of the call. 00460 class StackHintGenerator { 00461 public: 00462 virtual ~StackHintGenerator() = 0; 00463 00464 /// \brief Construct the Diagnostic message for the given ExplodedNode. 00465 virtual std::string getMessage(const ExplodedNode *N) = 0; 00466 }; 00467 00468 /// \brief Constructs a Stack hint for the given symbol. 00469 /// 00470 /// The class knows how to construct the stack hint message based on 00471 /// traversing the CallExpr associated with the call and checking if the given 00472 /// symbol is returned or is one of the arguments. 00473 /// The hint can be customized by redefining 'getMessageForX()' methods. 00474 class StackHintGeneratorForSymbol : public StackHintGenerator { 00475 private: 00476 SymbolRef Sym; 00477 std::string Msg; 00478 00479 public: 00480 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} 00481 virtual ~StackHintGeneratorForSymbol() {} 00482 00483 /// \brief Search the call expression for the symbol Sym and dispatch the 00484 /// 'getMessageForX()' methods to construct a specific message. 00485 std::string getMessage(const ExplodedNode *N) override; 00486 00487 /// Produces the message of the following form: 00488 /// 'Msg via Nth parameter' 00489 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); 00490 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 00491 return Msg; 00492 } 00493 virtual std::string getMessageForSymbolNotFound() { 00494 return Msg; 00495 } 00496 }; 00497 00498 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { 00499 Optional<bool> IsPrunable; 00500 00501 /// If the event occurs in a different frame than the final diagnostic, 00502 /// supply a message that will be used to construct an extra hint on the 00503 /// returns from all the calls on the stack from this event to the final 00504 /// diagnostic. 00505 std::unique_ptr<StackHintGenerator> CallStackHint; 00506 00507 public: 00508 PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, 00509 StringRef s, bool addPosRange = true, 00510 StackHintGenerator *stackHint = nullptr) 00511 : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), 00512 CallStackHint(stackHint) {} 00513 00514 ~PathDiagnosticEventPiece(); 00515 00516 /// Mark the diagnostic piece as being potentially prunable. This 00517 /// flag may have been previously set, at which point it will not 00518 /// be reset unless one specifies to do so. 00519 void setPrunable(bool isPrunable, bool override = false) { 00520 if (IsPrunable.hasValue() && !override) 00521 return; 00522 IsPrunable = isPrunable; 00523 } 00524 00525 /// Return true if the diagnostic piece is prunable. 00526 bool isPrunable() const { 00527 return IsPrunable.hasValue() ? IsPrunable.getValue() : false; 00528 } 00529 00530 bool hasCallStackHint() { return (bool)CallStackHint; } 00531 00532 /// Produce the hint for the given node. The node contains 00533 /// information about the call for which the diagnostic can be generated. 00534 std::string getCallStackMessage(const ExplodedNode *N) { 00535 if (CallStackHint) 00536 return CallStackHint->getMessage(N); 00537 return ""; 00538 } 00539 00540 void dump() const override; 00541 00542 static inline bool classof(const PathDiagnosticPiece *P) { 00543 return P->getKind() == Event; 00544 } 00545 }; 00546 00547 class PathDiagnosticCallPiece : public PathDiagnosticPiece { 00548 PathDiagnosticCallPiece(const Decl *callerD, 00549 const PathDiagnosticLocation &callReturnPos) 00550 : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), 00551 NoExit(false), callReturn(callReturnPos) {} 00552 00553 PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) 00554 : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), 00555 NoExit(true), path(oldPath) {} 00556 00557 const Decl *Caller; 00558 const Decl *Callee; 00559 00560 // Flag signifying that this diagnostic has only call enter and no matching 00561 // call exit. 00562 bool NoExit; 00563 00564 // The custom string, which should appear after the call Return Diagnostic. 00565 // TODO: Should we allow multiple diagnostics? 00566 std::string CallStackMessage; 00567 00568 public: 00569 PathDiagnosticLocation callEnter; 00570 PathDiagnosticLocation callEnterWithin; 00571 PathDiagnosticLocation callReturn; 00572 PathPieces path; 00573 00574 virtual ~PathDiagnosticCallPiece(); 00575 00576 const Decl *getCaller() const { return Caller; } 00577 00578 const Decl *getCallee() const { return Callee; } 00579 void setCallee(const CallEnter &CE, const SourceManager &SM); 00580 00581 bool hasCallStackMessage() { return !CallStackMessage.empty(); } 00582 void setCallStackMessage(StringRef st) { 00583 CallStackMessage = st; 00584 } 00585 00586 PathDiagnosticLocation getLocation() const override { 00587 return callEnter; 00588 } 00589 00590 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; 00591 IntrusiveRefCntPtr<PathDiagnosticEventPiece> 00592 getCallEnterWithinCallerEvent() const; 00593 IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; 00594 00595 void flattenLocations() override { 00596 callEnter.flatten(); 00597 callReturn.flatten(); 00598 for (PathPieces::iterator I = path.begin(), 00599 E = path.end(); I != E; ++I) (*I)->flattenLocations(); 00600 } 00601 00602 static PathDiagnosticCallPiece *construct(const ExplodedNode *N, 00603 const CallExitEnd &CE, 00604 const SourceManager &SM); 00605 00606 static PathDiagnosticCallPiece *construct(PathPieces &pieces, 00607 const Decl *caller); 00608 00609 void dump() const override; 00610 00611 void Profile(llvm::FoldingSetNodeID &ID) const override; 00612 00613 static inline bool classof(const PathDiagnosticPiece *P) { 00614 return P->getKind() == Call; 00615 } 00616 }; 00617 00618 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { 00619 std::vector<PathDiagnosticLocationPair> LPairs; 00620 public: 00621 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 00622 const PathDiagnosticLocation &endPos, 00623 StringRef s) 00624 : PathDiagnosticPiece(s, ControlFlow) { 00625 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 00626 } 00627 00628 PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, 00629 const PathDiagnosticLocation &endPos) 00630 : PathDiagnosticPiece(ControlFlow) { 00631 LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); 00632 } 00633 00634 ~PathDiagnosticControlFlowPiece(); 00635 00636 PathDiagnosticLocation getStartLocation() const { 00637 assert(!LPairs.empty() && 00638 "PathDiagnosticControlFlowPiece needs at least one location."); 00639 return LPairs[0].getStart(); 00640 } 00641 00642 PathDiagnosticLocation getEndLocation() const { 00643 assert(!LPairs.empty() && 00644 "PathDiagnosticControlFlowPiece needs at least one location."); 00645 return LPairs[0].getEnd(); 00646 } 00647 00648 void setStartLocation(const PathDiagnosticLocation &L) { 00649 LPairs[0].setStart(L); 00650 } 00651 00652 void setEndLocation(const PathDiagnosticLocation &L) { 00653 LPairs[0].setEnd(L); 00654 } 00655 00656 void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } 00657 00658 PathDiagnosticLocation getLocation() const override { 00659 return getStartLocation(); 00660 } 00661 00662 typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; 00663 iterator begin() { return LPairs.begin(); } 00664 iterator end() { return LPairs.end(); } 00665 00666 void flattenLocations() override { 00667 for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); 00668 } 00669 00670 typedef std::vector<PathDiagnosticLocationPair>::const_iterator 00671 const_iterator; 00672 const_iterator begin() const { return LPairs.begin(); } 00673 const_iterator end() const { return LPairs.end(); } 00674 00675 static inline bool classof(const PathDiagnosticPiece *P) { 00676 return P->getKind() == ControlFlow; 00677 } 00678 00679 void dump() const override; 00680 00681 void Profile(llvm::FoldingSetNodeID &ID) const override; 00682 }; 00683 00684 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { 00685 public: 00686 PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) 00687 : PathDiagnosticSpotPiece(pos, "", Macro) {} 00688 00689 ~PathDiagnosticMacroPiece(); 00690 00691 PathPieces subPieces; 00692 00693 bool containsEvent() const; 00694 00695 void flattenLocations() override { 00696 PathDiagnosticSpotPiece::flattenLocations(); 00697 for (PathPieces::iterator I = subPieces.begin(), 00698 E = subPieces.end(); I != E; ++I) (*I)->flattenLocations(); 00699 } 00700 00701 static inline bool classof(const PathDiagnosticPiece *P) { 00702 return P->getKind() == Macro; 00703 } 00704 00705 void dump() const override; 00706 00707 void Profile(llvm::FoldingSetNodeID &ID) const override; 00708 }; 00709 00710 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive 00711 /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, 00712 /// each which represent the pieces of the path. 00713 class PathDiagnostic : public llvm::FoldingSetNode { 00714 std::string CheckName; 00715 const Decl *DeclWithIssue; 00716 std::string BugType; 00717 std::string VerboseDesc; 00718 std::string ShortDesc; 00719 std::string Category; 00720 std::deque<std::string> OtherDesc; 00721 00722 /// \brief Loc The location of the path diagnostic report. 00723 PathDiagnosticLocation Loc; 00724 00725 PathPieces pathImpl; 00726 SmallVector<PathPieces *, 3> pathStack; 00727 00728 /// \brief Important bug uniqueing location. 00729 /// The location info is useful to differentiate between bugs. 00730 PathDiagnosticLocation UniqueingLoc; 00731 const Decl *UniqueingDecl; 00732 00733 PathDiagnostic() LLVM_DELETED_FUNCTION; 00734 public: 00735 PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue, 00736 StringRef bugtype, StringRef verboseDesc, StringRef shortDesc, 00737 StringRef category, PathDiagnosticLocation LocationToUnique, 00738 const Decl *DeclToUnique); 00739 00740 ~PathDiagnostic(); 00741 00742 const PathPieces &path; 00743 00744 /// Return the path currently used by builders for constructing the 00745 /// PathDiagnostic. 00746 PathPieces &getActivePath() { 00747 if (pathStack.empty()) 00748 return pathImpl; 00749 return *pathStack.back(); 00750 } 00751 00752 /// Return a mutable version of 'path'. 00753 PathPieces &getMutablePieces() { 00754 return pathImpl; 00755 } 00756 00757 /// Return the unrolled size of the path. 00758 unsigned full_size(); 00759 00760 void pushActivePath(PathPieces *p) { pathStack.push_back(p); } 00761 void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } 00762 00763 bool isWithinCall() const { return !pathStack.empty(); } 00764 00765 void setEndOfPath(std::unique_ptr<PathDiagnosticPiece> EndPiece) { 00766 assert(!Loc.isValid() && "End location already set!"); 00767 Loc = EndPiece->getLocation(); 00768 assert(Loc.isValid() && "Invalid location for end-of-path piece"); 00769 getActivePath().push_back(EndPiece.release()); 00770 } 00771 00772 void appendToDesc(StringRef S) { 00773 if (!ShortDesc.empty()) 00774 ShortDesc.append(S); 00775 VerboseDesc.append(S); 00776 } 00777 00778 void resetPath() { 00779 pathStack.clear(); 00780 pathImpl.clear(); 00781 Loc = PathDiagnosticLocation(); 00782 } 00783 00784 /// \brief If the last piece of the report point to the header file, resets 00785 /// the location of the report to be the last location in the main source 00786 /// file. 00787 void resetDiagnosticLocationToMainFile(); 00788 00789 StringRef getVerboseDescription() const { return VerboseDesc; } 00790 StringRef getShortDescription() const { 00791 return ShortDesc.empty() ? VerboseDesc : ShortDesc; 00792 } 00793 StringRef getCheckName() const { return CheckName; } 00794 StringRef getBugType() const { return BugType; } 00795 StringRef getCategory() const { return Category; } 00796 00797 /// Return the semantic context where an issue occurred. If the 00798 /// issue occurs along a path, this represents the "central" area 00799 /// where the bug manifests. 00800 const Decl *getDeclWithIssue() const { return DeclWithIssue; } 00801 00802 typedef std::deque<std::string>::const_iterator meta_iterator; 00803 meta_iterator meta_begin() const { return OtherDesc.begin(); } 00804 meta_iterator meta_end() const { return OtherDesc.end(); } 00805 void addMeta(StringRef s) { OtherDesc.push_back(s); } 00806 00807 PathDiagnosticLocation getLocation() const { 00808 assert(Loc.isValid() && "No report location set yet!"); 00809 return Loc; 00810 } 00811 00812 /// \brief Get the location on which the report should be uniqued. 00813 PathDiagnosticLocation getUniqueingLoc() const { 00814 return UniqueingLoc; 00815 } 00816 00817 /// \brief Get the declaration containing the uniqueing location. 00818 const Decl *getUniqueingDecl() const { 00819 return UniqueingDecl; 00820 } 00821 00822 void flattenLocations() { 00823 Loc.flatten(); 00824 for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 00825 I != E; ++I) (*I)->flattenLocations(); 00826 } 00827 00828 /// Profiles the diagnostic, independent of the path it references. 00829 /// 00830 /// This can be used to merge diagnostics that refer to the same issue 00831 /// along different paths. 00832 void Profile(llvm::FoldingSetNodeID &ID) const; 00833 00834 /// Profiles the diagnostic, including its path. 00835 /// 00836 /// Two diagnostics with the same issue along different paths will generate 00837 /// different profiles. 00838 void FullProfile(llvm::FoldingSetNodeID &ID) const; 00839 }; 00840 00841 } // end GR namespace 00842 00843 } //end clang namespace 00844 00845 #endif