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) {}
66 bool ShouldFlattenMacros)
const {
67 for (PathPieces::const_iterator
I =
begin(),
E =
end();
I !=
E; ++
I) {
76 Current.push_back(CallEnter);
77 Call->
path.flattenTo(Primary, Primary, ShouldFlattenMacros);
81 Current.push_back(callExit);
86 if (ShouldFlattenMacros) {
87 Macro->
subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
89 Current.push_back(Piece);
91 Macro->
subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
99 Current.push_back(Piece);
108 PathDiagnostic::PathDiagnostic(StringRef
CheckName,
const Decl *declWithIssue,
109 StringRef bugtype, StringRef verboseDesc,
110 StringRef shortDesc, StringRef category,
112 const Decl *DeclToUnique)
113 : CheckName(CheckName),
114 DeclWithIssue(declWithIssue),
119 UniqueingLoc(LocationToUnique),
120 UniqueingDecl(DeclToUnique),
133 "The call piece should be in the main file.");
146 dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
168 CP->setAsLastInMainSourceFile();
174 llvm::raw_svector_ostream os(buf);
175 os <<
" (within a call to '" << ND->
getDeclName() <<
"')";
180 DeclWithIssue = CP->getCaller();
181 Loc = CP->getLocation();
188 void PathDiagnosticConsumer::anchor() { }
193 Diags.begin(), et =
Diags.end() ; it != et ; ++it) {
199 std::unique_ptr<PathDiagnostic> D) {
200 if (!D || D->path.empty())
206 D->flattenLocations();
213 const SourceManager &SMgr = D->path.front()->getLocation().getManager();
215 WorkList.push_back(&D->path);
217 while (!WorkList.empty()) {
218 const PathPieces &path = *WorkList.pop_back_val();
220 for (PathPieces::const_iterator
I = path.begin(),
E = path.end();
I !=
E;
233 E = Ranges.end();
I !=
E; ++
I) {
243 dyn_cast<PathDiagnosticCallPiece>(piece)) {
244 WorkList.push_back(&call->path);
247 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
248 WorkList.push_back(¯o->subPieces);
258 llvm::FoldingSetNodeID profile;
260 void *InsertPos =
nullptr;
267 const unsigned orig_size = orig->full_size();
268 const unsigned new_size = D->full_size();
269 if (orig_size <= new_size)
272 assert(orig != D.get());
273 Diags.RemoveNode(orig);
277 Diags.InsertNode(D.release());
308 if (X_CEWL != Y_CEWL)
335 for (
unsigned i = 0, n = X.
getRanges().size(); i < n; ++i) {
348 cast<PathDiagnosticControlFlowPiece>(Y));
353 cast<PathDiagnosticMacroPiece>(Y));
355 return compareCall(cast<PathDiagnosticCallPiece>(X),
356 cast<PathDiagnosticCallPiece>(Y));
358 llvm_unreachable(
"all cases handled");
362 if (X.size() != Y.size())
363 return X.size() < Y.size();
365 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
366 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
368 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
406 if (XE - XI != YE - YI)
407 return (XE - XI) < (YE - YI);
408 for ( ; XI != XE ; ++XI, ++YI) {
410 return (*XI) < (*YI);
413 assert(b.hasValue());
424 std::vector<const PathDiagnostic *> BatchDiags;
426 et =
Diags.end(); it != et; ++it) {
428 BatchDiags.push_back(D);
435 assert(*X != *Y &&
"PathDiagnostics not uniqued!");
438 assert(
compare(**Y, **X) &&
"Not a total order!");
441 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
447 et = BatchDiags.end(); it != et; ++it) {
458 Entry.~PDFileEntry();
462 StringRef ConsumerName,
463 StringRef FileName) {
464 llvm::FoldingSetNodeID NodeID;
467 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
471 Set.InsertNode(Entry, InsertPos);
475 char *FileName_cstr = (
char*) Alloc.Allocate(FileName.size(), 1);
476 memcpy(FileName_cstr, FileName.data(), FileName.size());
478 Entry->
files.push_back(std::make_pair(ConsumerName,
479 StringRef(FileName_cstr,
485 llvm::FoldingSetNodeID NodeID;
488 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
491 return &Entry->
files;
500 bool UseEnd =
false) {
502 assert(!LAC.isNull() &&
"A valid LocationContext or AnalysisDeclContext should "
503 "be passed to PathDiagnosticLocation upon creation.");
517 const Stmt *Parent =
S;
519 Parent = PM.getParent(Parent);
528 L = Body->getLocStart();
534 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
569 if (
const Stmt *CallerBody = CallerInfo->
getBody())
575 llvm_unreachable(
"not yet implemented!");
578 llvm_unreachable(
"Unknown CFGElement kind");
602 return createEndBrace(CS, SM);
647 if (!CS->body_empty()) {
666 const Stmt*
S =
nullptr;
668 const CFGBlock *BSrc = BE->getSrc();
681 CE->getLocationContext(),
685 CEE->getLocationContext(),
688 llvm_unreachable(
"Unexpected ProgramPoint");
697 return SP->getStmt();
699 return BE->getSrc()->getTerminator();
701 return CE->getCallExpr();
703 return CEE->getCalleeContext()->getCallSite();
705 return PIPP->getInitializer()->getInit();
712 if (
const Stmt *
S = getStmt(N)) {
715 switch (
S->getStmtClass()) {
716 case Stmt::ChooseExprClass:
717 case Stmt::BinaryConditionalOperatorClass:
718 case Stmt::ConditionalOperatorClass:
720 case Stmt::BinaryOperatorClass: {
740 assert(N &&
"Cannot create a location with a null node.");
741 const Stmt *
S = getStmt(N);
755 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(S))
765 if (S->getLocStart().isValid())
794 const_cast<SourceManager&>(*
SM));
816 const Stmt *
S = asStmt();
817 switch (S->getStmtClass()) {
820 case Stmt::DeclStmtClass: {
831 case Stmt::IfStmtClass:
832 case Stmt::WhileStmtClass:
833 case Stmt::DoStmtClass:
834 case Stmt::ForStmtClass:
835 case Stmt::ChooseExprClass:
836 case Stmt::IndirectGotoStmtClass:
837 case Stmt::SwitchStmtClass:
838 case Stmt::BinaryConditionalOperatorClass:
839 case Stmt::ConditionalOperatorClass:
840 case Stmt::ObjCForCollectionStmtClass: {
852 return MD->getSourceRange();
853 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
854 if (
Stmt *Body = FD->getBody())
855 return Body->getSourceRange();
872 else if (K == DeclK) {
896 const Decl *caller) {
913 StringRef Prefix = StringRef()) {
916 Out << Prefix <<
'\'' << *D <<
'\'';
920 bool ExtendedDescription,
921 StringRef Prefix = StringRef()) {
925 if (isa<BlockDecl>(D)) {
926 if (ExtendedDescription)
927 Out << Prefix <<
"anonymous block";
928 return ExtendedDescription;
933 if (ExtendedDescription && !MD->isUserProvided()) {
934 if (MD->isExplicitlyDefaulted())
941 if (CD->isDefaultConstructor())
943 else if (CD->isCopyConstructor())
945 else if (CD->isMoveConstructor())
948 Out <<
"constructor";
951 }
else if (isa<CXXDestructorDecl>(MD)) {
952 if (!MD->isUserProvided()) {
957 Out <<
"'" << *MD <<
"'";
960 }
else if (MD->isCopyAssignmentOperator()) {
961 Out <<
"copy assignment operator";
964 }
else if (MD->isMoveAssignmentOperator()) {
965 Out <<
"move assignment operator";
969 if (MD->getParent()->getIdentifier())
970 Out <<
"'" << *MD->getParent() <<
"::" << *MD <<
"'";
972 Out <<
"'" << *MD <<
"'";
978 Out << Prefix << '\'' << cast<NamedDecl>(*D) <<
'\'';
988 llvm::raw_svector_ostream Out(buf);
993 assert(callEnter.asLocation().isValid());
999 if (!callEnterWithin.asLocation().isValid())
1001 if (Callee->isImplicit() || !Callee->hasBody())
1003 if (
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
1004 if (MD->isDefaulted())
1008 llvm::raw_svector_ostream Out(buf);
1010 Out <<
"Entered call";
1022 llvm::raw_svector_ostream Out(buf);
1024 if (!CallStackMessage.empty()) {
1025 Out << CallStackMessage;
1031 Out <<
"Returning to caller";
1034 assert(callReturn.asLocation().isValid());
1039 for (PathPieces::const_iterator it = pieces.begin(),
1040 et = pieces.end(); it != et; ++it) {
1043 dyn_cast<PathDiagnosticCallPiece>(piece)) {
1062 ID.AddInteger(Range.getBegin().getRawEncoding());
1063 ID.AddInteger(Range.getEnd().getRawEncoding());
1064 ID.AddInteger(
Loc.getRawEncoding());
1069 ID.AddInteger((
unsigned)
getKind());
1072 ID.AddInteger((
unsigned) getDisplayHint());
1076 ID.AddInteger(
I->getBegin().getRawEncoding());
1077 ID.AddInteger(
I->getEnd().getRawEncoding());
1083 for (PathPieces::const_iterator it = path.begin(),
1084 et = path.end(); it != et; ++it) {
1102 for (PathPieces::const_iterator
I = subPieces.begin(),
E = subPieces.end();
1108 ID.Add(getLocation());
1110 ID.AddString(VerboseDesc);
1116 for (PathPieces::const_iterator
I = path.begin(),
E = path.end();
I !=
E; ++
I)
1130 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1135 return getMessageForSymbolNotFound();
1140 unsigned ArgIndex = 0;
1143 SVal SV = State->getSVal(*
I, LCtx);
1148 return getMessageForArg(*
I, ArgIndex);
1153 SVal PSV = State->getSVal(Reg->getRegion());
1156 return getMessageForArg(*
I, ArgIndex);
1162 SVal SV = State->getSVal(CE, LCtx);
1164 if (RetSym == Sym) {
1165 return getMessageForReturn(CE);
1168 return getMessageForSymbolNotFound();
1172 unsigned ArgIndex) {
1177 llvm::raw_svector_ostream os(buf);
1179 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.
Decl - This represents one declaration (or definition), e.g.
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
SourceLocation getLocEnd() const LLVM_READONLY
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)
SourceLocation getBodyRBrace() const
getBodyRBrace - Gets the right brace of the body, if a body exists.
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).
ID
Defines the set of possible language-specific address spaces.
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.
SourceLocation getLocStart() const LLVM_READONLY
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...
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
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.
SourceLocation getLocation() const
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