/// \brief Non-owning reference to the ASTReader, if one exists.
ASTReader *ModuleManager;
- /// \brief A module that we have already attempted to load, which is known
- /// by either a file entry (FIXME: a temporary measure) or via its module
- /// definition.
- typedef llvm::PointerUnion<const FileEntry *, ModuleMap::Module *>
- KnownModule;
-
/// \brief The set of top-level modules that has already been loaded,
/// along with the module map
- llvm::DenseMap<const IdentifierInfo *, KnownModule> KnownModules;
+ llvm::DenseMap<const IdentifierInfo *, ModuleMap::Module *> KnownModules;
/// \brief The location of the module-import keyword for the last module
/// import.
/// \brief The result of the last module import.
///
- KnownModule LastModuleImportResult;
+ ModuleMap::Module *LastModuleImportResult;
/// \brief Holds information about the output file.
///
/// \returns The named module, if known; otherwise, returns null.
Module *findModule(StringRef Name);
+ /// \brief Find a new module or submodule, or create it if it does not already
+ /// exist.
+ ///
+ /// \param Name The name of the module to find or create.
+ ///
+ /// \param Parent The module that will act as the parent of this submodule,
+ /// or NULL to indicate that this is a top-level module.
+ ///
+ /// \param IsFramework Whether this is a framework module.
+ ///
+ /// \param IsExplicit Whether this is an explicit submodule.
+ ///
+ /// \returns The found or newly-created module, along with a boolean value
+ /// that will be true if the module is newly-created.
+ std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
+ bool IsFramework,
+ bool IsExplicit);
+
/// \brief Infer the contents of a framework module map from the given
/// framework directory.
Module *inferFrameworkModule(StringRef ModuleName,
DECL_UPDATES_BLOCK_ID,
/// \brief The block containing the detailed preprocessing record.
- PREPROCESSOR_DETAIL_BLOCK_ID
+ PREPROCESSOR_DETAIL_BLOCK_ID,
+
+ /// \brief The block containing the submodule structure.
+ SUBMODULE_BLOCK_ID
};
/// \brief Record types that occur within the AST block itself.
PPD_INCLUSION_DIRECTIVE = 2
};
+ /// \brief Record types used within a submodule description block.
+ enum SubmoduleRecordTypes {
+ /// \brief Defines the major attributes of a submodule, including its
+ /// name and parent.
+ SUBMODULE_DEFINITION = 0,
+ /// \brief Specifies the umbrella header used to create this module,
+ /// if any.
+ SUBMODULE_UMBRELLA = 1,
+ /// \brief Specifies a header that falls into this (sub)module.
+ SUBMODULE_HEADER = 2
+ };
+
/// \defgroup ASTAST AST file AST constants
///
/// The constants in this group describe various components of the
ASTReadResult ReadSLocEntryRecord(int ID);
llvm::BitstreamCursor &SLocCursorForID(int ID);
SourceLocation getImportLocation(Module *F);
+ ASTReadResult ReadSubmoduleBlock(Module &F);
bool ParseLanguageOptions(const SmallVectorImpl<uint64_t> &Record);
-
+
struct RecordLocation {
RecordLocation(Module *M, uint64_t O)
: F(M), Offset(O) {}
/// in the order they should be written.
SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite;
+ /// \brief A mapping from each known submodule to its ID number, which will
+ /// be a positive integer.
+ llvm::DenseMap<ModuleMap::Module *, unsigned> SubmoduleIDs;
+
/// \brief Write the given subexpression to the bitstream.
void WriteSubStmt(Stmt *S,
llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
void WritePreprocessor(const Preprocessor &PP, bool IsModule);
void WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot);
void WritePreprocessorDetail(PreprocessingRecord &PPRec);
+ void WriteSubmodules(ModuleMap::Module *WritingModule);
void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag);
void WriteCXXBaseSpecifiersOffsets();
void WriteType(QualType T);
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ContinuousRangeMap.h"
+#include "clang/Lex/ModuleMap.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SetVector.h"
/// search information.
const char *HeaderFileFrameworkStrings;
+ // === Submodule information ===
+ llvm::SmallVector<ModuleMap::Module *, 2> Submodules;
+
// === Selectors ===
/// \brief The number of selectors new to this file.
// This one-element cache is important to eliminate redundant diagnostics
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc)
- return LastModuleImportResult.getOpaqueValue();
+ return LastModuleImportResult;
// Determine what file we're searching from.
SourceManager &SourceMgr = getSourceManager();
const FileEntry *ModuleFile = 0;
// If we don't already have information on this module, load the module now.
- KnownModule &Known = KnownModules[Path[0].first];
- if (Known.isNull()) {
+ llvm::DenseMap<const IdentifierInfo *, ModuleMap::Module *>::iterator Known
+ = KnownModules.find(Path[0].first);
+ if (Known == KnownModules.end()) {
// Search for a module with the given name.
std::string ModuleFileName;
ModuleFile
case ASTReader::IgnorePCH:
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
+ KnownModules[Path[0].first] = 0;
return 0;
case ASTReader::Failure:
- // Already complained.
+ // Already complained, but note now that we failed.
+ KnownModules[Path[0].first] = 0;
return 0;
}
- if (Module)
- Known = Module;
- else
- Known = ModuleFile;
+ if (!Module) {
+ // If we loaded the module directly, without finding a module map first,
+ // we'll have loaded the module's information from the module itself.
+ Module = PP->getHeaderSearchInfo().getModuleMap()
+ .findModule((Path[0].first->getName()));
+ }
+
+ // Cache the result of this top-level module lookup for later.
+ Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
} else {
- Module = Known.dyn_cast<ModuleMap::Module *>();
+ // Retrieve the cached top-level module.
+ Module = Known->second;
}
+ // If we never found the module, fail.
+ if (!Module)
+ return 0;
+
// Verify that the rest of the module path actually corresponds to
// a submodule.
- ModuleMap::Module *Sub = 0;
- if (Module && Path.size() > 1) {
- Sub = Module;
+ if (Path.size() > 1) {
for (unsigned I = 1, N = Path.size(); I != N; ++I) {
StringRef Name = Path[I].first->getName();
llvm::StringMap<ModuleMap::Module *>::iterator Pos
- = Sub->SubModules.find(Name);
+ = Module->SubModules.find(Name);
- if (Pos == Sub->SubModules.end()) {
+ if (Pos == Module->SubModules.end()) {
// Attempt to perform typo correction to find a module name that works.
llvm::SmallVector<StringRef, 2> Best;
unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)();
for (llvm::StringMap<ModuleMap::Module *>::iterator
- I = Sub->SubModules.begin(),
- IEnd = Sub->SubModules.end();
+ I = Module->SubModules.begin(),
+ IEnd = Module->SubModules.end();
I != IEnd; ++I) {
unsigned ED = Name.edit_distance(I->getValue()->Name,
/*AllowReplacements=*/true,
if (Best.size() == 1) {
getDiagnostics().Report(Path[I].second,
diag::err_no_submodule_suggest)
- << Path[I].first << Sub->getFullModuleName() << Best[0]
+ << Path[I].first << Module->getFullModuleName() << Best[0]
<< SourceRange(Path[0].second, Path[I-1].second)
<< FixItHint::CreateReplacement(SourceRange(Path[I].second),
Best[0]);
- Pos = Sub->SubModules.find(Best[0]);
+ Pos = Module->SubModules.find(Best[0]);
}
}
- if (Pos == Sub->SubModules.end()) {
+ if (Pos == Module->SubModules.end()) {
// No submodule by this name. Complain, and don't look for further
// submodules.
getDiagnostics().Report(Path[I].second, diag::err_no_submodule)
- << Path[I].first << Sub->getFullModuleName()
+ << Path[I].first << Module->getFullModuleName()
<< SourceRange(Path[0].second, Path[I-1].second);
break;
}
- Sub = Pos->getValue();
+ Module = Pos->getValue();
}
}
// FIXME: Tell the AST reader to make the named submodule visible.
- // FIXME: The module file's FileEntry makes a poor key indeed! Once we
- // eliminate the need for FileEntry here, the module itself will become the
- // key (which does make sense).
LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = Known;
- return Known.getOpaqueValue();
+ LastModuleImportResult = Module;
+ return Module;
}
return 0;
}
+std::pair<ModuleMap::Module *, bool>
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+ bool IsExplicit) {
+ // Try to find an existing module with this name.
+ if (Module *Found = Parent? Parent->SubModules[Name] : Modules[Name])
+ return std::make_pair(Found, false);
+
+ // Create a new module with this name.
+ Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
+ IsExplicit);
+ if (Parent)
+ Parent->SubModules[Name] = Result;
+ else
+ Modules[Name] = Result;
+ return std::make_pair(Result, true);
+}
+
ModuleMap::Module *
ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir) {
return IgnorePCH;
}
break;
+
+ case SUBMODULE_BLOCK_ID:
+ switch (ReadSubmoduleBlock(F)) {
+ case Success:
+ break;
+
+ case Failure:
+ Error("malformed submodule block in AST file");
+ return Failure;
+
+ case IgnorePCH:
+ return IgnorePCH;
+ }
+ break;
+
+ default:
+ if (!Stream.SkipBlock())
+ break;
+ Error("malformed block record in AST file");
+ return Failure;
}
continue;
}
return std::string();
}
+ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(Module &F) {
+ // Enter the submodule block.
+ if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
+ Error("malformed submodule block record in AST file");
+ return Failure;
+ }
+
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ ModuleMap::Module *CurrentModule = 0;
+ RecordData Record;
+ while (true) {
+ unsigned Code = F.Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (F.Stream.ReadBlockEnd()) {
+ Error("error at end of submodule block in AST file");
+ return Failure;
+ }
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ F.Stream.ReadSubBlockID();
+ if (F.Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ F.Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SUBMODULE_DEFINITION: {
+ StringRef Name(BlobStart, BlobLen);
+ unsigned Parent = Record[0];
+ bool IsFramework = Record[1];
+ bool IsExplicit = Record[2];
+
+ ModuleMap::Module *ParentModule = 0;
+ if (Parent) {
+ if (Parent > F.Submodules.size()) {
+ Error("malformed submodule parent entry");
+ return Failure;
+ }
+
+ ParentModule = F.Submodules[Parent - 1];
+ }
+
+ // Retrieve this (sub)module from the module map, creating it if
+ // necessary.
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
+ IsFramework,
+ IsExplicit).first;
+ F.Submodules.push_back(CurrentModule);
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA: {
+ if (!CurrentModule)
+ break;
+
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
+ if (!CurrentModule->UmbrellaHeader)
+ CurrentModule->UmbrellaHeader = Umbrella;
+ else if (CurrentModule->UmbrellaHeader != Umbrella) {
+ Error("mismatched umbrella headers in submodule");
+ return Failure;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_HEADER: {
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
+ if (std::find(CurrentModule->Headers.begin(),
+ CurrentModule->Headers.end(),
+ File) == CurrentModule->Headers.end())
+ CurrentModule->Headers.push_back(File);
+ }
+ break;
+ }
+ }
+ }
+
+ return Success;
+}
+
/// \brief Parse the record that corresponds to a LangOptions data
/// structure.
///
}
}
+void ASTWriter::WriteSubmodules(ModuleMap::Module *WritingModule) {
+ // Enter the submodule description block.
+ Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
+
+ // Write the abbreviations needed for the submodules block.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write all of the submodules.
+ unsigned SubmoduleID = 1;
+ std::queue<ModuleMap::Module *> Q;
+ Q.push(WritingModule);
+ RecordData Record;
+ while (!Q.empty()) {
+ ModuleMap::Module *Mod = Q.front();
+ Q.pop();
+ SubmoduleIDs[Mod] = SubmoduleID++;
+
+ // Emit the definition of the block.
+ Record.clear();
+ Record.push_back(SUBMODULE_DEFINITION);
+ if (Mod->Parent) {
+ assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
+ Record.push_back(SubmoduleIDs[Mod->Parent]);
+ } else {
+ Record.push_back(0);
+ }
+ Record.push_back(Mod->IsFramework);
+ Record.push_back(Mod->IsExplicit);
+ Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
+
+ // Emit the umbrella header, if there is one.
+ if (Mod->UmbrellaHeader) {
+ Record.clear();
+ Record.push_back(SUBMODULE_UMBRELLA);
+ Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,
+ Mod->UmbrellaHeader->getName());
+ }
+
+ // Emit the headers.
+ for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_HEADER);
+ Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
+ Mod->Headers[I]->getName());
+ }
+
+ // Queue up the submodules of this module.
+ llvm::SmallVector<StringRef, 2> SubModules;
+
+ // Sort the submodules first, so we get a predictable ordering in the AST
+ // file.
+ for (llvm::StringMap<ModuleMap::Module *>::iterator
+ Sub = Mod->SubModules.begin(),
+ SubEnd = Mod->SubModules.end();
+ Sub != SubEnd; ++Sub)
+ SubModules.push_back(Sub->getKey());
+ llvm::array_pod_sort(SubModules.begin(), SubModules.end());
+
+ for (unsigned I = 0, N = SubModules.size(); I != N; ++I)
+ Q.push(Mod->SubModules[SubModules[I]]);
+ }
+
+ Stream.ExitBlock();
+}
+
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
RecordData Record;
for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
Buffer.data(), Buffer.size());
}
-
+ if (WritingModule)
+ WriteSubmodules(WritingModule);
WritePreprocessor(PP, WritingModule != 0);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);