diff options
-rw-r--r-- | clang/include/clang/Frontend/ASTUnit.h | 26 | ||||
-rw-r--r-- | clang/include/clang/Lex/PreprocessingRecord.h | 8 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ASTReader.h | 7 | ||||
-rw-r--r-- | clang/include/clang/Serialization/ASTWriter.h | 14 | ||||
-rw-r--r-- | clang/lib/Frontend/ASTUnit.cpp | 70 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 67 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 44 | ||||
-rw-r--r-- | clang/lib/Serialization/GeneratePCH.cpp | 8 | ||||
-rw-r--r-- | clang/test/Index/c-index-getCursor-pp.c | 6 | ||||
-rw-r--r-- | clang/tools/libclang/CIndex.cpp | 20 |
10 files changed, 220 insertions, 50 deletions
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index c7db42d6900..4e27cf3032e 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -110,6 +110,14 @@ private: // more scalable search mechanisms. std::vector<Decl*> TopLevelDecls; + /// \brief The list of preprocessed entities which appeared when the ASTUnit + /// was loaded. + /// + /// FIXME: This is just an optimization hack to avoid deserializing large + /// parts of a PCH file while performing a walk or search. In the long term, + /// we should provide more scalable search mechanisms. + std::vector<PreprocessedEntity *> PreprocessedEntities; + /// The name of the original source file used to generate this ASTUnit. std::string OriginalSourceFile; @@ -215,6 +223,10 @@ private: /// declarations parsed within the precompiled preamble. std::vector<serialization::DeclID> TopLevelDeclsInPreamble; + /// \brief A list of the offsets into the precompiled preamble which + /// correspond to preprocessed entities. + std::vector<uint64_t> PreprocessedEntitiesInPreamble; + /// \brief Whether we should be caching code-completion results. bool ShouldCacheCodeCompletionResults; @@ -317,7 +329,8 @@ private: bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); - + void RealizePreprocessedEntitiesFromPreamble(); + public: class ConcurrencyCheck { volatile ASTUnit &Self; @@ -426,6 +439,17 @@ public: TopLevelDeclsInPreamble.push_back(D); } + typedef std::vector<PreprocessedEntity *>::iterator pp_entity_iterator; + + pp_entity_iterator pp_entity_begin(); + pp_entity_iterator pp_entity_end(); + + /// \brief Add a new preprocessed entity that's stored at the given offset + /// in the precompiled preamble. + void addPreprocessedEntityFromPreamble(uint64_t Offset) { + PreprocessedEntitiesInPreamble.push_back(Offset); + } + /// \brief Retrieve the mapping from File IDs to the preprocessed entities /// within that file. PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() { diff --git a/clang/include/clang/Lex/PreprocessingRecord.h b/clang/include/clang/Lex/PreprocessingRecord.h index 01ac79d3d42..5a3b85ddd43 100644 --- a/clang/include/clang/Lex/PreprocessingRecord.h +++ b/clang/include/clang/Lex/PreprocessingRecord.h @@ -248,6 +248,9 @@ namespace clang { /// \brief Read any preallocated preprocessed entities from the external /// source. virtual void ReadPreprocessedEntities() = 0; + + /// \brief Read the preprocessed entity at the given offset. + virtual PreprocessedEntity *ReadPreprocessedEntity(uint64_t Offset) = 0; }; /// \brief A record of the steps taken while preprocessing a source file, @@ -302,6 +305,11 @@ namespace clang { void SetExternalSource(ExternalPreprocessingRecordSource &Source, unsigned NumPreallocatedEntities); + /// \brief Retrieve the external source for preprocessed entities. + ExternalPreprocessingRecordSource *getExternalSource() const { + return ExternalSource; + } + unsigned getNumPreallocatedEntities() const { return NumPreallocatedEntities; } diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index c1470ea12d8..cc3497a1009 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -845,9 +845,12 @@ public: /// build prior to including the precompiled header. const std::string &getSuggestedPredefines() { return SuggestedPredefines; } - /// \brief Read preprocessed entities into the + /// \brief Read preprocessed entities into the preprocessing record. virtual void ReadPreprocessedEntities(); + /// \brief Read the preprocessed entity at the given offset. + virtual PreprocessedEntity *ReadPreprocessedEntity(uint64_t Offset); + void ReadUserDiagnosticMappings(Diagnostic &Diag); /// \brief Returns the number of source locations found in the chain. @@ -1154,7 +1157,7 @@ public: Expr *ReadSubExpr(); /// \brief Reads the macro record located at the given offset. - void ReadMacroRecord(PerFileData &F, uint64_t Offset); + PreprocessedEntity *ReadMacroRecord(PerFileData &F, uint64_t Offset); /// \brief Note that the identifier is a macro whose record will be loaded /// from the given AST file at the given (file-local) offset. diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 6b7884d525d..e0f1d963214 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -23,6 +23,7 @@ #include "clang/Sema/SemaConsumer.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/Bitcode/BitstreamWriter.h" #include <map> #include <queue> @@ -37,6 +38,7 @@ namespace llvm { namespace clang { class ASTContext; +class ASTSerializationListener; class NestedNameSpecifier; class CXXBaseSpecifier; class CXXBaseOrMemberInitializer; @@ -44,6 +46,7 @@ class LabelStmt; class MacroDefinition; class MemorizeStatCalls; class ASTReader; +class PreprocessedEntity; class Preprocessor; class Sema; class SourceManager; @@ -70,6 +73,10 @@ private: /// \brief The reader of existing AST files, if we're chaining. ASTReader *Chain; + /// \brief A listener object that receives notifications when certain + /// entities are serialized. + ASTSerializationListener *SerializationListener; + /// \brief Stores a declaration or a type to be written to the AST file. class DeclOrType { public: @@ -334,6 +341,12 @@ public: /// the given bitstream. ASTWriter(llvm::BitstreamWriter &Stream); + /// \brief Set the listener that will receive notification of serialization + /// events. + void SetSerializationListener(ASTSerializationListener *Listener) { + SerializationListener = Listener; + } + /// \brief Write a precompiled header for the given semantic analysis. /// /// \param SemaRef a reference to the semantic analysis object that processed @@ -573,6 +586,7 @@ public: virtual void InitializeSema(Sema &S) { SemaPtr = &S; } virtual void HandleTranslationUnit(ASTContext &Ctx); virtual ASTMutationListener *GetASTMutationListener(); + virtual ASTSerializationListener *GetASTSerializationListener(); virtual ASTDeserializationListener *GetASTDeserializationListener(); }; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index a43d0d3ca11..586002daef5 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -27,6 +27,7 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTSerializationListener.h" #include "clang/Serialization/ASTWriter.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -637,10 +638,11 @@ public: } }; -class PrecompilePreambleConsumer : public PCHGenerator { +class PrecompilePreambleConsumer : public PCHGenerator, + public ASTSerializationListener { ASTUnit &Unit; std::vector<Decl *> TopLevelDecls; - + public: PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP, bool Chaining, @@ -672,6 +674,15 @@ public: getWriter().getDeclID(TopLevelDecls[I])); } } + + virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity, + uint64_t Offset) { + Unit.addPreprocessedEntityFromPreamble(Offset); + } + + virtual ASTSerializationListener *GetASTSerializationListener() { + return this; + } }; class PrecompilePreambleAction : public ASTFrontendAction { @@ -757,6 +768,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Clear out old caches and data. TopLevelDecls.clear(); + PreprocessedEntities.clear(); CleanTemporaryFiles(); PreprocessedEntitiesByFile.clear(); @@ -765,6 +777,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, StoredDiagnostics.end()); TopLevelDeclsInPreamble.clear(); + PreprocessedEntitiesInPreamble.clear(); } // Create a file manager object to provide access to and cache the filesystem. @@ -1237,6 +1250,8 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( StoredDiagnostics.end()); TopLevelDecls.clear(); TopLevelDeclsInPreamble.clear(); + PreprocessedEntities.clear(); + PreprocessedEntitiesInPreamble.clear(); // Create a file manager object to provide access to and cache the filesystem. Clang.setFileManager(new FileManager(Clang.getFileSystemOpts())); @@ -1269,6 +1284,8 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); TopLevelDeclsInPreamble.clear(); + PreprocessedEntities.clear(); + PreprocessedEntitiesInPreamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); @@ -1321,6 +1338,55 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() { TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); } +void ASTUnit::RealizePreprocessedEntitiesFromPreamble() { + if (!PP) + return; + + PreprocessingRecord *PPRec = PP->getPreprocessingRecord(); + if (!PPRec) + return; + + ExternalPreprocessingRecordSource *External = PPRec->getExternalSource(); + if (!External) + return; + + for (unsigned I = 0, N = PreprocessedEntitiesInPreamble.size(); I != N; ++I) { + if (PreprocessedEntity *PE + = External->ReadPreprocessedEntity(PreprocessedEntitiesInPreamble[I])) + PreprocessedEntities.push_back(PE); + } + + if (PreprocessedEntities.empty()) + return; + + PreprocessedEntities.insert(PreprocessedEntities.end(), + PPRec->begin(true), PPRec->end(true)); +} + +ASTUnit::pp_entity_iterator ASTUnit::pp_entity_begin() { + if (!PreprocessedEntitiesInPreamble.empty() && + PreprocessedEntities.empty()) + RealizePreprocessedEntitiesFromPreamble(); + + if (PreprocessedEntities.empty()) + if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) + return PPRec->begin(true); + + return PreprocessedEntities.begin(); +} + +ASTUnit::pp_entity_iterator ASTUnit::pp_entity_end() { + if (!PreprocessedEntitiesInPreamble.empty() && + PreprocessedEntities.empty()) + RealizePreprocessedEntitiesFromPreamble(); + + if (PreprocessedEntities.empty()) + if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) + return PPRec->end(true); + + return PreprocessedEntities.end(); +} + unsigned ASTUnit::getMaxPCHLevel() const { if (!getOnlyLocalDecls()) return Decl::MaxPCHLevel; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 1cac948d032..57002eb5d0b 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1339,7 +1339,7 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, } } -void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { +PreprocessedEntity *ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { assert(PP && "Forgot to set Preprocessor ?"); llvm::BitstreamCursor &Stream = F.MacroCursor; @@ -1356,14 +1356,14 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { unsigned Code = Stream.ReadCode(); switch (Code) { case llvm::bitc::END_BLOCK: - return; + return 0; case llvm::bitc::ENTER_SUBBLOCK: // No known subblocks, always skip them. Stream.ReadSubBlockID(); if (Stream.SkipBlock()) { Error("malformed block record in AST file"); - return; + return 0; } continue; @@ -1387,12 +1387,12 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { // of the definition of the macro we were looking for. We're // done. if (Macro) - return; + return 0; IdentifierInfo *II = DecodeIdentifierInfo(Record[0]); if (II == 0) { Error("macro must have a name in AST file"); - return; + return 0; } SourceLocation Loc = ReadSourceLocation(F, Record[1]); bool isUsed = Record[2]; @@ -1459,16 +1459,16 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { // of the definition of the macro we were looking for. We're // done. if (Macro) - return; + return 0; if (!PP->getPreprocessingRecord()) { Error("missing preprocessing record in AST file"); - return; + return 0; } PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); - if (PPRec.getPreprocessedEntity(Record[0])) - return; + if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0])) + return PE; MacroInstantiation *MI = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]), @@ -1476,7 +1476,7 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { ReadSourceLocation(F, Record[2])), getMacroDefinition(Record[4])); PPRec.SetPreallocatedEntity(Record[0], MI); - return; + return MI; } case PP_MACRO_DEFINITION: { @@ -1484,20 +1484,20 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { // of the definition of the macro we were looking for. We're // done. if (Macro) - return; + return 0; if (!PP->getPreprocessingRecord()) { Error("missing preprocessing record in AST file"); - return; + return 0; } PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); - if (PPRec.getPreprocessedEntity(Record[0])) - return; + if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0])) + return PE; if (Record[1] > MacroDefinitionsLoaded.size()) { Error("out-of-bounds macro definition record"); - return; + return 0; } // Decode the identifier info and then check again; if the macro is @@ -1518,7 +1518,7 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { DeserializationListener->MacroDefinitionRead(Record[1], MD); } - return; + return MacroDefinitionsLoaded[Record[1] - 1]; } case PP_INCLUSION_DIRECTIVE: { @@ -1526,21 +1526,21 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { // of the definition of the macro we were looking for. We're // done. if (Macro) - return; + return 0; if (!PP->getPreprocessingRecord()) { Error("missing preprocessing record in AST file"); - return; + return 0; } PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); - if (PPRec.getPreprocessedEntity(Record[0])) - return; + if (PreprocessedEntity *PE = PPRec.getPreprocessedEntity(Record[0])) + return PE; const char *FullFileNameStart = BlobStart + Record[3]; const FileEntry *File - = PP->getFileManager().getFile(llvm::StringRef(FullFileNameStart, - BlobLen - Record[3])); + = PP->getFileManager().getFile(llvm::StringRef(FullFileNameStart, + BlobLen - Record[3])); // FIXME: Stable encoding InclusionDirective::InclusionKind Kind @@ -1553,10 +1553,12 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) { SourceRange(ReadSourceLocation(F, Record[1]), ReadSourceLocation(F, Record[2]))); PPRec.SetPreallocatedEntity(Record[0], ID); - return; + return ID; } } } + + return 0; } void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, PerFileData &F, @@ -2638,6 +2640,25 @@ void ASTReader::ReadPreprocessedEntities() { ReadDefinedMacros(); } +PreprocessedEntity *ASTReader::ReadPreprocessedEntity(uint64_t Offset) { + PerFileData *F = 0; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (Offset < Chain[I]->SizeInBits) { + F = Chain[I]; + break; + } + + Offset -= Chain[I]->SizeInBits; + } + + if (!F) { + Error("Malformed preprocessed entity offset"); + return 0; + } + + return ReadMacroRecord(*F, Offset); +} + void ASTReader::ReadUserDiagnosticMappings(Diagnostic &Diag) { unsigned Idx = 0; while (Idx < UserDiagMappings.size()) { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index b143ce4b1b5..9a5085da279 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" +#include "clang/Serialization/ASTSerializationListener.h" #include "ASTCommon.h" #include "clang/Sema/Sema.h" #include "clang/Sema/IdentifierResolver.h" @@ -1358,33 +1359,28 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { E != EEnd; ++E) { Record.clear(); - if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) { - Record.push_back(IndexBase + NumPreprocessingRecords++); - AddSourceLocation(MI->getSourceRange().getBegin(), Record); - AddSourceLocation(MI->getSourceRange().getEnd(), Record); - AddIdentifierRef(MI->getName(), Record); - Record.push_back(getMacroDefinitionID(MI->getDefinition())); - Stream.EmitRecord(PP_MACRO_INSTANTIATION, Record); - continue; - } - if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) { // Record this macro definition's location. MacroID ID = getMacroDefinitionID(MD); - + // Don't write the macro definition if it is from another AST file. if (ID < FirstMacroID) continue; + + // Notify the serialization listener that we're serializing this entity. + if (SerializationListener) + SerializationListener->SerializedPreprocessedEntity(*E, + Stream.GetCurrentBitNo()); unsigned Position = ID - FirstMacroID; if (Position != MacroDefinitionOffsets.size()) { if (Position > MacroDefinitionOffsets.size()) MacroDefinitionOffsets.resize(Position + 1); - + MacroDefinitionOffsets[Position] = Stream.GetCurrentBitNo(); } else MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); - + Record.push_back(IndexBase + NumPreprocessingRecords++); Record.push_back(ID); AddSourceLocation(MD->getSourceRange().getBegin(), Record); @@ -1395,6 +1391,21 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { continue; } + // Notify the serialization listener that we're serializing this entity. + if (SerializationListener) + SerializationListener->SerializedPreprocessedEntity(*E, + Stream.GetCurrentBitNo()); + + if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) { + Record.push_back(IndexBase + NumPreprocessingRecords++); + AddSourceLocation(MI->getSourceRange().getBegin(), Record); + AddSourceLocation(MI->getSourceRange().getEnd(), Record); + AddIdentifierRef(MI->getName(), Record); + Record.push_back(getMacroDefinitionID(MI->getDefinition())); + Stream.EmitRecord(PP_MACRO_INSTANTIATION, Record); + continue; + } + if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) { Record.push_back(PP_INCLUSION_DIRECTIVE); Record.push_back(IndexBase + NumPreprocessingRecords++); @@ -1409,6 +1420,8 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer); continue; } + + llvm_unreachable("Unhandled PreprocessedEntity in ASTWriter"); } } @@ -2232,7 +2245,8 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { } ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) - : Stream(Stream), Chain(0), FirstDeclID(1), NextDeclID(FirstDeclID), + : Stream(Stream), Chain(0), SerializationListener(0), + FirstDeclID(1), NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), FirstIdentID(1), NextIdentID(FirstIdentID), FirstSelectorID(1), NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID), @@ -3415,3 +3429,5 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); AddDeclRef(D, Record); } + +ASTSerializationListener::~ASTSerializationListener() { } diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index 4f6f5cae426..3b4f869c007 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -32,7 +32,6 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS) : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream), Chaining(Chaining) { - // Install a stat() listener to keep track of all of the stat() // calls. StatCalls = new MemorizeStatCalls(); @@ -46,6 +45,9 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { if (PP.getDiagnostics().hasErrorOccurred()) return; + // Set up the serialization listener. + Writer.SetSerializationListener(GetASTSerializationListener()); + // Emit the PCH file assert(SemaPtr && "No Sema?"); Writer.WriteAST(*SemaPtr, StatCalls, isysroot); @@ -66,6 +68,10 @@ ASTMutationListener *PCHGenerator::GetASTMutationListener() { return 0; } +ASTSerializationListener *PCHGenerator::GetASTSerializationListener() { + return 0; +} + ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { return &Writer; } diff --git a/clang/test/Index/c-index-getCursor-pp.c b/clang/test/Index/c-index-getCursor-pp.c index 5f3c1df990b..2393965c283 100644 --- a/clang/test/Index/c-index-getCursor-pp.c +++ b/clang/test/Index/c-index-getCursor-pp.c @@ -20,3 +20,9 @@ void OBSCURE(func)(int x) { // CHECK-5: macro instantiation=DECORATION:2:9 // RUN: c-index-test -cursor-at=%s:9:10 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-6 %s // CHECK-6: inclusion directive=a.h + +// Same tests, but with "editing" optimizations +// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s +// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:2:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-2 %s +// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:5:7 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-3 %s +// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:9:10 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-6 %s diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 7fc2f6ebb4a..cdd7764016f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -410,10 +410,18 @@ CursorVisitor::getPreprocessedEntities() { bool OnlyLocalDecls = !AU->isMainFileAST() && AU->getOnlyLocalDecls(); + PreprocessingRecord::iterator StartEntity, EndEntity; + if (OnlyLocalDecls) { + StartEntity = AU->pp_entity_begin(); + EndEntity = AU->pp_entity_end(); + } else { + StartEntity = PPRec.begin(); + EndEntity = PPRec.end(); + } + // There is no region of interest; we have to walk everything. if (RegionOfInterest.isInvalid()) - return std::make_pair(PPRec.begin(OnlyLocalDecls), - PPRec.end(OnlyLocalDecls)); + return std::make_pair(StartEntity, EndEntity); // Find the file in which the region of interest lands. SourceManager &SM = AU->getSourceManager(); @@ -424,18 +432,16 @@ CursorVisitor::getPreprocessedEntities() { // The region of interest spans files; we have to walk everything. if (Begin.first != End.first) - return std::make_pair(PPRec.begin(OnlyLocalDecls), - PPRec.end(OnlyLocalDecls)); + return std::make_pair(StartEntity, EndEntity); ASTUnit::PreprocessedEntitiesByFileMap &ByFileMap = AU->getPreprocessedEntitiesByFile(); if (ByFileMap.empty()) { // Build the mapping from files to sets of preprocessed entities. - for (PreprocessingRecord::iterator E = PPRec.begin(OnlyLocalDecls), - EEnd = PPRec.end(OnlyLocalDecls); - E != EEnd; ++E) { + for (PreprocessingRecord::iterator E = StartEntity; E != EndEntity; ++E) { std::pair<FileID, unsigned> P = SM.getDecomposedInstantiationLoc((*E)->getSourceRange().getBegin()); + ByFileMap[P.first].push_back(*E); } } |