diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 9301a833bad72b19edd5ac7dd901e41b2a8c3dfe..982c31d2932fd50a171b8e9b1cf858f68cf74dce 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -436,7 +436,10 @@ namespace clang { /// \brief Record code for ObjC categories in a module that are chained to /// an interface. - OBJC_CHAINED_CATEGORIES + OBJC_CHAINED_CATEGORIES, + + /// \brief Record code for a file sorted array of DeclIDs in a module. + FILE_SORTED_DECLS }; /// \brief Record types used within a source manager block. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index a463a280d343281be9e2fdff6feb75f7c3402def..f9ca9b27586639b1d801a82cd46693ba07e2b7e1 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -296,6 +296,9 @@ private: /// \brief Declarations that have been replaced in a later file in the chain. DeclReplacementMap ReplacedDecls; + /// \brief Map from a FileID to the file-level declarations that it contains. + llvm::DenseMap<FileID, ArrayRef<serialization::DeclID> > FileDeclIDs; + // Updates for visible decls can occur for other contexts than just the // TU, and when we read those update records, the actual context will not // be available yet (unless it's the TU), so have this pending map using the diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 184897fba9dfe16d7d6038952f68368b40d9642e..52c80d1248e2450252c9ebb90b77a67b3ed83645 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -59,6 +59,8 @@ class SwitchCase; class TargetInfo; class VersionTuple; +namespace SrcMgr { class SLocEntry; } + /// \brief Writes an AST file containing the contents of a translation unit. /// /// The ASTWriter class produces a bitstream containing the serialized @@ -144,6 +146,25 @@ private: /// the declaration's ID. std::vector<serialization::DeclOffset> DeclOffsets; + /// \brief Vector of pairs of raw location/DeclID. + typedef SmallVector<std::pair<unsigned, serialization::DeclID>, 64> + LocDeclIDsTy; + struct DeclIDInFileInfo { + LocDeclIDsTy DeclIDs; + /// \brief Set when the DeclIDs vectors from all files are joined, this + /// indicates the index that this particular vector has in the global one. + unsigned FirstDeclIndex; + }; + typedef llvm::DenseMap<const SrcMgr::SLocEntry *, + DeclIDInFileInfo *> FileDeclIDsTy; + + /// \brief Map from file SLocEntries to info about the file-level declarations + /// that it contains. + FileDeclIDsTy FileDeclIDs; + + void associateDeclWithFile(const Decl *D, serialization::DeclID, + SourceLocation FileLoc); + /// \brief The first ID number we can use for our own types. serialization::TypeID FirstTypeID; @@ -354,6 +375,7 @@ private: uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); void WriteTypeDeclOffsets(); + void WriteFileDeclIDsMap(); void WriteSelectors(Sema &SemaRef); void WriteReferencedSelectorsPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, @@ -393,6 +415,7 @@ public: /// \brief Create a new precompiled header writer that outputs to /// the given bitstream. ASTWriter(llvm::BitstreamWriter &Stream); + ~ASTWriter(); /// \brief Write a precompiled header for the given semantic analysis. /// diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index 5c0cc9d2967dad95b659e303199990c8ea3d391b..43687f46ddef4e30cee5b7526199be0d99eb1c9e 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -271,6 +271,9 @@ public: /// Key is the ID of the interface. /// Value is a pair of linked category DeclIDs (head category, tail category). ChainedObjCCategoriesMap ChainedObjCCategories; + + /// \brief Array of file-level DeclIDs sorted by file. + const serialization::DeclID *FileSortedDecls; // === Types === diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 4678930702de993890dc613e62c3c4b7df301c42..8a1ae3da1aae7aecc5eab2a2e15650f6fe5bd25f 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1134,6 +1134,13 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { FileInfo.NumCreatedFIDs = Record[6]; if (Record[3]) FileInfo.setHasLineDirectives(); + + const DeclID *FirstDecl = F->FileSortedDecls + Record[7]; + unsigned NumFileDecls = Record[8]; + if (NumFileDecls) { + assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); + FileDeclIDs[FID] = llvm::makeArrayRef(FirstDecl, NumFileDecls); + } break; } @@ -1960,6 +1967,10 @@ ASTReader::ReadASTBlock(Module &F) { if (!Record.empty() && Listener) Listener->ReadCounter(Record[0]); break; + + case FILE_SORTED_DECLS: + F.FileSortedDecls = (const DeclID *)BlobStart; + break; case SOURCE_LOCATION_OFFSETS: { F.SLocEntryOffsets = (const uint32_t *)BlobStart; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 3f1a1d8ce8922611ffefc85e23afd9119ecdb5d0..749c27b1aa10c8cb122047c3089bbf20be16efaa 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1172,6 +1172,8 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name return Stream.EmitAbbrev(Abbrev); } @@ -1445,6 +1447,15 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(Content->OrigEntry->getModificationTime()); Record.push_back(File.NumCreatedFIDs); + + FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc); + if (FDI != FileDeclIDs.end()) { + Record.push_back(FDI->second->FirstDeclIndex); + Record.push_back(FDI->second->DeclIDs.size()); + } else { + Record.push_back(0); + Record.push_back(0); + } // Turn the file name into an absolute path, if it isn't already. const char *Filename = Content->OrigEntry->getName(); @@ -1972,6 +1983,29 @@ void ASTWriter::WriteTypeDeclOffsets() { Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets)); } +void ASTWriter::WriteFileDeclIDsMap() { + using namespace llvm; + RecordData Record; + + // Join the vectors of DeclIDs from all files. + SmallVector<DeclID, 256> FileSortedIDs; + for (FileDeclIDsTy::iterator + FI = FileDeclIDs.begin(), FE = FileDeclIDs.end(); FI != FE; ++FI) { + DeclIDInFileInfo &Info = *FI->second; + Info.FirstDeclIndex = FileSortedIDs.size(); + for (LocDeclIDsTy::iterator + DI = Info.DeclIDs.begin(), DE = Info.DeclIDs.end(); DI != DE; ++DI) + FileSortedIDs.push_back(DI->second); + } + + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + Record.push_back(FILE_SORTED_DECLS); + Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs)); +} + //===----------------------------------------------------------------------===// // Global Method Pool and Selector Serialization //===----------------------------------------------------------------------===// @@ -2732,6 +2766,12 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) { } +ASTWriter::~ASTWriter() { + for (FileDeclIDsTy::iterator + I = FileDeclIDs.begin(), E = FileDeclIDs.end(); I != E; ++I) + delete I->second; +} + void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, const std::string &OutputFile, bool IsModule, StringRef isysroot) { @@ -2910,49 +2950,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteLanguageOptions(Context.getLangOptions()); if (StatCalls && isysroot.empty()) WriteStatCache(*StatCalls); - WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - - if (Chain) { - // Write the mapping information describing our module dependencies and how - // each of those modules were mapped into our own offset/ID space, so that - // the reader can build the appropriate mapping to its own offset/ID space. - // The map consists solely of a blob with the following format: - // *(module-name-len:i16 module-name:len*i8 - // source-location-offset:i32 - // identifier-id:i32 - // preprocessed-entity-id:i32 - // macro-definition-id:i32 - // selector-id:i32 - // declaration-id:i32 - // c++-base-specifiers-id:i32 - // type-id:i32) - // - llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev); - llvm::SmallString<2048> Buffer; - { - llvm::raw_svector_ostream Out(Buffer); - for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(), - MEnd = Chain->ModuleMgr.end(); - M != MEnd; ++M) { - StringRef FileName = (*M)->FileName; - io::Emit16(Out, FileName.size()); - Out.write(FileName.data(), FileName.size()); - io::Emit32(Out, (*M)->SLocEntryBaseOffset); - io::Emit32(Out, (*M)->BaseIdentifierID); - io::Emit32(Out, (*M)->BasePreprocessedEntityID); - io::Emit32(Out, (*M)->BaseSelectorID); - io::Emit32(Out, (*M)->BaseDeclID); - io::Emit32(Out, (*M)->BaseTypeIndex); - } - } - Record.clear(); - Record.push_back(MODULE_OFFSET_MAP); - Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, - Buffer.data(), Buffer.size()); - } // Create a lexical update block containing all of the declarations in the // translation unit that do not come from other AST files. @@ -3030,6 +3027,51 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, } Stream.ExitBlock(); + WriteFileDeclIDsMap(); + WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); + + if (Chain) { + // Write the mapping information describing our module dependencies and how + // each of those modules were mapped into our own offset/ID space, so that + // the reader can build the appropriate mapping to its own offset/ID space. + // The map consists solely of a blob with the following format: + // *(module-name-len:i16 module-name:len*i8 + // source-location-offset:i32 + // identifier-id:i32 + // preprocessed-entity-id:i32 + // macro-definition-id:i32 + // selector-id:i32 + // declaration-id:i32 + // c++-base-specifiers-id:i32 + // type-id:i32) + // + llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev); + llvm::SmallString<2048> Buffer; + { + llvm::raw_svector_ostream Out(Buffer); + for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(), + MEnd = Chain->ModuleMgr.end(); + M != MEnd; ++M) { + StringRef FileName = (*M)->FileName; + io::Emit16(Out, FileName.size()); + Out.write(FileName.data(), FileName.size()); + io::Emit32(Out, (*M)->SLocEntryBaseOffset); + io::Emit32(Out, (*M)->BaseIdentifierID); + io::Emit32(Out, (*M)->BasePreprocessedEntityID); + io::Emit32(Out, (*M)->BaseSelectorID); + io::Emit32(Out, (*M)->BaseDeclID); + io::Emit32(Out, (*M)->BaseTypeIndex); + } + } + Record.clear(); + Record.push_back(MODULE_OFFSET_MAP); + Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, + Buffer.data(), Buffer.size()); + } + WritePreprocessor(PP, IsModule); WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); WriteSelectors(SemaRef); @@ -3439,6 +3481,48 @@ DeclID ASTWriter::getDeclID(const Decl *D) { return DeclIDs[D]; } +static inline bool compLocDecl(std::pair<unsigned, serialization::DeclID> L, + std::pair<unsigned, serialization::DeclID> R) { + return L.first < R.first; +} + +void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID, + SourceLocation FileLoc) { + assert(ID); + assert(FileLoc.isValid()); + assert(FileLoc.isFileID()); + + // We only keep track of the file-level declarations of each file. + if (!D->getLexicalDeclContext()->isFileContext()) + return; + + SourceManager &SM = Context->getSourceManager(); + assert(SM.isLocalSourceLocation(FileLoc)); + FileID FID = SM.getFileID(FileLoc); + if (FID.isInvalid()) + return; + const SrcMgr::SLocEntry *Entry = &SM.getSLocEntry(FID); + assert(Entry->isFile()); + + DeclIDInFileInfo *&Info = FileDeclIDs[Entry]; + if (!Info) + Info = new DeclIDInFileInfo(); + + unsigned RawLoc = FileLoc.getRawEncoding(); + std::pair<unsigned, serialization::DeclID> LocDecl(RawLoc, ID); + LocDeclIDsTy &Decls = Info->DeclIDs; + + if (Decls.empty() || Decls.back().first <= RawLoc) { + Decls.push_back(LocDecl); + return; + } + + LocDeclIDsTy::iterator + I = std::upper_bound(Decls.begin(), Decls.end(), LocDecl, compLocDecl); + + Decls.insert(I, LocDecl); +} + void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record) { // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc. Record.push_back(Name.getNameKind()); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 13cdd0ef2b6858bb080edffe8f8f06c54297772f..1b95e927f9ba992239ab13014e8550198466a802 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclContextInternals.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" @@ -1651,14 +1652,20 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { unsigned Index = ID - FirstDeclID; // Record the offset for this declaration + SourceLocation Loc = D->getLocation(); if (DeclOffsets.size() == Index) - DeclOffsets.push_back(DeclOffset(D->getLocation(), - Stream.GetCurrentBitNo())); + DeclOffsets.push_back(DeclOffset(Loc, Stream.GetCurrentBitNo())); else if (DeclOffsets.size() < Index) { DeclOffsets.resize(Index+1); - DeclOffsets[Index].setLocation(D->getLocation()); + DeclOffsets[Index].setLocation(Loc); DeclOffsets[Index].BitOffset = Stream.GetCurrentBitNo(); } + + SourceManager &SM = Context.getSourceManager(); + if (Loc.isValid() && SM.isLocalSourceLocation(Loc)) { + SourceLocation FileLoc = SM.getFileLoc(Loc); + associateDeclWithFile(D, ID, FileLoc); + } } // Build and emit a record for this declaration diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index 0a721c4365af2b7ab9f0b6b861f3115e5e0430dc..fd18fb7798f24c60e92e02137380ca620575b885 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -35,6 +35,7 @@ Module::Module(ModuleKind Kind) SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), DeclOffsets(0), BaseDeclID(0), LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), + FileSortedDecls(0), LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0) {}