24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/Support/raw_ostream.h"
28 using namespace clang;
34 if (isa<PathDiagnosticEventPiece>(*I))
37 if (MP->containsEvent())
44 for (StringRef::size_type i = s.size(); i != 0; --i)
46 return s.substr(0, i);
50 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
53 LastInMainSourceFile(
false) {}
56 :
kind(k), Hint(hint), LastInMainSourceFile(
false) {}
68 bool ShouldFlattenMacros)
const {
69 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
78 Current.push_back(CallEnter);
79 Call->
path.flattenTo(Primary, Primary, ShouldFlattenMacros);
83 Current.push_back(callExit);
88 if (ShouldFlattenMacros) {
89 Macro->
subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
91 Current.push_back(Piece);
93 Macro->
subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
101 Current.push_back(Piece);
110 PathDiagnostic::PathDiagnostic(StringRef
CheckName,
const Decl *declWithIssue,
111 StringRef bugtype, StringRef verboseDesc,
112 StringRef shortDesc, StringRef category,
114 const Decl *DeclToUnique)
115 : CheckName(CheckName),
116 DeclWithIssue(declWithIssue),
121 UniqueingLoc(LocationToUnique),
122 UniqueingDecl(DeclToUnique),
135 "The call piece should be in the main file.");
148 dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
170 CP->setAsLastInMainSourceFile();
176 llvm::raw_svector_ostream os(buf);
177 os <<
" (within a call to '" << ND->
getDeclName() <<
"')";
182 DeclWithIssue = CP->getCaller();
183 Loc = CP->getLocation();
190 void PathDiagnosticConsumer::anchor() { }
194 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
195 Diags.begin(), et =
Diags.end() ; it != et ; ++it) {
201 std::unique_ptr<PathDiagnostic> D) {
202 if (!D || D->path.empty())
208 D->flattenLocations();
215 const SourceManager &SMgr = D->path.front()->getLocation().getManager();
217 WorkList.push_back(&D->path);
219 while (!WorkList.empty()) {
220 const PathPieces &path = *WorkList.pop_back_val();
222 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
235 E = Ranges.end(); I != E; ++I) {
245 dyn_cast<PathDiagnosticCallPiece>(piece)) {
246 WorkList.push_back(&call->path);
249 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
250 WorkList.push_back(¯o->subPieces);
260 llvm::FoldingSetNodeID profile;
262 void *InsertPos =
nullptr;
269 const unsigned orig_size = orig->full_size();
270 const unsigned new_size = D->full_size();
271 if (orig_size <= new_size)
274 assert(orig != D.get());
275 Diags.RemoveNode(orig);
279 Diags.InsertNode(D.release());
310 if (X_CEWL != Y_CEWL)
337 for (
unsigned i = 0, n = X.
getRanges().size(); i < n; ++i) {
350 cast<PathDiagnosticControlFlowPiece>(Y));
355 cast<PathDiagnosticMacroPiece>(Y));
357 return compareCall(cast<PathDiagnosticCallPiece>(X),
358 cast<PathDiagnosticCallPiece>(Y));
360 llvm_unreachable(
"all cases handled");
364 if (X.size() != Y.size())
365 return X.size() < Y.size();
367 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
368 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
370 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
408 if (XE - XI != YE - YI)
409 return (XE - XI) < (YE - YI);
410 for ( ; XI != XE ; ++XI, ++YI) {
412 return (*XI) < (*YI);
415 assert(b.hasValue());
426 std::vector<const PathDiagnostic *> BatchDiags;
427 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
Diags.begin(),
428 et =
Diags.end(); it != et; ++it) {
430 BatchDiags.push_back(D);
437 assert(*X != *Y &&
"PathDiagnostics not uniqued!");
440 assert(
compare(**Y, **X) &&
"Not a total order!");
443 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
448 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
449 et = BatchDiags.end(); it != et; ++it) {
460 Entry.~PDFileEntry();
464 StringRef ConsumerName,
465 StringRef FileName) {
466 llvm::FoldingSetNodeID NodeID;
469 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
473 Set.InsertNode(Entry, InsertPos);
477 char *FileName_cstr = (
char*) Alloc.Allocate(FileName.size(), 1);
478 memcpy(FileName_cstr, FileName.data(), FileName.size());
480 Entry->
files.push_back(std::make_pair(ConsumerName,
481 StringRef(FileName_cstr,
487 llvm::FoldingSetNodeID NodeID;
490 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
493 return &Entry->
files;
502 bool UseEnd =
false) {
504 assert(!LAC.isNull() &&
"A valid LocationContext or AnalysisDeclContext should "
505 "be passed to PathDiagnosticLocation upon creation.");
519 const Stmt *Parent =
S;
521 Parent = PM.getParent(Parent);
530 L = Body->getLocStart();
536 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
571 if (
const Stmt *CallerBody = CallerInfo->
getBody())
577 llvm_unreachable(
"not yet implemented!");
580 llvm_unreachable(
"Unknown CFGElement kind");
604 return createEndBrace(CS, SM);
649 if (!CS->body_empty()) {
668 const Stmt*
S =
nullptr;
670 const CFGBlock *BSrc = BE->getSrc();
683 CE->getLocationContext(),
687 CEE->getLocationContext(),
690 llvm_unreachable(
"Unexpected ProgramPoint");
699 return SP->getStmt();
701 return BE->getSrc()->getTerminator();
703 return CE->getCallExpr();
705 return CEE->getCalleeContext()->getCallSite();
707 return PIPP->getInitializer()->getInit();
714 if (
const Stmt *
S = getStmt(N)) {
717 switch (
S->getStmtClass()) {
718 case Stmt::ChooseExprClass:
719 case Stmt::BinaryConditionalOperatorClass:
720 case Stmt::ConditionalOperatorClass:
722 case Stmt::BinaryOperatorClass: {
742 assert(N &&
"Cannot create a location with a null node.");
743 const Stmt *
S = getStmt(N);
757 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(S))
767 if (S->getLocStart().isValid())
796 const_cast<SourceManager&>(*
SM));
818 const Stmt *
S = asStmt();
819 switch (S->getStmtClass()) {
822 case Stmt::DeclStmtClass: {
833 case Stmt::IfStmtClass:
834 case Stmt::WhileStmtClass:
835 case Stmt::DoStmtClass:
836 case Stmt::ForStmtClass:
837 case Stmt::ChooseExprClass:
838 case Stmt::IndirectGotoStmtClass:
839 case Stmt::SwitchStmtClass:
840 case Stmt::BinaryConditionalOperatorClass:
841 case Stmt::ConditionalOperatorClass:
842 case Stmt::ObjCForCollectionStmtClass: {
854 return MD->getSourceRange();
855 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
856 if (
Stmt *Body = FD->getBody())
857 return Body->getSourceRange();
874 else if (K == DeclK) {
898 const Decl *caller) {
915 StringRef Prefix = StringRef()) {
918 Out << Prefix <<
'\'' << *D <<
'\'';
922 bool ExtendedDescription,
923 StringRef Prefix = StringRef()) {
927 if (isa<BlockDecl>(D)) {
928 if (ExtendedDescription)
929 Out << Prefix <<
"anonymous block";
930 return ExtendedDescription;
935 if (ExtendedDescription && !MD->isUserProvided()) {
936 if (MD->isExplicitlyDefaulted())
943 if (CD->isDefaultConstructor())
945 else if (CD->isCopyConstructor())
947 else if (CD->isMoveConstructor())
950 Out <<
"constructor";
953 }
else if (isa<CXXDestructorDecl>(MD)) {
954 if (!MD->isUserProvided()) {
959 Out <<
"'" << *MD <<
"'";
962 }
else if (MD->isCopyAssignmentOperator()) {
963 Out <<
"copy assignment operator";
966 }
else if (MD->isMoveAssignmentOperator()) {
967 Out <<
"move assignment operator";
971 if (MD->getParent()->getIdentifier())
972 Out <<
"'" << *MD->getParent() <<
"::" << *MD <<
"'";
974 Out <<
"'" << *MD <<
"'";
980 Out << Prefix << '\'' << cast<NamedDecl>(*D) <<
'\'';
990 llvm::raw_svector_ostream Out(buf);
995 assert(callEnter.asLocation().isValid());
1001 if (!callEnterWithin.asLocation().isValid())
1003 if (Callee->isImplicit() || !Callee->hasBody())
1005 if (
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
1006 if (MD->isDefaulted())
1010 llvm::raw_svector_ostream Out(buf);
1012 Out <<
"Entered call";
1024 llvm::raw_svector_ostream Out(buf);
1026 if (!CallStackMessage.empty()) {
1027 Out << CallStackMessage;
1033 Out <<
"Returning to caller";
1036 assert(callReturn.asLocation().isValid());
1041 for (PathPieces::const_iterator it = pieces.begin(),
1042 et = pieces.end(); it != et; ++it) {
1045 dyn_cast<PathDiagnosticCallPiece>(piece)) {
1064 ID.AddInteger(Range.getBegin().getRawEncoding());
1065 ID.AddInteger(Range.getEnd().getRawEncoding());
1066 ID.AddInteger(
Loc.getRawEncoding());
1071 ID.AddInteger((
unsigned)
getKind());
1074 ID.AddInteger((
unsigned) getDisplayHint());
1078 ID.AddInteger(I->getBegin().getRawEncoding());
1079 ID.AddInteger(I->getEnd().getRawEncoding());
1085 for (PathPieces::const_iterator it = path.begin(),
1086 et = path.end(); it != et; ++it) {
1104 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1110 ID.Add(getLocation());
1112 ID.AddString(VerboseDesc);
1113 ID.AddString(Category);
1118 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1120 for (
meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1132 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1137 return getMessageForSymbolNotFound();
1142 unsigned ArgIndex = 0;
1144 E = CE->
arg_end(); I != E; ++I, ++ArgIndex){
1145 SVal SV = State->getSVal(*I, LCtx);
1150 return getMessageForArg(*I, ArgIndex);
1155 SVal PSV = State->getSVal(Reg->getRegion());
1158 return getMessageForArg(*I, ArgIndex);
1164 SVal SV = State->getSVal(CE, LCtx);
1166 if (RetSym == Sym) {
1167 return getMessageForReturn(CE);
1170 return getMessageForSymbolNotFound();
1174 unsigned ArgIndex) {
1179 llvm::raw_svector_ostream os(buf);
1181 os << Msg <<
" via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
SourceLocation getEnd() const
static Optional< bool > compareMacro(const PathDiagnosticMacroPiece &X, const PathDiagnosticMacroPiece &Y)
~PathDiagnosticMacroPiece() override
static void compute_path_size(const PathPieces &pieces, unsigned &size)
IdentifierInfo * getIdentifier() const
std::deque< std::string >::const_iterator meta_iterator
const StackFrameContext * getCalleeContext() const
Defines the SourceManager interface.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, const SourceManager &SM)
~PathDiagnosticEventPiece() override
StringRef getCategory() const
const SourceManager & getManager() const
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)
const CXXDeleteExpr * getDeleteExpr() const
virtual ~StackHintGenerator()=0
SourceLocation getOperatorLoc() const
SourceLocation getLocEnd() const LLVM_READONLY
Represents a C++ constructor within a class.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
PathDiagnosticLocation getLocation() const
Expr * getInit() const
Get the initializer.
const Decl * getDeclWithIssue() const
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
~PathDiagnosticPiece() override
Defines the clang::Expr interface and subclasses for C++ expressions.
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
FullSourceLoc asLocation() const
Symbolic value. These values used to capture symbolic execution of the program.
AnalysisDeclContext * getAnalysisDeclContext() const
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef. Otherwise return 0...
StringRef getString() const
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
~PathDiagnosticControlFlowPiece() override
bool containsEvent() const
virtual ~PathDiagnosticConsumer()
SourceLocation getLBracLoc() const
Optional< T > getLocationAs() const LLVM_LVALUE_FUNCTION
virtual void Profile(llvm::FoldingSetNodeID &ID) const
static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const SourceManager &SMgr)
llvm::FoldingSet< PathDiagnostic > Diags
std::vector< PathDiagnosticLocationPair >::const_iterator const_iterator
unsigned getIndex() const
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallExitEvent() const
const CFGBlock * getCallSiteBlock() const
A builtin binary operation expression such as "x + y" or "x <= y".
const Stmt * getCallSite() const
std::string getMessage(const ExplodedNode *N) override
Search the call expression for the symbol Sym and dispatch the 'getMessageForX()' methods to construc...
static PathDiagnosticCallPiece * construct(const ExplodedNode *N, const CallExitEnd &CE, const SourceManager &SM)
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
static Optional< bool > comparePath(const PathPieces &X, const PathPieces &Y)
const Decl * getDecl() const
meta_iterator meta_begin() const
PathDiagnosticLocation callEnter
virtual PathDiagnosticLocation getLocation() const =0
const Stmt * getTriggerStmt() const
static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEnd=false)
const LocationContext * getLocationContext() const
static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
PDFileEntry::ConsumerFiles * getFiles(const PathDiagnostic &PD)
SourceLocation getBodyRBrace() const
Stmt * getBody() const
Get the body of the Declaration.
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallEnterWithinCallerEvent() const
ID
Defines the set of possible language-specific address spaces.
const ProgramStateRef & getState() const
void FullProfile(llvm::FoldingSetNodeID &ID) const
Stmt * getTerminatorCondition(bool StripParens=true)
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
StringRef getShortDescription() const
const SourceManager & getManager() const
CXXCtorInitializer * getInitializer() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
const ExplodedNode * getFirstSucc() const
PathDiagnosticLocation getEndLocation() const
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallEnterEvent() const
static PathDiagnosticLocation getLocationForCaller(const StackFrameContext *SFC, const LocationContext *CallerCtx, const SourceManager &SM)
static const Stmt * getNextStmt(const ExplodedNode *N)
Retrieve the statement corresponding to the successor node.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
void resetDiagnosticLocationToMainFile()
If the last piece of the report point to the header file, resets the location of the report to be the...
std::vector< std::pair< StringRef, StringRef > > ConsumerFiles
DeclarationName getDeclName() const
virtual bool supportsCrossFileDiagnostics() const
PathDiagnosticLocation getStartLocation() const
static Optional< bool > comparePiece(const PathDiagnosticPiece &X, const PathDiagnosticPiece &Y)
llvm::PointerUnion< const LocationContext *, AnalysisDeclContext * > LocationOrAnalysisDeclContext
meta_iterator meta_end() const
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
SourceLocation getLocStart() const LLVM_READONLY
static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, const SourceManager &SM)
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
~PathDiagnosticCallPiece() override
virtual void FlushDiagnosticsImpl(std::vector< const PathDiagnostic * > &Diags, FilesMade *filesMade)=0
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
StringRef getVerboseDescription() const
bool isSingleDecl() const
PathDiagnosticLocation callReturn
void Profile(llvm::FoldingSetNodeID &ID) const
void setCallee(const CallEnter &CE, const SourceManager &SM)
static PathDiagnosticLocation createConditionalColonLoc(const ConditionalOperator *CO, const SourceManager &SM)
Represents a static or instance method of a struct/union/class.
const Stmt * getStmt() const
static bool describeCodeDecl(raw_ostream &Out, const Decl *D, bool ExtendedDescription, StringRef Prefix=StringRef())
virtual Stmt * getBody() const
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
const StackFrameContext * getCalleeContext() const
const Decl * getDecl() const
SourceLocation getBegin() const
const Decl * getSingleDecl() const
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
ConsumerFiles files
A vector of <consumer,file> pairs.
SourceLocation getLocStart() const LLVM_READONLY
static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, StringRef Prefix=StringRef())
const LocationContext * getLocationContext() const
void FlushDiagnostics(FilesMade *FilesMade)
static Optional< bool > compareCall(const PathDiagnosticCallPiece &X, const PathDiagnosticCallPiece &Y)
void Profile(llvm::FoldingSetNodeID &ID) const override
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
void appendToDesc(StringRef S)
SourceLocation getMemberLoc() const
void Profile(llvm::FoldingSetNodeID &ID) const
void Profile(llvm::FoldingSetNodeID &ID) const override
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
bool isBeforeInTranslationUnitThan(SourceLocation Loc) const
Determines the order of 2 source locations in the translation unit.
Represents a C++ struct/union/class.
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
CFGElement - Represents a top-level expression in a basic block.
static StringRef StripTrailingDots(StringRef s)
unsigned kind
All of the diagnostics that can be emitted by the frontend.
A SourceLocation and its associated SourceManager.
PathDiagnosticLocation callEnterWithin
SourceLocation getRBracLoc() const
static Decl::Kind getKind(const Decl *D)
void Profile(llvm::FoldingSetNodeID &ID) const override
StringRef getBugType() const
void addDiagnostic(const PathDiagnostic &PD, StringRef ConsumerName, StringRef fileName)
FullSourceLoc getExpansionLoc() const
ParentMap & getParentMap()
A trivial tuple used to represent a source range.
SourceLocation getLocation() const
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
static Optional< bool > compareControlFlow(const PathDiagnosticControlFlowPiece &X, const PathDiagnosticControlFlowPiece &Y)
This class handles loading and caching of source files into memory.
SourceLocation getColonLoc() const
unsigned full_size()
Return the unrolled size of the path.
void Profile(llvm::FoldingSetNodeID &ID) const override