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) {}
65 bool ShouldFlattenMacros)
const {
66 for (PathPieces::const_iterator
I =
begin(),
E =
end();
I !=
E; ++
I) {
75 Current.push_back(CallEnter);
76 Call->
path.flattenTo(Primary, Primary, ShouldFlattenMacros);
80 Current.push_back(callExit);
85 if (ShouldFlattenMacros) {
86 Macro->
subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
88 Current.push_back(Piece);
90 Macro->
subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
98 Current.push_back(Piece);
106 PathDiagnostic::PathDiagnostic(StringRef
CheckName,
const Decl *declWithIssue,
107 StringRef bugtype, StringRef verboseDesc,
108 StringRef shortDesc, StringRef category,
110 const Decl *DeclToUnique)
111 : CheckName(CheckName),
112 DeclWithIssue(declWithIssue),
117 UniqueingLoc(LocationToUnique),
118 UniqueingDecl(DeclToUnique),
131 "The call piece should be in the main file.");
144 dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
166 CP->setAsLastInMainSourceFile();
172 llvm::raw_svector_ostream os(buf);
173 os <<
" (within a call to '" << ND->
getDeclName() <<
"')";
178 DeclWithIssue = CP->getCaller();
179 Loc = CP->getLocation();
186 void PathDiagnosticConsumer::anchor() { }
191 Diags.begin(), et =
Diags.end() ; it != et ; ++it) {
197 std::unique_ptr<PathDiagnostic> D) {
198 if (!D || D->path.empty())
204 D->flattenLocations();
211 const SourceManager &SMgr = D->path.front()->getLocation().getManager();
213 WorkList.push_back(&D->path);
215 while (!WorkList.empty()) {
216 const PathPieces &path = *WorkList.pop_back_val();
218 for (PathPieces::const_iterator
I = path.begin(),
E = path.end();
I !=
E;
231 E = Ranges.end();
I !=
E; ++
I) {
241 dyn_cast<PathDiagnosticCallPiece>(piece)) {
242 WorkList.push_back(&call->path);
245 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
246 WorkList.push_back(¯o->subPieces);
256 llvm::FoldingSetNodeID profile;
258 void *InsertPos =
nullptr;
265 const unsigned orig_size = orig->full_size();
266 const unsigned new_size = D->full_size();
267 if (orig_size <= new_size)
270 assert(orig != D.get());
271 Diags.RemoveNode(orig);
275 Diags.InsertNode(D.release());
307 if (X_CEWL != Y_CEWL)
334 for (
unsigned i = 0, n = X.
getRanges().size(); i < n; ++i) {
347 cast<PathDiagnosticControlFlowPiece>(Y));
352 cast<PathDiagnosticMacroPiece>(Y));
354 return compareCall(cast<PathDiagnosticCallPiece>(X),
355 cast<PathDiagnosticCallPiece>(Y));
357 llvm_unreachable(
"all cases handled");
361 if (X.size() != Y.size())
362 return X.size() < Y.size();
364 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
365 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
367 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
405 if (XE - XI != YE - YI)
406 return (XE - XI) < (YE - YI);
407 for ( ; XI != XE ; ++XI, ++YI) {
409 return (*XI) < (*YI);
412 assert(b.hasValue());
423 std::vector<const PathDiagnostic *> BatchDiags;
425 et =
Diags.end(); it != et; ++it) {
427 BatchDiags.push_back(D);
434 assert(*X != *Y &&
"PathDiagnostics not uniqued!");
437 assert(
compare(**Y, **X) &&
"Not a total order!");
440 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
446 et = BatchDiags.end(); it != et; ++it) {
457 Entry.~PDFileEntry();
461 StringRef ConsumerName,
463 llvm::FoldingSetNodeID NodeID;
466 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
470 Set.InsertNode(Entry, InsertPos);
474 char *FileName_cstr = (
char*) Alloc.Allocate(FileName.size(), 1);
475 memcpy(FileName_cstr, FileName.data(), FileName.size());
477 Entry->
files.push_back(std::make_pair(ConsumerName,
478 StringRef(FileName_cstr,
484 llvm::FoldingSetNodeID NodeID;
487 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
490 return &Entry->
files;
499 bool UseEnd =
false) {
501 assert(!LAC.isNull() &&
"A valid LocationContext or AnalysisDeclContext should "
502 "be passed to PathDiagnosticLocation upon creation.");
515 const Stmt *Parent =
S;
517 Parent = PM.getParent(Parent);
526 L = Body->getLocStart();
528 L = ADC->
getDecl()->getLocEnd();
532 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
567 if (
const Stmt *CallerBody = CallerInfo->
getBody())
573 llvm_unreachable(
"not yet implemented!");
576 llvm_unreachable(
"Unknown CFGElement kind");
598 return createEndBrace(CS, SM);
642 dyn_cast_or_null<CompoundStmt>(LC->
getDecl()->getBody()))
643 if (!CS->body_empty()) {
661 const Stmt*
S =
nullptr;
663 const CFGBlock *BSrc = BE->getSrc();
676 CE->getLocationContext(),
680 CEE->getLocationContext(),
683 llvm_unreachable(
"Unexpected ProgramPoint");
692 return SP->getStmt();
694 return BE->getSrc()->getTerminator();
696 return CE->getCallExpr();
698 return CEE->getCalleeContext()->getCallSite();
700 return PIPP->getInitializer()->getInit();
707 if (
const Stmt *
S = getStmt(N)) {
710 switch (
S->getStmtClass()) {
711 case Stmt::ChooseExprClass:
712 case Stmt::BinaryConditionalOperatorClass:
713 case Stmt::ConditionalOperatorClass:
715 case Stmt::BinaryOperatorClass: {
717 if (Op == BO_LAnd || Op == BO_LOr)
735 assert(N &&
"Cannot create a location with a null node.");
736 const Stmt *
S = getStmt(N);
750 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(S))
760 if (S->getLocStart().isValid())
789 const_cast<SourceManager&>(*
SM));
811 const Stmt *
S = asStmt();
812 switch (S->getStmtClass()) {
815 case Stmt::DeclStmtClass: {
826 case Stmt::IfStmtClass:
827 case Stmt::WhileStmtClass:
828 case Stmt::DoStmtClass:
829 case Stmt::ForStmtClass:
830 case Stmt::ChooseExprClass:
831 case Stmt::IndirectGotoStmtClass:
832 case Stmt::SwitchStmtClass:
833 case Stmt::BinaryConditionalOperatorClass:
834 case Stmt::ConditionalOperatorClass:
835 case Stmt::ObjCForCollectionStmtClass: {
847 return MD->getSourceRange();
848 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
849 if (
Stmt *Body = FD->getBody())
850 return Body->getSourceRange();
867 else if (K == DeclK) {
891 const Decl *caller) {
908 StringRef Prefix = StringRef()) {
911 Out << Prefix <<
'\'' << *D <<
'\'';
915 bool ExtendedDescription,
916 StringRef Prefix = StringRef()) {
920 if (isa<BlockDecl>(D)) {
921 if (ExtendedDescription)
922 Out << Prefix <<
"anonymous block";
923 return ExtendedDescription;
928 if (ExtendedDescription && !MD->isUserProvided()) {
929 if (MD->isExplicitlyDefaulted())
936 if (CD->isDefaultConstructor())
938 else if (CD->isCopyConstructor())
940 else if (CD->isMoveConstructor())
943 Out <<
"constructor";
946 }
else if (isa<CXXDestructorDecl>(MD)) {
947 if (!MD->isUserProvided()) {
952 Out <<
"'" << *MD <<
"'";
955 }
else if (MD->isCopyAssignmentOperator()) {
956 Out <<
"copy assignment operator";
959 }
else if (MD->isMoveAssignmentOperator()) {
960 Out <<
"move assignment operator";
964 if (MD->getParent()->getIdentifier())
965 Out <<
"'" << *MD->getParent() <<
"::" << *MD <<
"'";
967 Out <<
"'" << *MD <<
"'";
973 Out << Prefix << '\'' << cast<NamedDecl>(*D) <<
'\'';
983 llvm::raw_svector_ostream Out(buf);
988 assert(callEnter.asLocation().isValid());
994 if (!callEnterWithin.asLocation().isValid())
996 if (Callee->isImplicit() || !Callee->hasBody())
998 if (
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
999 if (MD->isDefaulted())
1003 llvm::raw_svector_ostream Out(buf);
1005 Out <<
"Entered call";
1017 llvm::raw_svector_ostream Out(buf);
1019 if (!CallStackMessage.empty()) {
1020 Out << CallStackMessage;
1026 Out <<
"Returning to caller";
1029 assert(callReturn.asLocation().isValid());
1034 for (PathPieces::const_iterator it = pieces.begin(),
1035 et = pieces.end(); it != et; ++it) {
1038 dyn_cast<PathDiagnosticCallPiece>(piece)) {
1057 ID.AddInteger(Range.getBegin().getRawEncoding());
1058 ID.AddInteger(Range.getEnd().getRawEncoding());
1059 ID.AddInteger(
Loc.getRawEncoding());
1063 ID.AddInteger((
unsigned)
getKind());
1066 ID.AddInteger((
unsigned) getDisplayHint());
1070 ID.AddInteger(
I->getBegin().getRawEncoding());
1071 ID.AddInteger(
I->getEnd().getRawEncoding());
1077 for (PathPieces::const_iterator it = path.begin(),
1078 et = path.end(); it != et; ++it) {
1096 for (PathPieces::const_iterator
I = subPieces.begin(),
E = subPieces.end();
1102 ID.Add(getLocation());
1104 ID.AddString(VerboseDesc);
1110 for (PathPieces::const_iterator
I = path.begin(),
E = path.end();
I !=
E; ++
I)
1124 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1129 return getMessageForSymbolNotFound();
1134 unsigned ArgIndex = 0;
1137 SVal SV = State->getSVal(*
I, LCtx);
1142 return getMessageForArg(*
I, ArgIndex);
1147 SVal PSV = State->getSVal(Reg->getRegion());
1150 return getMessageForArg(*
I, ArgIndex);
1156 SVal SV = State->getSVal(CE, LCtx);
1158 if (RetSym == Sym) {
1159 return getMessageForReturn(CE);
1162 return getMessageForSymbolNotFound();
1166 unsigned ArgIndex) {
1171 llvm::raw_svector_ostream os(buf);
1173 os << Msg <<
" via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
SourceLocation getEnd() const
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
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
getIdentifier - Get the identifier that names this declaration, if there is one.
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.
Represents a point when we begin processing an inlined call.
static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the beginning of the compound statement.
~PathDiagnosticEventPiece() override
StringRef getCategory() const
const SourceManager & getManager() const
CFGDeleteDtor - Represents C++ object destructor generated from a call to delete. ...
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)
Produces the message of the following form: 'Msg via Nth parameter'.
Represents a program point just before an implicit call event.
const CXXDeleteExpr * getDeleteExpr() const
virtual ~StackHintGenerator()=0
SourceLocation getOperatorLoc() const
Represents a C++ constructor within a class.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
PathDiagnosticLocation getLocation() const
Expr * getInit() const
Get the initializer.
ObjCMethodDecl - Represents an instance or class method declaration.
const Decl * getDeclWithIssue() const
Return the semantic context where an issue occurred.
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
~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
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
AnalysisDeclContext contains the context data for the function or method under analysis.
CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated for automatic object or t...
AnalysisDeclContext * getAnalysisDeclContext() const
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
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...
Represents a point after we ran remove dead bindings AFTER processing the given statement.
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
detail::InMemoryDirectory::const_iterator I
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)
For member expressions, return the location of the '.
ConditionalOperator - The ?: ternary operator.
CompoundStmt - This represents a group of statements like { stmt stmt }.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
CFGBlock - Represents a single basic block in a source-level CFG.
PDFileEntry::ConsumerFiles * getFiles(const PathDiagnostic &PD)
Stmt * getBody() const
Get the body of the Declaration.
IntrusiveRefCntPtr< PathDiagnosticEventPiece > getCallEnterWithinCallerEvent() const
Represents a point when we finish the call exit sequence (for inlined call).
Expr - This represents one expression.
const ProgramStateRef & getState() const
void FullProfile(llvm::FoldingSetNodeID &ID) const
Profiles the diagnostic, including its path.
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
getDeclName - Get the actual, stored name of the declaration, which may be a special name...
virtual bool supportsCrossFileDiagnostics() const
Return true if the PathDiagnosticConsumer supports individual PathDiagnostics that span multiple file...
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.
static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, const SourceManager &SM)
Create a location for the beginning of the enclosing declaration body.
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
ConstExprIterator const_arg_iterator
Encodes a location in the source.
const TemplateArgument * iterator
bool isValid() const
Return true if this is a valid SourceLocation object.
StringRef getVerboseDescription() const
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl. ...
PathDiagnosticLocation callReturn
void Profile(llvm::FoldingSetNodeID &ID) const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
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())
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx)
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
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
Represents a program point just after an implicit call event.
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)
detail::InMemoryDirectory::const_iterator E
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
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'...
void Profile(llvm::FoldingSetNodeID &ID) const
Profiles the diagnostic, independent of the path it references.
void Profile(llvm::FoldingSetNodeID &ID) const override
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
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)
Create a location corresponding to the next valid ExplodedNode as end of path location.
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.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
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
CFGInitializer - Represents C++ base or member initializer from constructor's initialization list...
ParentMap & getParentMap()
A trivial tuple used to represent a source range.
NamedDecl - This represents a decl with a name.
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