[PCH] When visiting preprocessed entities, make it possible to avoid deserializing
preprocessed entities that are #included in the range that we are interested.
This is useful when we are interested in preprocessed entities of a specific file, e.g
when we are annotating tokens. There is also an optimization where we cache the last
result of PreprocessingRecord::getPreprocessedEntitiesInRange and we re-use it if
there is a call with the same range as before.
rdar://10313365
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142887 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 17b2316..4bf1c52 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -192,6 +192,10 @@
/// \brief Whether we should visit the preprocessing record entries last,
/// after visiting other declarations.
bool VisitPreprocessorLast;
+
+ /// \brief Whether we should visit the preprocessing record entries that are
+ /// #included inside the \arg RegionOfInterest.
+ bool VisitIncludedPreprocessingEntries;
/// \brief When valid, a source range to which the cursor should restrict
/// its search.
@@ -240,10 +244,12 @@
CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
CXClientData ClientData,
bool VisitPreprocessorLast,
+ bool VisitIncludedPreprocessingEntries = false,
SourceRange RegionOfInterest = SourceRange())
: TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
Visitor(Visitor), ClientData(ClientData),
VisitPreprocessorLast(VisitPreprocessorLast),
+ VisitIncludedPreprocessingEntries(VisitIncludedPreprocessingEntries),
RegionOfInterest(RegionOfInterest), DI_current(0)
{
Parent.kind = CXCursor_NoDeclFound;
@@ -268,8 +274,14 @@
bool visitPreprocessedEntitiesInRegion();
+ bool shouldVisitIncludedPreprocessingEntries() const {
+ return VisitIncludedPreprocessingEntries;
+ }
+
template<typename InputIterator>
- bool visitPreprocessedEntities(InputIterator First, InputIterator Last);
+ bool visitPreprocessedEntities(InputIterator First, InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID = FileID());
bool VisitChildren(CXCursor Parent);
@@ -399,45 +411,95 @@
return false;
}
+static bool visitPreprocessedEntitiesInRange(SourceRange R,
+ PreprocessingRecord &PPRec,
+ CursorVisitor &Visitor) {
+ SourceManager &SM = Visitor.getASTUnit()->getSourceManager();
+ FileID FID;
+
+ if (!Visitor.shouldVisitIncludedPreprocessingEntries()) {
+ // If the begin/end of the range lie in the same FileID, do the optimization
+ // where we skip preprocessed entities that do not come from the same FileID.
+ FID = SM.getFileID(R.getBegin());
+ if (FID != SM.getFileID(R.getEnd()))
+ FID = FileID();
+ }
+
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ Entities = PPRec.getPreprocessedEntitiesInRange(R);
+ return Visitor.visitPreprocessedEntities(Entities.first, Entities.second,
+ PPRec, FID);
+}
+
bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
PreprocessingRecord &PPRec
= *AU->getPreprocessor().getPreprocessingRecord();
+ SourceManager &SM = AU->getSourceManager();
if (RegionOfInterest.isValid()) {
SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest);
- std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
- Entities = PPRec.getPreprocessedEntitiesInRange(MappedRange);
- return visitPreprocessedEntities(Entities.first, Entities.second);
+ SourceLocation B = MappedRange.getBegin();
+ SourceLocation E = MappedRange.getEnd();
+
+ if (AU->isInPreambleFileID(B)) {
+ if (SM.isLoadedSourceLocation(E))
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E),
+ PPRec, *this);
+
+ // Beginning of range lies in the preamble but it also extends beyond
+ // it into the main file. Split the range into 2 parts, one covering
+ // the preamble and another covering the main file. This allows subsequent
+ // calls to visitPreprocessedEntitiesInRange to accept a source range that
+ // lies in the same FileID, allowing it to skip preprocessed entities that
+ // do not come from the same FileID.
+ bool breaked =
+ visitPreprocessedEntitiesInRange(
+ SourceRange(B, AU->getEndOfPreambleFileID()),
+ PPRec, *this);
+ if (breaked) return true;
+ return visitPreprocessedEntitiesInRange(
+ SourceRange(AU->getStartOfMainFileID(), E),
+ PPRec, *this);
+ }
+
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E), PPRec, *this);
}
bool OnlyLocalDecls
= !AU->isMainFileAST() && AU->getOnlyLocalDecls();
if (OnlyLocalDecls)
- return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end());
+ return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end(),
+ PPRec);
- return visitPreprocessedEntities(PPRec.begin(), PPRec.end());
+ return visitPreprocessedEntities(PPRec.begin(), PPRec.end(), PPRec);
}
template<typename InputIterator>
bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
- InputIterator Last) {
+ InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID) {
for (; First != Last; ++First) {
- if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*First)) {
+ if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID))
+ continue;
+
+ PreprocessedEntity *PPE = *First;
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) {
if (Visit(MakeMacroExpansionCursor(ME, TU)))
return true;
continue;
}
- if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*First)) {
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(PPE)) {
if (Visit(MakeMacroDefinitionCursor(MD, TU)))
return true;
continue;
}
- if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*First)) {
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
if (Visit(MakeInclusionDirectiveCursor(ID, TU)))
return true;
@@ -3007,8 +3069,8 @@
unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data) {
- CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
- false);
+ CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
+ /*VisitPreprocessorLast=*/false);
return CursorVis.VisitChildren(parent);
}
@@ -3895,6 +3957,7 @@
CXCursor Parent = clang_getTranslationUnitCursor(TU);
CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
/*VisitPreprocessorLast=*/true,
+ /*VisitIncludedPreprocessingEntries=*/false,
SourceLocation(SLoc));
CursorVis.VisitChildren(Parent);
}
@@ -4722,7 +4785,10 @@
: Annotated(annotated), Tokens(tokens), Cursors(cursors),
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
AnnotateVis(tu,
- AnnotateTokensVisitor, this, true, RegionOfInterest),
+ AnnotateTokensVisitor, this,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedPreprocessingEntries=*/false,
+ RegionOfInterest),
SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
@@ -5197,7 +5263,9 @@
Tokens, NumTokens);
CursorVisitor MacroArgMarker(TU,
MarkMacroArgTokensVisitorDelegate, &Visitor,
- true, RegionOfInterest);
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedPreprocessingEntries=*/false,
+ RegionOfInterest);
MacroArgMarker.visitPreprocessedEntitiesInRegion();
}