| //===--- ModuleMap.cpp - Describe the layout of modules ---------*- C++ -*-===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file defines the ModuleMap implementation, which describes the layout | 
 | // of a module as it relates to headers. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | #include "clang/Lex/ModuleMap.h" | 
 | #include "clang/Basic/CharInfo.h" | 
 | #include "clang/Basic/Diagnostic.h" | 
 | #include "clang/Basic/DiagnosticOptions.h" | 
 | #include "clang/Basic/FileManager.h" | 
 | #include "clang/Basic/TargetInfo.h" | 
 | #include "clang/Basic/TargetOptions.h" | 
 | #include "clang/Lex/HeaderSearch.h" | 
 | #include "clang/Lex/LexDiagnostic.h" | 
 | #include "clang/Lex/Lexer.h" | 
 | #include "clang/Lex/LiteralSupport.h" | 
 | #include "llvm/ADT/StringRef.h" | 
 | #include "llvm/ADT/StringSwitch.h" | 
 | #include "llvm/Support/Allocator.h" | 
 | #include "llvm/Support/FileSystem.h" | 
 | #include "llvm/Support/Host.h" | 
 | #include "llvm/Support/Path.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | #include <stdlib.h> | 
 | #if defined(LLVM_ON_UNIX) | 
 | #include <limits.h> | 
 | #endif | 
 | using namespace clang; | 
 |  | 
 | Module::ExportDecl  | 
 | ModuleMap::resolveExport(Module *Mod,  | 
 |                          const Module::UnresolvedExportDecl &Unresolved, | 
 |                          bool Complain) const { | 
 |   // We may have just a wildcard. | 
 |   if (Unresolved.Id.empty()) { | 
 |     assert(Unresolved.Wildcard && "Invalid unresolved export"); | 
 |     return Module::ExportDecl(nullptr, true); | 
 |   } | 
 |    | 
 |   // Resolve the module-id. | 
 |   Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain); | 
 |   if (!Context) | 
 |     return Module::ExportDecl(); | 
 |  | 
 |   return Module::ExportDecl(Context, Unresolved.Wildcard); | 
 | } | 
 |  | 
 | Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, | 
 |                                    bool Complain) const { | 
 |   // Find the starting module. | 
 |   Module *Context = lookupModuleUnqualified(Id[0].first, Mod); | 
 |   if (!Context) { | 
 |     if (Complain) | 
 |       Diags.Report(Id[0].second, diag::err_mmap_missing_module_unqualified) | 
 |       << Id[0].first << Mod->getFullModuleName(); | 
 |  | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Dig into the module path. | 
 |   for (unsigned I = 1, N = Id.size(); I != N; ++I) { | 
 |     Module *Sub = lookupModuleQualified(Id[I].first, Context); | 
 |     if (!Sub) { | 
 |       if (Complain) | 
 |         Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified) | 
 |         << Id[I].first << Context->getFullModuleName() | 
 |         << SourceRange(Id[0].second, Id[I-1].second); | 
 |  | 
 |       return nullptr; | 
 |     } | 
 |  | 
 |     Context = Sub; | 
 |   } | 
 |  | 
 |   return Context; | 
 | } | 
 |  | 
 | ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, | 
 |                      const LangOptions &LangOpts, const TargetInfo *Target, | 
 |                      HeaderSearch &HeaderInfo) | 
 |     : SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target), | 
 |       HeaderInfo(HeaderInfo), BuiltinIncludeDir(nullptr), | 
 |       CompilingModule(nullptr), SourceModule(nullptr) {} | 
 |  | 
 | ModuleMap::~ModuleMap() { | 
 |   for (llvm::StringMap<Module *>::iterator I = Modules.begin(),  | 
 |                                         IEnd = Modules.end(); | 
 |        I != IEnd; ++I) { | 
 |     delete I->getValue(); | 
 |   } | 
 | } | 
 |  | 
 | void ModuleMap::setTarget(const TargetInfo &Target) { | 
 |   assert((!this->Target || this->Target == &Target) &&  | 
 |          "Improper target override"); | 
 |   this->Target = &Target; | 
 | } | 
 |  | 
 | /// \brief "Sanitize" a filename so that it can be used as an identifier. | 
 | static StringRef sanitizeFilenameAsIdentifier(StringRef Name, | 
 |                                               SmallVectorImpl<char> &Buffer) { | 
 |   if (Name.empty()) | 
 |     return Name; | 
 |  | 
 |   if (!isValidIdentifier(Name)) { | 
 |     // If we don't already have something with the form of an identifier, | 
 |     // create a buffer with the sanitized name. | 
 |     Buffer.clear(); | 
 |     if (isDigit(Name[0])) | 
 |       Buffer.push_back('_'); | 
 |     Buffer.reserve(Buffer.size() + Name.size()); | 
 |     for (unsigned I = 0, N = Name.size(); I != N; ++I) { | 
 |       if (isIdentifierBody(Name[I])) | 
 |         Buffer.push_back(Name[I]); | 
 |       else | 
 |         Buffer.push_back('_'); | 
 |     } | 
 |  | 
 |     Name = StringRef(Buffer.data(), Buffer.size()); | 
 |   } | 
 |  | 
 |   while (llvm::StringSwitch<bool>(Name) | 
 | #define KEYWORD(Keyword,Conditions) .Case(#Keyword, true) | 
 | #define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true) | 
 | #include "clang/Basic/TokenKinds.def" | 
 |            .Default(false)) { | 
 |     if (Name.data() != Buffer.data()) | 
 |       Buffer.append(Name.begin(), Name.end()); | 
 |     Buffer.push_back('_'); | 
 |     Name = StringRef(Buffer.data(), Buffer.size()); | 
 |   } | 
 |  | 
 |   return Name; | 
 | } | 
 |  | 
 | /// \brief Determine whether the given file name is the name of a builtin | 
 | /// header, supplied by Clang to replace, override, or augment existing system | 
 | /// headers. | 
 | static bool isBuiltinHeader(StringRef FileName) { | 
 |   return llvm::StringSwitch<bool>(FileName) | 
 |            .Case("float.h", true) | 
 |            .Case("iso646.h", true) | 
 |            .Case("limits.h", true) | 
 |            .Case("stdalign.h", true) | 
 |            .Case("stdarg.h", true) | 
 |            .Case("stdbool.h", true) | 
 |            .Case("stddef.h", true) | 
 |            .Case("stdint.h", true) | 
 |            .Case("tgmath.h", true) | 
 |            .Case("unwind.h", true) | 
 |            .Default(false); | 
 | } | 
 |  | 
 | ModuleMap::HeadersMap::iterator | 
 | ModuleMap::findKnownHeader(const FileEntry *File) { | 
 |   HeadersMap::iterator Known = Headers.find(File); | 
 |   if (Known == Headers.end() && File->getDir() == BuiltinIncludeDir && | 
 |       isBuiltinHeader(llvm::sys::path::filename(File->getName()))) { | 
 |     HeaderInfo.loadTopLevelSystemModules(); | 
 |     return Headers.find(File); | 
 |   } | 
 |   return Known; | 
 | } | 
 |  | 
 | ModuleMap::KnownHeader | 
 | ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File, | 
 |                     SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs) { | 
 |   const DirectoryEntry *Dir = File->getDir(); | 
 |   assert(Dir && "file in no directory"); | 
 |  | 
 |   // Note: as an egregious but useful hack we use the real path here, because | 
 |   // frameworks moving from top-level frameworks to embedded frameworks tend | 
 |   // to be symlinked from the top-level location to the embedded location, | 
 |   // and we need to resolve lookups as if we had found the embedded location. | 
 |   StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir); | 
 |  | 
 |   // Keep walking up the directory hierarchy, looking for a directory with | 
 |   // an umbrella header. | 
 |   do { | 
 |     auto KnownDir = UmbrellaDirs.find(Dir); | 
 |     if (KnownDir != UmbrellaDirs.end()) | 
 |       return KnownHeader(KnownDir->second, NormalHeader); | 
 |  | 
 |     IntermediateDirs.push_back(Dir); | 
 |  | 
 |     // Retrieve our parent path. | 
 |     DirName = llvm::sys::path::parent_path(DirName); | 
 |     if (DirName.empty()) | 
 |       break; | 
 |  | 
 |     // Resolve the parent path to a directory entry. | 
 |     Dir = SourceMgr.getFileManager().getDirectory(DirName); | 
 |   } while (Dir); | 
 |   return KnownHeader(); | 
 | } | 
 |  | 
 | // Returns 'true' if 'RequestingModule directly uses 'RequestedModule'. | 
 | static bool directlyUses(const Module *RequestingModule, | 
 |                          const Module *RequestedModule) { | 
 |   return std::find(RequestingModule->DirectUses.begin(), | 
 |                    RequestingModule->DirectUses.end(), | 
 |                    RequestedModule) != RequestingModule->DirectUses.end(); | 
 | } | 
 |  | 
 | static bool violatesPrivateInclude(Module *RequestingModule, | 
 |                                    const FileEntry *IncFileEnt, | 
 |                                    ModuleMap::ModuleHeaderRole Role, | 
 |                                    Module *RequestedModule) { | 
 |   #ifndef NDEBUG | 
 |   // Check for consistency between the module header role | 
 |   // as obtained from the lookup and as obtained from the module. | 
 |   // This check is not cheap, so enable it only for debugging. | 
 |   SmallVectorImpl<const FileEntry *> &PvtHdrs | 
 |       = RequestedModule->PrivateHeaders; | 
 |   SmallVectorImpl<const FileEntry *>::iterator Look | 
 |       = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt); | 
 |   bool IsPrivate = Look != PvtHdrs.end(); | 
 |   assert((IsPrivate && Role == ModuleMap::PrivateHeader) | 
 |                || (!IsPrivate && Role != ModuleMap::PrivateHeader)); | 
 |   #endif | 
 |   return Role == ModuleMap::PrivateHeader && | 
 |          RequestedModule->getTopLevelModule() != RequestingModule; | 
 | } | 
 |  | 
 | static Module *getTopLevelOrNull(Module *M) { | 
 |   return M ? M->getTopLevelModule() : nullptr; | 
 | } | 
 |  | 
 | void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule, | 
 |                                         SourceLocation FilenameLoc, | 
 |                                         StringRef Filename, | 
 |                                         const FileEntry *File) { | 
 |   // No errors for indirect modules. This may be a bit of a problem for modules | 
 |   // with no source files. | 
 |   if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule)) | 
 |     return; | 
 |  | 
 |   if (RequestingModule) | 
 |     resolveUses(RequestingModule, /*Complain=*/false); | 
 |  | 
 |   bool Excluded = false; | 
 |   Module *Private = nullptr; | 
 |   Module *NotUsed = nullptr; | 
 |  | 
 |   HeadersMap::iterator Known = findKnownHeader(File); | 
 |   if (Known != Headers.end()) { | 
 |     for (const KnownHeader &Header : Known->second) { | 
 |       // Excluded headers don't really belong to a module. | 
 |       if (Header.getRole() == ModuleMap::ExcludedHeader) { | 
 |         Excluded = true; | 
 |         continue; | 
 |       } | 
 |  | 
 |       // If 'File' is part of 'RequestingModule' we can definitely include it. | 
 |       if (Header.getModule() == RequestingModule) | 
 |         return; | 
 |  | 
 |       // Remember private headers for later printing of a diagnostic. | 
 |       if (violatesPrivateInclude(RequestingModule, File, Header.getRole(), | 
 |                                  Header.getModule())) { | 
 |         Private = Header.getModule(); | 
 |         continue; | 
 |       } | 
 |  | 
 |       // If uses need to be specified explicitly, we are only allowed to return | 
 |       // modules that are explicitly used by the requesting module. | 
 |       if (RequestingModule && LangOpts.ModulesDeclUse && | 
 |           !directlyUses(RequestingModule, Header.getModule())) { | 
 |         NotUsed = Header.getModule(); | 
 |         continue; | 
 |       } | 
 |  | 
 |       // We have found a module that we can happily use. | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   // We have found a header, but it is private. | 
 |   if (Private) { | 
 |     Diags.Report(FilenameLoc, diag::error_use_of_private_header_outside_module) | 
 |         << Filename; | 
 |     return; | 
 |   } | 
 |  | 
 |   // We have found a module, but we don't use it. | 
 |   if (NotUsed) { | 
 |     Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module) | 
 |         << RequestingModule->getFullModuleName() << Filename; | 
 |     return; | 
 |   } | 
 |  | 
 |   if (Excluded || isHeaderInUmbrellaDirs(File)) | 
 |     return; | 
 |  | 
 |   // At this point, only non-modular includes remain. | 
 |  | 
 |   if (LangOpts.ModulesStrictDeclUse) { | 
 |     Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module) | 
 |         << RequestingModule->getFullModuleName() << Filename; | 
 |   } else if (RequestingModule) { | 
 |     diag::kind DiagID = RequestingModule->getTopLevelModule()->IsFramework ? | 
 |         diag::warn_non_modular_include_in_framework_module : | 
 |         diag::warn_non_modular_include_in_module; | 
 |     Diags.Report(FilenameLoc, DiagID) << RequestingModule->getFullModuleName(); | 
 |   } | 
 | } | 
 |  | 
 | ModuleMap::KnownHeader | 
 | ModuleMap::findModuleForHeader(const FileEntry *File, | 
 |                                Module *RequestingModule) { | 
 |   HeadersMap::iterator Known = findKnownHeader(File); | 
 |  | 
 |   if (Known != Headers.end()) { | 
 |     ModuleMap::KnownHeader Result = KnownHeader(); | 
 |  | 
 |     // Iterate over all modules that 'File' is part of to find the best fit. | 
 |     for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(), | 
 |                                                 E = Known->second.end(); | 
 |          I != E; ++I) { | 
 |       // Cannot use a module if the header is excluded in it. | 
 |       if (I->getRole() == ModuleMap::ExcludedHeader) | 
 |         continue; | 
 |  | 
 |       // Cannot use a module if it is unavailable. | 
 |       if (!I->getModule()->isAvailable()) | 
 |         continue; | 
 |  | 
 |       // If 'File' is part of 'RequestingModule', 'RequestingModule' is the | 
 |       // module we are looking for. | 
 |       if (I->getModule() == RequestingModule) | 
 |         return *I; | 
 |  | 
 |       // If uses need to be specified explicitly, we are only allowed to return | 
 |       // modules that are explicitly used by the requesting module. | 
 |       if (RequestingModule && LangOpts.ModulesDeclUse && | 
 |           !directlyUses(RequestingModule, I->getModule())) | 
 |         continue; | 
 |  | 
 |       Result = *I; | 
 |       // If 'File' is a public header of this module, this is as good as we | 
 |       // are going to get. | 
 |       // FIXME: If we have a RequestingModule, we should prefer the header from | 
 |       // that module. | 
 |       if (I->getRole() == ModuleMap::NormalHeader) | 
 |         break; | 
 |     } | 
 |     return Result; | 
 |   } | 
 |  | 
 |   SmallVector<const DirectoryEntry *, 2> SkippedDirs; | 
 |   KnownHeader H = findHeaderInUmbrellaDirs(File, SkippedDirs); | 
 |   if (H) { | 
 |     Module *Result = H.getModule(); | 
 |  | 
 |     // Search up the module stack until we find a module with an umbrella | 
 |     // directory. | 
 |     Module *UmbrellaModule = Result; | 
 |     while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent) | 
 |       UmbrellaModule = UmbrellaModule->Parent; | 
 |  | 
 |     if (UmbrellaModule->InferSubmodules) { | 
 |       // Infer submodules for each of the directories we found between | 
 |       // the directory of the umbrella header and the directory where | 
 |       // the actual header is located. | 
 |       bool Explicit = UmbrellaModule->InferExplicitSubmodules; | 
 |  | 
 |       for (unsigned I = SkippedDirs.size(); I != 0; --I) { | 
 |         // Find or create the module that corresponds to this directory name. | 
 |         SmallString<32> NameBuf; | 
 |         StringRef Name = sanitizeFilenameAsIdentifier( | 
 |             llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf); | 
 |         Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap, | 
 |                                     /*IsFramework=*/false, Explicit).first; | 
 |         Result->IsInferred = true; | 
 |  | 
 |         // Associate the module and the directory. | 
 |         UmbrellaDirs[SkippedDirs[I-1]] = Result; | 
 |  | 
 |         // If inferred submodules export everything they import, add a | 
 |         // wildcard to the set of exports. | 
 |         if (UmbrellaModule->InferExportWildcard && Result->Exports.empty()) | 
 |           Result->Exports.push_back(Module::ExportDecl(nullptr, true)); | 
 |       } | 
 |  | 
 |       // Infer a submodule with the same name as this header file. | 
 |       SmallString<32> NameBuf; | 
 |       StringRef Name = sanitizeFilenameAsIdentifier( | 
 |                          llvm::sys::path::stem(File->getName()), NameBuf); | 
 |       Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap, | 
 |                                   /*IsFramework=*/false, Explicit).first; | 
 |       Result->IsInferred = true; | 
 |       Result->addTopHeader(File); | 
 |  | 
 |       // If inferred submodules export everything they import, add a | 
 |       // wildcard to the set of exports. | 
 |       if (UmbrellaModule->InferExportWildcard && Result->Exports.empty()) | 
 |         Result->Exports.push_back(Module::ExportDecl(nullptr, true)); | 
 |     } else { | 
 |       // Record each of the directories we stepped through as being part of | 
 |       // the module we found, since the umbrella header covers them all. | 
 |       for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I) | 
 |         UmbrellaDirs[SkippedDirs[I]] = Result; | 
 |     } | 
 |  | 
 |     Headers[File].push_back(KnownHeader(Result, NormalHeader)); | 
 |  | 
 |     // If a header corresponds to an unavailable module, don't report | 
 |     // that it maps to anything. | 
 |     if (!Result->isAvailable()) | 
 |       return KnownHeader(); | 
 |  | 
 |     return Headers[File].back(); | 
 |   } | 
 |    | 
 |   return KnownHeader(); | 
 | } | 
 |  | 
 | bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const { | 
 |   return isHeaderUnavailableInModule(Header, nullptr); | 
 | } | 
 |  | 
 | bool | 
 | ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header, | 
 |                                        const Module *RequestingModule) const { | 
 |   HeadersMap::const_iterator Known = Headers.find(Header); | 
 |   if (Known != Headers.end()) { | 
 |     for (SmallVectorImpl<KnownHeader>::const_iterator | 
 |              I = Known->second.begin(), | 
 |              E = Known->second.end(); | 
 |          I != E; ++I) { | 
 |       if (I->isAvailable() && (!RequestingModule || | 
 |                                I->getModule()->isSubModuleOf(RequestingModule))) | 
 |         return false; | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |   const DirectoryEntry *Dir = Header->getDir(); | 
 |   SmallVector<const DirectoryEntry *, 2> SkippedDirs; | 
 |   StringRef DirName = Dir->getName(); | 
 |  | 
 |   auto IsUnavailable = [&](const Module *M) { | 
 |     return !M->isAvailable() && (!RequestingModule || | 
 |                                  M->isSubModuleOf(RequestingModule)); | 
 |   }; | 
 |  | 
 |   // Keep walking up the directory hierarchy, looking for a directory with | 
 |   // an umbrella header. | 
 |   do { | 
 |     llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir | 
 |       = UmbrellaDirs.find(Dir); | 
 |     if (KnownDir != UmbrellaDirs.end()) { | 
 |       Module *Found = KnownDir->second; | 
 |       if (IsUnavailable(Found)) | 
 |         return true; | 
 |  | 
 |       // Search up the module stack until we find a module with an umbrella | 
 |       // directory. | 
 |       Module *UmbrellaModule = Found; | 
 |       while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent) | 
 |         UmbrellaModule = UmbrellaModule->Parent; | 
 |  | 
 |       if (UmbrellaModule->InferSubmodules) { | 
 |         for (unsigned I = SkippedDirs.size(); I != 0; --I) { | 
 |           // Find or create the module that corresponds to this directory name. | 
 |           SmallString<32> NameBuf; | 
 |           StringRef Name = sanitizeFilenameAsIdentifier( | 
 |                              llvm::sys::path::stem(SkippedDirs[I-1]->getName()), | 
 |                              NameBuf); | 
 |           Found = lookupModuleQualified(Name, Found); | 
 |           if (!Found) | 
 |             return false; | 
 |           if (IsUnavailable(Found)) | 
 |             return true; | 
 |         } | 
 |          | 
 |         // Infer a submodule with the same name as this header file. | 
 |         SmallString<32> NameBuf; | 
 |         StringRef Name = sanitizeFilenameAsIdentifier( | 
 |                            llvm::sys::path::stem(Header->getName()), | 
 |                            NameBuf); | 
 |         Found = lookupModuleQualified(Name, Found); | 
 |         if (!Found) | 
 |           return false; | 
 |       } | 
 |  | 
 |       return IsUnavailable(Found); | 
 |     } | 
 |      | 
 |     SkippedDirs.push_back(Dir); | 
 |      | 
 |     // Retrieve our parent path. | 
 |     DirName = llvm::sys::path::parent_path(DirName); | 
 |     if (DirName.empty()) | 
 |       break; | 
 |      | 
 |     // Resolve the parent path to a directory entry. | 
 |     Dir = SourceMgr.getFileManager().getDirectory(DirName); | 
 |   } while (Dir); | 
 |    | 
 |   return false; | 
 | } | 
 |  | 
 | Module *ModuleMap::findModule(StringRef Name) const { | 
 |   llvm::StringMap<Module *>::const_iterator Known = Modules.find(Name); | 
 |   if (Known != Modules.end()) | 
 |     return Known->getValue(); | 
 |  | 
 |   return nullptr; | 
 | } | 
 |  | 
 | Module *ModuleMap::lookupModuleUnqualified(StringRef Name, | 
 |                                            Module *Context) const { | 
 |   for(; Context; Context = Context->Parent) { | 
 |     if (Module *Sub = lookupModuleQualified(Name, Context)) | 
 |       return Sub; | 
 |   } | 
 |    | 
 |   return findModule(Name); | 
 | } | 
 |  | 
 | Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{ | 
 |   if (!Context) | 
 |     return findModule(Name); | 
 |    | 
 |   return Context->findSubmodule(Name); | 
 | } | 
 |  | 
 | std::pair<Module *, bool>  | 
 | ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, | 
 |                               const FileEntry *ModuleMap, bool IsFramework, | 
 |                               bool IsExplicit) { | 
 |   // Try to find an existing module with this name. | 
 |   if (Module *Sub = lookupModuleQualified(Name, Parent)) | 
 |     return std::make_pair(Sub, false); | 
 |    | 
 |   // Create a new module with this name. | 
 |   Module *Result = new Module(Name, SourceLocation(), Parent, ModuleMap, | 
 |                               IsFramework, IsExplicit); | 
 |   if (LangOpts.CurrentModule == Name) { | 
 |     SourceModule = Result; | 
 |     SourceModuleName = Name; | 
 |   } | 
 |   if (!Parent) { | 
 |     Modules[Name] = Result; | 
 |     if (!LangOpts.CurrentModule.empty() && !CompilingModule && | 
 |         Name == LangOpts.CurrentModule) { | 
 |       CompilingModule = Result; | 
 |     } | 
 |   } | 
 |   return std::make_pair(Result, true); | 
 | } | 
 |  | 
 | bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir, | 
 |                                         StringRef Name, bool &IsSystem) const { | 
 |   // Check whether we have already looked into the parent directory | 
 |   // for a module map. | 
 |   llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator | 
 |     inferred = InferredDirectories.find(ParentDir); | 
 |   if (inferred == InferredDirectories.end()) | 
 |     return false; | 
 |  | 
 |   if (!inferred->second.InferModules) | 
 |     return false; | 
 |  | 
 |   // We're allowed to infer for this directory, but make sure it's okay | 
 |   // to infer this particular module. | 
 |   bool canInfer = std::find(inferred->second.ExcludedModules.begin(), | 
 |                             inferred->second.ExcludedModules.end(), | 
 |                             Name) == inferred->second.ExcludedModules.end(); | 
 |  | 
 |   if (canInfer && inferred->second.InferSystemModules) | 
 |     IsSystem = true; | 
 |  | 
 |   return canInfer; | 
 | } | 
 |  | 
 | /// \brief For a framework module, infer the framework against which we | 
 | /// should link. | 
 | static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir, | 
 |                                FileManager &FileMgr) { | 
 |   assert(Mod->IsFramework && "Can only infer linking for framework modules"); | 
 |   assert(!Mod->isSubFramework() && | 
 |          "Can only infer linking for top-level frameworks"); | 
 |  | 
 |   SmallString<128> LibName; | 
 |   LibName += FrameworkDir->getName(); | 
 |   llvm::sys::path::append(LibName, Mod->Name); | 
 |   if (FileMgr.getFile(LibName)) { | 
 |     Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name, | 
 |                                                      /*IsFramework=*/true)); | 
 |   } | 
 | } | 
 |  | 
 | Module * | 
 | ModuleMap::inferFrameworkModule(StringRef ModuleName, | 
 |                                 const DirectoryEntry *FrameworkDir, | 
 |                                 bool IsSystem, | 
 |                                 Module *Parent) { | 
 |   // Check whether we've already found this module. | 
 |   if (Module *Mod = lookupModuleQualified(ModuleName, Parent)) | 
 |     return Mod; | 
 |    | 
 |   FileManager &FileMgr = SourceMgr.getFileManager(); | 
 |  | 
 |   // If the framework has a parent path from which we're allowed to infer | 
 |   // a framework module, do so. | 
 |   const FileEntry *ModuleMapFile = nullptr; | 
 |   if (!Parent) { | 
 |     // Determine whether we're allowed to infer a module map. | 
 |  | 
 |     // Note: as an egregious but useful hack we use the real path here, because | 
 |     // we might be looking at an embedded framework that symlinks out to a | 
 |     // top-level framework, and we need to infer as if we were naming the | 
 |     // top-level framework. | 
 |     StringRef FrameworkDirName | 
 |       = SourceMgr.getFileManager().getCanonicalName(FrameworkDir); | 
 |  | 
 |     bool canInfer = false; | 
 |     if (llvm::sys::path::has_parent_path(FrameworkDirName)) { | 
 |       // Figure out the parent path. | 
 |       StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName); | 
 |       if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) { | 
 |         // Check whether we have already looked into the parent directory | 
 |         // for a module map. | 
 |         llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator | 
 |           inferred = InferredDirectories.find(ParentDir); | 
 |         if (inferred == InferredDirectories.end()) { | 
 |           // We haven't looked here before. Load a module map, if there is | 
 |           // one. | 
 |           bool IsFrameworkDir = Parent.endswith(".framework"); | 
 |           if (const FileEntry *ModMapFile = | 
 |                 HeaderInfo.lookupModuleMapFile(ParentDir, IsFrameworkDir)) { | 
 |             parseModuleMapFile(ModMapFile, IsSystem); | 
 |             inferred = InferredDirectories.find(ParentDir); | 
 |           } | 
 |  | 
 |           if (inferred == InferredDirectories.end()) | 
 |             inferred = InferredDirectories.insert( | 
 |                          std::make_pair(ParentDir, InferredDirectory())).first; | 
 |         } | 
 |  | 
 |         if (inferred->second.InferModules) { | 
 |           // We're allowed to infer for this directory, but make sure it's okay | 
 |           // to infer this particular module. | 
 |           StringRef Name = llvm::sys::path::stem(FrameworkDirName); | 
 |           canInfer = std::find(inferred->second.ExcludedModules.begin(), | 
 |                                inferred->second.ExcludedModules.end(), | 
 |                                Name) == inferred->second.ExcludedModules.end(); | 
 |  | 
 |           if (inferred->second.InferSystemModules) | 
 |             IsSystem = true; | 
 |           ModuleMapFile = inferred->second.ModuleMapFile; | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     // If we're not allowed to infer a framework module, don't. | 
 |     if (!canInfer) | 
 |       return nullptr; | 
 |   } else | 
 |     ModuleMapFile = Parent->ModuleMap; | 
 |  | 
 |  | 
 |   // Look for an umbrella header. | 
 |   SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); | 
 |   llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h"); | 
 |   const FileEntry *UmbrellaHeader = FileMgr.getFile(UmbrellaName); | 
 |    | 
 |   // FIXME: If there's no umbrella header, we could probably scan the | 
 |   // framework to load *everything*. But, it's not clear that this is a good | 
 |   // idea. | 
 |   if (!UmbrellaHeader) | 
 |     return nullptr; | 
 |  | 
 |   Module *Result = new Module(ModuleName, SourceLocation(), Parent, ModuleMapFile, | 
 |                               /*IsFramework=*/true, /*IsExplicit=*/false); | 
 |   if (LangOpts.CurrentModule == ModuleName) { | 
 |     SourceModule = Result; | 
 |     SourceModuleName = ModuleName; | 
 |   } | 
 |   if (IsSystem) | 
 |     Result->IsSystem = IsSystem; | 
 |    | 
 |   if (!Parent) | 
 |     Modules[ModuleName] = Result; | 
 |    | 
 |   // umbrella header "umbrella-header-name" | 
 |   Result->Umbrella = UmbrellaHeader; | 
 |   Headers[UmbrellaHeader].push_back(KnownHeader(Result, NormalHeader)); | 
 |   UmbrellaDirs[UmbrellaHeader->getDir()] = Result; | 
 |    | 
 |   // export * | 
 |   Result->Exports.push_back(Module::ExportDecl(nullptr, true)); | 
 |  | 
 |   // module * { export * } | 
 |   Result->InferSubmodules = true; | 
 |   Result->InferExportWildcard = true; | 
 |    | 
 |   // Look for subframeworks. | 
 |   std::error_code EC; | 
 |   SmallString<128> SubframeworksDirName | 
 |     = StringRef(FrameworkDir->getName()); | 
 |   llvm::sys::path::append(SubframeworksDirName, "Frameworks"); | 
 |   llvm::sys::path::native(SubframeworksDirName); | 
 |   for (llvm::sys::fs::directory_iterator  | 
 |          Dir(SubframeworksDirName.str(), EC), DirEnd; | 
 |        Dir != DirEnd && !EC; Dir.increment(EC)) { | 
 |     if (!StringRef(Dir->path()).endswith(".framework")) | 
 |       continue; | 
 |  | 
 |     if (const DirectoryEntry *SubframeworkDir | 
 |           = FileMgr.getDirectory(Dir->path())) { | 
 |       // Note: as an egregious but useful hack, we use the real path here and | 
 |       // check whether it is actually a subdirectory of the parent directory. | 
 |       // This will not be the case if the 'subframework' is actually a symlink | 
 |       // out to a top-level framework. | 
 |       StringRef SubframeworkDirName = FileMgr.getCanonicalName(SubframeworkDir); | 
 |       bool FoundParent = false; | 
 |       do { | 
 |         // Get the parent directory name. | 
 |         SubframeworkDirName | 
 |           = llvm::sys::path::parent_path(SubframeworkDirName); | 
 |         if (SubframeworkDirName.empty()) | 
 |           break; | 
 |  | 
 |         if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) { | 
 |           FoundParent = true; | 
 |           break; | 
 |         } | 
 |       } while (true); | 
 |  | 
 |       if (!FoundParent) | 
 |         continue; | 
 |  | 
 |       // FIXME: Do we want to warn about subframeworks without umbrella headers? | 
 |       SmallString<32> NameBuf; | 
 |       inferFrameworkModule(sanitizeFilenameAsIdentifier( | 
 |                              llvm::sys::path::stem(Dir->path()), NameBuf), | 
 |                            SubframeworkDir, IsSystem, Result); | 
 |     } | 
 |   } | 
 |  | 
 |   // If the module is a top-level framework, automatically link against the | 
 |   // framework. | 
 |   if (!Result->isSubFramework()) { | 
 |     inferFrameworkLink(Result, FrameworkDir, FileMgr); | 
 |   } | 
 |  | 
 |   return Result; | 
 | } | 
 |  | 
 | void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){ | 
 |   Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader)); | 
 |   Mod->Umbrella = UmbrellaHeader; | 
 |   UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; | 
 | } | 
 |  | 
 | void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) { | 
 |   Mod->Umbrella = UmbrellaDir; | 
 |   UmbrellaDirs[UmbrellaDir] = Mod; | 
 | } | 
 |  | 
 | void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, | 
 |                           ModuleHeaderRole Role) { | 
 |   if (Role == ExcludedHeader) { | 
 |     Mod->ExcludedHeaders.push_back(Header); | 
 |   } else { | 
 |     if (Role == PrivateHeader) | 
 |       Mod->PrivateHeaders.push_back(Header); | 
 |     else | 
 |       Mod->NormalHeaders.push_back(Header); | 
 |     bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule; | 
 |     HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader); | 
 |   } | 
 |   Headers[Header].push_back(KnownHeader(Mod, Role)); | 
 | } | 
 |  | 
 | const FileEntry * | 
 | ModuleMap::getContainingModuleMapFile(Module *Module) const { | 
 |   if (Module->DefinitionLoc.isInvalid()) | 
 |     return nullptr; | 
 |  | 
 |   return SourceMgr.getFileEntryForID( | 
 |            SourceMgr.getFileID(Module->DefinitionLoc)); | 
 | } | 
 |  | 
 | void ModuleMap::dump() { | 
 |   llvm::errs() << "Modules:"; | 
 |   for (llvm::StringMap<Module *>::iterator M = Modules.begin(),  | 
 |                                         MEnd = Modules.end();  | 
 |        M != MEnd; ++M) | 
 |     M->getValue()->print(llvm::errs(), 2); | 
 |    | 
 |   llvm::errs() << "Headers:"; | 
 |   for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end(); | 
 |        H != HEnd; ++H) { | 
 |     llvm::errs() << "  \"" << H->first->getName() << "\" -> "; | 
 |     for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(), | 
 |                                                       E = H->second.end(); | 
 |          I != E; ++I) { | 
 |       if (I != H->second.begin()) | 
 |         llvm::errs() << ","; | 
 |       llvm::errs() << I->getModule()->getFullModuleName(); | 
 |     } | 
 |     llvm::errs() << "\n"; | 
 |   } | 
 | } | 
 |  | 
 | bool ModuleMap::resolveExports(Module *Mod, bool Complain) { | 
 |   bool HadError = false; | 
 |   for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) { | 
 |     Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I],  | 
 |                                               Complain); | 
 |     if (Export.getPointer() || Export.getInt()) | 
 |       Mod->Exports.push_back(Export); | 
 |     else | 
 |       HadError = true; | 
 |   } | 
 |   Mod->UnresolvedExports.clear(); | 
 |   return HadError; | 
 | } | 
 |  | 
 | bool ModuleMap::resolveUses(Module *Mod, bool Complain) { | 
 |   bool HadError = false; | 
 |   for (unsigned I = 0, N = Mod->UnresolvedDirectUses.size(); I != N; ++I) { | 
 |     Module *DirectUse = | 
 |         resolveModuleId(Mod->UnresolvedDirectUses[I], Mod, Complain); | 
 |     if (DirectUse) | 
 |       Mod->DirectUses.push_back(DirectUse); | 
 |     else | 
 |       HadError = true; | 
 |   } | 
 |   Mod->UnresolvedDirectUses.clear(); | 
 |   return HadError; | 
 | } | 
 |  | 
 | bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) { | 
 |   bool HadError = false; | 
 |   for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) { | 
 |     Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id, | 
 |                                        Mod, Complain); | 
 |     if (!OtherMod) { | 
 |       HadError = true; | 
 |       continue; | 
 |     } | 
 |  | 
 |     Module::Conflict Conflict; | 
 |     Conflict.Other = OtherMod; | 
 |     Conflict.Message = Mod->UnresolvedConflicts[I].Message; | 
 |     Mod->Conflicts.push_back(Conflict); | 
 |   } | 
 |   Mod->UnresolvedConflicts.clear(); | 
 |   return HadError; | 
 | } | 
 |  | 
 | Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) { | 
 |   if (Loc.isInvalid()) | 
 |     return nullptr; | 
 |  | 
 |   // Use the expansion location to determine which module we're in. | 
 |   FullSourceLoc ExpansionLoc = Loc.getExpansionLoc(); | 
 |   if (!ExpansionLoc.isFileID()) | 
 |     return nullptr; | 
 |  | 
 |   const SourceManager &SrcMgr = Loc.getManager(); | 
 |   FileID ExpansionFileID = ExpansionLoc.getFileID(); | 
 |    | 
 |   while (const FileEntry *ExpansionFile | 
 |            = SrcMgr.getFileEntryForID(ExpansionFileID)) { | 
 |     // Find the module that owns this header (if any). | 
 |     if (Module *Mod = findModuleForHeader(ExpansionFile).getModule()) | 
 |       return Mod; | 
 |      | 
 |     // No module owns this header, so look up the inclusion chain to see if | 
 |     // any included header has an associated module. | 
 |     SourceLocation IncludeLoc = SrcMgr.getIncludeLoc(ExpansionFileID); | 
 |     if (IncludeLoc.isInvalid()) | 
 |       return nullptr; | 
 |  | 
 |     ExpansionFileID = SrcMgr.getFileID(IncludeLoc); | 
 |   } | 
 |  | 
 |   return nullptr; | 
 | } | 
 |  | 
 | //----------------------------------------------------------------------------// | 
 | // Module map file parser | 
 | //----------------------------------------------------------------------------// | 
 |  | 
 | namespace clang { | 
 |   /// \brief A token in a module map file. | 
 |   struct MMToken { | 
 |     enum TokenKind { | 
 |       Comma, | 
 |       ConfigMacros, | 
 |       Conflict, | 
 |       EndOfFile, | 
 |       HeaderKeyword, | 
 |       Identifier, | 
 |       Exclaim, | 
 |       ExcludeKeyword, | 
 |       ExplicitKeyword, | 
 |       ExportKeyword, | 
 |       ExternKeyword, | 
 |       FrameworkKeyword, | 
 |       LinkKeyword, | 
 |       ModuleKeyword, | 
 |       Period, | 
 |       PrivateKeyword, | 
 |       UmbrellaKeyword, | 
 |       UseKeyword, | 
 |       RequiresKeyword, | 
 |       Star, | 
 |       StringLiteral, | 
 |       LBrace, | 
 |       RBrace, | 
 |       LSquare, | 
 |       RSquare | 
 |     } Kind; | 
 |      | 
 |     unsigned Location; | 
 |     unsigned StringLength; | 
 |     const char *StringData; | 
 |      | 
 |     void clear() { | 
 |       Kind = EndOfFile; | 
 |       Location = 0; | 
 |       StringLength = 0; | 
 |       StringData = nullptr; | 
 |     } | 
 |      | 
 |     bool is(TokenKind K) const { return Kind == K; } | 
 |      | 
 |     SourceLocation getLocation() const { | 
 |       return SourceLocation::getFromRawEncoding(Location); | 
 |     } | 
 |      | 
 |     StringRef getString() const { | 
 |       return StringRef(StringData, StringLength); | 
 |     } | 
 |   }; | 
 |  | 
 |   /// \brief The set of attributes that can be attached to a module. | 
 |   struct Attributes { | 
 |     Attributes() : IsSystem(), IsExternC(), IsExhaustive() { } | 
 |  | 
 |     /// \brief Whether this is a system module. | 
 |     unsigned IsSystem : 1; | 
 |  | 
 |     /// \brief Whether this is an extern "C" module. | 
 |     unsigned IsExternC : 1; | 
 |  | 
 |     /// \brief Whether this is an exhaustive set of configuration macros. | 
 |     unsigned IsExhaustive : 1; | 
 |   }; | 
 |    | 
 |  | 
 |   class ModuleMapParser { | 
 |     Lexer &L; | 
 |     SourceManager &SourceMgr; | 
 |  | 
 |     /// \brief Default target information, used only for string literal | 
 |     /// parsing. | 
 |     const TargetInfo *Target; | 
 |  | 
 |     DiagnosticsEngine &Diags; | 
 |     ModuleMap ⤅ | 
 |  | 
 |     /// \brief The current module map file. | 
 |     const FileEntry *ModuleMapFile; | 
 |      | 
 |     /// \brief The directory that this module map resides in. | 
 |     const DirectoryEntry *Directory; | 
 |  | 
 |     /// \brief The directory containing Clang-supplied headers. | 
 |     const DirectoryEntry *BuiltinIncludeDir; | 
 |  | 
 |     /// \brief Whether this module map is in a system header directory. | 
 |     bool IsSystem; | 
 |      | 
 |     /// \brief Whether an error occurred. | 
 |     bool HadError; | 
 |          | 
 |     /// \brief Stores string data for the various string literals referenced | 
 |     /// during parsing. | 
 |     llvm::BumpPtrAllocator StringData; | 
 |      | 
 |     /// \brief The current token. | 
 |     MMToken Tok; | 
 |      | 
 |     /// \brief The active module. | 
 |     Module *ActiveModule; | 
 |      | 
 |     /// \brief Consume the current token and return its location. | 
 |     SourceLocation consumeToken(); | 
 |      | 
 |     /// \brief Skip tokens until we reach the a token with the given kind | 
 |     /// (or the end of the file). | 
 |     void skipUntil(MMToken::TokenKind K); | 
 |  | 
 |     typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId; | 
 |     bool parseModuleId(ModuleId &Id); | 
 |     void parseModuleDecl(); | 
 |     void parseExternModuleDecl(); | 
 |     void parseRequiresDecl(); | 
 |     void parseHeaderDecl(clang::MMToken::TokenKind, | 
 |                          SourceLocation LeadingLoc); | 
 |     void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); | 
 |     void parseExportDecl(); | 
 |     void parseUseDecl(); | 
 |     void parseLinkDecl(); | 
 |     void parseConfigMacros(); | 
 |     void parseConflict(); | 
 |     void parseInferredModuleDecl(bool Framework, bool Explicit); | 
 |     bool parseOptionalAttributes(Attributes &Attrs); | 
 |      | 
 |   public: | 
 |     explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,  | 
 |                              const TargetInfo *Target, | 
 |                              DiagnosticsEngine &Diags, | 
 |                              ModuleMap &Map, | 
 |                              const FileEntry *ModuleMapFile, | 
 |                              const DirectoryEntry *Directory, | 
 |                              const DirectoryEntry *BuiltinIncludeDir, | 
 |                              bool IsSystem) | 
 |       : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),  | 
 |         ModuleMapFile(ModuleMapFile), Directory(Directory), | 
 |         BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem), | 
 |         HadError(false), ActiveModule(nullptr) | 
 |     { | 
 |       Tok.clear(); | 
 |       consumeToken(); | 
 |     } | 
 |      | 
 |     bool parseModuleMapFile(); | 
 |   }; | 
 | } | 
 |  | 
 | SourceLocation ModuleMapParser::consumeToken() { | 
 | retry: | 
 |   SourceLocation Result = Tok.getLocation(); | 
 |   Tok.clear(); | 
 |    | 
 |   Token LToken; | 
 |   L.LexFromRawLexer(LToken); | 
 |   Tok.Location = LToken.getLocation().getRawEncoding(); | 
 |   switch (LToken.getKind()) { | 
 |   case tok::raw_identifier: { | 
 |     StringRef RI = LToken.getRawIdentifier(); | 
 |     Tok.StringData = RI.data(); | 
 |     Tok.StringLength = RI.size(); | 
 |     Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI) | 
 |                  .Case("config_macros", MMToken::ConfigMacros) | 
 |                  .Case("conflict", MMToken::Conflict) | 
 |                  .Case("exclude", MMToken::ExcludeKeyword) | 
 |                  .Case("explicit", MMToken::ExplicitKeyword) | 
 |                  .Case("export", MMToken::ExportKeyword) | 
 |                  .Case("extern", MMToken::ExternKeyword) | 
 |                  .Case("framework", MMToken::FrameworkKeyword) | 
 |                  .Case("header", MMToken::HeaderKeyword) | 
 |                  .Case("link", MMToken::LinkKeyword) | 
 |                  .Case("module", MMToken::ModuleKeyword) | 
 |                  .Case("private", MMToken::PrivateKeyword) | 
 |                  .Case("requires", MMToken::RequiresKeyword) | 
 |                  .Case("umbrella", MMToken::UmbrellaKeyword) | 
 |                  .Case("use", MMToken::UseKeyword) | 
 |                  .Default(MMToken::Identifier); | 
 |     break; | 
 |   } | 
 |  | 
 |   case tok::comma: | 
 |     Tok.Kind = MMToken::Comma; | 
 |     break; | 
 |  | 
 |   case tok::eof: | 
 |     Tok.Kind = MMToken::EndOfFile; | 
 |     break; | 
 |        | 
 |   case tok::l_brace: | 
 |     Tok.Kind = MMToken::LBrace; | 
 |     break; | 
 |  | 
 |   case tok::l_square: | 
 |     Tok.Kind = MMToken::LSquare; | 
 |     break; | 
 |        | 
 |   case tok::period: | 
 |     Tok.Kind = MMToken::Period; | 
 |     break; | 
 |        | 
 |   case tok::r_brace: | 
 |     Tok.Kind = MMToken::RBrace; | 
 |     break; | 
 |        | 
 |   case tok::r_square: | 
 |     Tok.Kind = MMToken::RSquare; | 
 |     break; | 
 |        | 
 |   case tok::star: | 
 |     Tok.Kind = MMToken::Star; | 
 |     break; | 
 |        | 
 |   case tok::exclaim: | 
 |     Tok.Kind = MMToken::Exclaim; | 
 |     break; | 
 |        | 
 |   case tok::string_literal: { | 
 |     if (LToken.hasUDSuffix()) { | 
 |       Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl); | 
 |       HadError = true; | 
 |       goto retry; | 
 |     } | 
 |  | 
 |     // Parse the string literal. | 
 |     LangOptions LangOpts; | 
 |     StringLiteralParser StringLiteral(LToken, SourceMgr, LangOpts, *Target); | 
 |     if (StringLiteral.hadError) | 
 |       goto retry; | 
 |      | 
 |     // Copy the string literal into our string data allocator. | 
 |     unsigned Length = StringLiteral.GetStringLength(); | 
 |     char *Saved = StringData.Allocate<char>(Length + 1); | 
 |     memcpy(Saved, StringLiteral.GetString().data(), Length); | 
 |     Saved[Length] = 0; | 
 |      | 
 |     // Form the token. | 
 |     Tok.Kind = MMToken::StringLiteral; | 
 |     Tok.StringData = Saved; | 
 |     Tok.StringLength = Length; | 
 |     break; | 
 |   } | 
 |        | 
 |   case tok::comment: | 
 |     goto retry; | 
 |        | 
 |   default: | 
 |     Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token); | 
 |     HadError = true; | 
 |     goto retry; | 
 |   } | 
 |    | 
 |   return Result; | 
 | } | 
 |  | 
 | void ModuleMapParser::skipUntil(MMToken::TokenKind K) { | 
 |   unsigned braceDepth = 0; | 
 |   unsigned squareDepth = 0; | 
 |   do { | 
 |     switch (Tok.Kind) { | 
 |     case MMToken::EndOfFile: | 
 |       return; | 
 |  | 
 |     case MMToken::LBrace: | 
 |       if (Tok.is(K) && braceDepth == 0 && squareDepth == 0) | 
 |         return; | 
 |          | 
 |       ++braceDepth; | 
 |       break; | 
 |  | 
 |     case MMToken::LSquare: | 
 |       if (Tok.is(K) && braceDepth == 0 && squareDepth == 0) | 
 |         return; | 
 |        | 
 |       ++squareDepth; | 
 |       break; | 
 |  | 
 |     case MMToken::RBrace: | 
 |       if (braceDepth > 0) | 
 |         --braceDepth; | 
 |       else if (Tok.is(K)) | 
 |         return; | 
 |       break; | 
 |  | 
 |     case MMToken::RSquare: | 
 |       if (squareDepth > 0) | 
 |         --squareDepth; | 
 |       else if (Tok.is(K)) | 
 |         return; | 
 |       break; | 
 |  | 
 |     default: | 
 |       if (braceDepth == 0 && squareDepth == 0 && Tok.is(K)) | 
 |         return; | 
 |       break; | 
 |     } | 
 |      | 
 |    consumeToken(); | 
 |   } while (true); | 
 | } | 
 |  | 
 | /// \brief Parse a module-id. | 
 | /// | 
 | ///   module-id: | 
 | ///     identifier | 
 | ///     identifier '.' module-id | 
 | /// | 
 | /// \returns true if an error occurred, false otherwise. | 
 | bool ModuleMapParser::parseModuleId(ModuleId &Id) { | 
 |   Id.clear(); | 
 |   do { | 
 |     if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) { | 
 |       Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation())); | 
 |       consumeToken(); | 
 |     } else { | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name); | 
 |       return true; | 
 |     } | 
 |      | 
 |     if (!Tok.is(MMToken::Period)) | 
 |       break; | 
 |      | 
 |     consumeToken(); | 
 |   } while (true); | 
 |    | 
 |   return false; | 
 | } | 
 |  | 
 | namespace { | 
 |   /// \brief Enumerates the known attributes. | 
 |   enum AttributeKind { | 
 |     /// \brief An unknown attribute. | 
 |     AT_unknown, | 
 |     /// \brief The 'system' attribute. | 
 |     AT_system, | 
 |     /// \brief The 'extern_c' attribute. | 
 |     AT_extern_c, | 
 |     /// \brief The 'exhaustive' attribute. | 
 |     AT_exhaustive | 
 |   }; | 
 | } | 
 |  | 
 | /// \brief Parse a module declaration. | 
 | /// | 
 | ///   module-declaration: | 
 | ///     'extern' 'module' module-id string-literal | 
 | ///     'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]  | 
 | ///       { module-member* } | 
 | /// | 
 | ///   module-member: | 
 | ///     requires-declaration | 
 | ///     header-declaration | 
 | ///     submodule-declaration | 
 | ///     export-declaration | 
 | ///     link-declaration | 
 | /// | 
 | ///   submodule-declaration: | 
 | ///     module-declaration | 
 | ///     inferred-submodule-declaration | 
 | void ModuleMapParser::parseModuleDecl() { | 
 |   assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) || | 
 |          Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword)); | 
 |   if (Tok.is(MMToken::ExternKeyword)) { | 
 |     parseExternModuleDecl(); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Parse 'explicit' or 'framework' keyword, if present. | 
 |   SourceLocation ExplicitLoc; | 
 |   bool Explicit = false; | 
 |   bool Framework = false; | 
 |  | 
 |   // Parse 'explicit' keyword, if present. | 
 |   if (Tok.is(MMToken::ExplicitKeyword)) { | 
 |     ExplicitLoc = consumeToken(); | 
 |     Explicit = true; | 
 |   } | 
 |  | 
 |   // Parse 'framework' keyword, if present. | 
 |   if (Tok.is(MMToken::FrameworkKeyword)) { | 
 |     consumeToken(); | 
 |     Framework = true; | 
 |   }  | 
 |    | 
 |   // Parse 'module' keyword. | 
 |   if (!Tok.is(MMToken::ModuleKeyword)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); | 
 |     consumeToken(); | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |   consumeToken(); // 'module' keyword | 
 |  | 
 |   // If we have a wildcard for the module name, this is an inferred submodule. | 
 |   // Parse it.  | 
 |   if (Tok.is(MMToken::Star)) | 
 |     return parseInferredModuleDecl(Framework, Explicit); | 
 |    | 
 |   // Parse the module name. | 
 |   ModuleId Id; | 
 |   if (parseModuleId(Id)) { | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   if (ActiveModule) { | 
 |     if (Id.size() > 1) { | 
 |       Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id) | 
 |         << SourceRange(Id.front().second, Id.back().second); | 
 |        | 
 |       HadError = true; | 
 |       return; | 
 |     } | 
 |   } else if (Id.size() == 1 && Explicit) { | 
 |     // Top-level modules can't be explicit. | 
 |     Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level); | 
 |     Explicit = false; | 
 |     ExplicitLoc = SourceLocation(); | 
 |     HadError = true; | 
 |   } | 
 |    | 
 |   Module *PreviousActiveModule = ActiveModule;   | 
 |   if (Id.size() > 1) { | 
 |     // This module map defines a submodule. Go find the module of which it | 
 |     // is a submodule. | 
 |     ActiveModule = nullptr; | 
 |     for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) { | 
 |       if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) { | 
 |         ActiveModule = Next; | 
 |         continue; | 
 |       } | 
 |        | 
 |       if (ActiveModule) { | 
 |         Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified) | 
 |           << Id[I].first | 
 |           << ActiveModule->getTopLevelModule()->getFullModuleName(); | 
 |       } else { | 
 |         Diags.Report(Id[I].second, diag::err_mmap_expected_module_name); | 
 |       } | 
 |       HadError = true; | 
 |       return; | 
 |     } | 
 |   }  | 
 |    | 
 |   StringRef ModuleName = Id.back().first; | 
 |   SourceLocation ModuleNameLoc = Id.back().second; | 
 |    | 
 |   // Parse the optional attribute list. | 
 |   Attributes Attrs; | 
 |   parseOptionalAttributes(Attrs); | 
 |    | 
 |   // Parse the opening brace. | 
 |   if (!Tok.is(MMToken::LBrace)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace) | 
 |       << ModuleName; | 
 |     HadError = true; | 
 |     return; | 
 |   }   | 
 |   SourceLocation LBraceLoc = consumeToken(); | 
 |    | 
 |   // Determine whether this (sub)module has already been defined. | 
 |   if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) { | 
 |     if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) { | 
 |       // Skip the module definition. | 
 |       skipUntil(MMToken::RBrace); | 
 |       if (Tok.is(MMToken::RBrace)) | 
 |         consumeToken(); | 
 |       else { | 
 |         Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace); | 
 |         Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match); | 
 |         HadError = true;         | 
 |       } | 
 |       return; | 
 |     } | 
 |      | 
 |     Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition) | 
 |       << ModuleName; | 
 |     Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition); | 
 |      | 
 |     // Skip the module definition. | 
 |     skipUntil(MMToken::RBrace); | 
 |     if (Tok.is(MMToken::RBrace)) | 
 |       consumeToken(); | 
 |      | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   // If this is a submodule, use the parent's module map, since we don't want | 
 |   // the private module map file. | 
 |   const FileEntry *ModuleMap = ActiveModule ? ActiveModule->ModuleMap | 
 |                                             : ModuleMapFile; | 
 |  | 
 |   // Start defining this module. | 
 |   ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, ModuleMap, | 
 |                                         Framework, Explicit).first; | 
 |   ActiveModule->DefinitionLoc = ModuleNameLoc; | 
 |   if (Attrs.IsSystem || IsSystem) | 
 |     ActiveModule->IsSystem = true; | 
 |   if (Attrs.IsExternC) | 
 |     ActiveModule->IsExternC = true; | 
 |  | 
 |   bool Done = false; | 
 |   do { | 
 |     switch (Tok.Kind) { | 
 |     case MMToken::EndOfFile: | 
 |     case MMToken::RBrace: | 
 |       Done = true; | 
 |       break; | 
 |  | 
 |     case MMToken::ConfigMacros: | 
 |       parseConfigMacros(); | 
 |       break; | 
 |  | 
 |     case MMToken::Conflict: | 
 |       parseConflict(); | 
 |       break; | 
 |  | 
 |     case MMToken::ExplicitKeyword: | 
 |     case MMToken::ExternKeyword: | 
 |     case MMToken::FrameworkKeyword: | 
 |     case MMToken::ModuleKeyword: | 
 |       parseModuleDecl(); | 
 |       break; | 
 |  | 
 |     case MMToken::ExportKeyword: | 
 |       parseExportDecl(); | 
 |       break; | 
 |  | 
 |     case MMToken::UseKeyword: | 
 |       parseUseDecl(); | 
 |       break; | 
 |          | 
 |     case MMToken::RequiresKeyword: | 
 |       parseRequiresDecl(); | 
 |       break; | 
 |  | 
 |     case MMToken::UmbrellaKeyword: { | 
 |       SourceLocation UmbrellaLoc = consumeToken(); | 
 |       if (Tok.is(MMToken::HeaderKeyword)) | 
 |         parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc); | 
 |       else | 
 |         parseUmbrellaDirDecl(UmbrellaLoc); | 
 |       break; | 
 |     } | 
 |          | 
 |     case MMToken::ExcludeKeyword: { | 
 |       SourceLocation ExcludeLoc = consumeToken(); | 
 |       if (Tok.is(MMToken::HeaderKeyword)) { | 
 |         parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc); | 
 |       } else { | 
 |         Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) | 
 |           << "exclude"; | 
 |       } | 
 |       break; | 
 |     } | 
 |        | 
 |     case MMToken::PrivateKeyword: { | 
 |       SourceLocation PrivateLoc = consumeToken(); | 
 |       if (Tok.is(MMToken::HeaderKeyword)) { | 
 |         parseHeaderDecl(MMToken::PrivateKeyword, PrivateLoc); | 
 |       } else { | 
 |         Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) | 
 |           << "private"; | 
 |       } | 
 |       break; | 
 |     } | 
 |        | 
 |     case MMToken::HeaderKeyword: | 
 |       parseHeaderDecl(MMToken::HeaderKeyword, SourceLocation()); | 
 |       break; | 
 |  | 
 |     case MMToken::LinkKeyword: | 
 |       parseLinkDecl(); | 
 |       break; | 
 |  | 
 |     default: | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member); | 
 |       consumeToken(); | 
 |       break;         | 
 |     } | 
 |   } while (!Done); | 
 |  | 
 |   if (Tok.is(MMToken::RBrace)) | 
 |     consumeToken(); | 
 |   else { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace); | 
 |     Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match); | 
 |     HadError = true; | 
 |   } | 
 |  | 
 |   // If the active module is a top-level framework, and there are no link | 
 |   // libraries, automatically link against the framework. | 
 |   if (ActiveModule->IsFramework && !ActiveModule->isSubFramework() && | 
 |       ActiveModule->LinkLibraries.empty()) { | 
 |     inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager()); | 
 |   } | 
 |  | 
 |   // If the module meets all requirements but is still unavailable, mark the | 
 |   // whole tree as unavailable to prevent it from building. | 
 |   if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement && | 
 |       ActiveModule->Parent) { | 
 |     ActiveModule->getTopLevelModule()->markUnavailable(); | 
 |     ActiveModule->getTopLevelModule()->MissingHeaders.append( | 
 |       ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end()); | 
 |   } | 
 |  | 
 |   // We're done parsing this module. Pop back to the previous module. | 
 |   ActiveModule = PreviousActiveModule; | 
 | } | 
 |  | 
 | /// \brief Parse an extern module declaration. | 
 | /// | 
 | ///   extern module-declaration: | 
 | ///     'extern' 'module' module-id string-literal | 
 | void ModuleMapParser::parseExternModuleDecl() { | 
 |   assert(Tok.is(MMToken::ExternKeyword)); | 
 |   consumeToken(); // 'extern' keyword | 
 |  | 
 |   // Parse 'module' keyword. | 
 |   if (!Tok.is(MMToken::ModuleKeyword)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); | 
 |     consumeToken(); | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |   consumeToken(); // 'module' keyword | 
 |  | 
 |   // Parse the module name. | 
 |   ModuleId Id; | 
 |   if (parseModuleId(Id)) { | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Parse the referenced module map file name. | 
 |   if (!Tok.is(MMToken::StringLiteral)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file); | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |   std::string FileName = Tok.getString(); | 
 |   consumeToken(); // filename | 
 |  | 
 |   StringRef FileNameRef = FileName; | 
 |   SmallString<128> ModuleMapFileName; | 
 |   if (llvm::sys::path::is_relative(FileNameRef)) { | 
 |     ModuleMapFileName += Directory->getName(); | 
 |     llvm::sys::path::append(ModuleMapFileName, FileName); | 
 |     FileNameRef = ModuleMapFileName.str(); | 
 |   } | 
 |   if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef)) | 
 |     Map.parseModuleMapFile(File, /*IsSystem=*/false); | 
 | } | 
 |  | 
 | /// \brief Parse a requires declaration. | 
 | /// | 
 | ///   requires-declaration: | 
 | ///     'requires' feature-list | 
 | /// | 
 | ///   feature-list: | 
 | ///     feature ',' feature-list | 
 | ///     feature | 
 | /// | 
 | ///   feature: | 
 | ///     '!'[opt] identifier | 
 | void ModuleMapParser::parseRequiresDecl() { | 
 |   assert(Tok.is(MMToken::RequiresKeyword)); | 
 |  | 
 |   // Parse 'requires' keyword. | 
 |   consumeToken(); | 
 |  | 
 |   // Parse the feature-list. | 
 |   do { | 
 |     bool RequiredState = true; | 
 |     if (Tok.is(MMToken::Exclaim)) { | 
 |       RequiredState = false; | 
 |       consumeToken(); | 
 |     } | 
 |  | 
 |     if (!Tok.is(MMToken::Identifier)) { | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature); | 
 |       HadError = true; | 
 |       return; | 
 |     } | 
 |  | 
 |     // Consume the feature name. | 
 |     std::string Feature = Tok.getString(); | 
 |     consumeToken(); | 
 |  | 
 |     // Add this feature. | 
 |     ActiveModule->addRequirement(Feature, RequiredState, | 
 |                                  Map.LangOpts, *Map.Target); | 
 |  | 
 |     if (!Tok.is(MMToken::Comma)) | 
 |       break; | 
 |  | 
 |     // Consume the comma. | 
 |     consumeToken(); | 
 |   } while (true); | 
 | } | 
 |  | 
 | /// \brief Append to \p Paths the set of paths needed to get to the  | 
 | /// subframework in which the given module lives. | 
 | static void appendSubframeworkPaths(Module *Mod, | 
 |                                     SmallVectorImpl<char> &Path) { | 
 |   // Collect the framework names from the given module to the top-level module. | 
 |   SmallVector<StringRef, 2> Paths; | 
 |   for (; Mod; Mod = Mod->Parent) { | 
 |     if (Mod->IsFramework) | 
 |       Paths.push_back(Mod->Name); | 
 |   } | 
 |    | 
 |   if (Paths.empty()) | 
 |     return; | 
 |    | 
 |   // Add Frameworks/Name.framework for each subframework. | 
 |   for (unsigned I = Paths.size() - 1; I != 0; --I) | 
 |     llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework"); | 
 | } | 
 |  | 
 | /// \brief Parse a header declaration. | 
 | /// | 
 | ///   header-declaration: | 
 | ///     'umbrella'[opt] 'header' string-literal | 
 | ///     'exclude'[opt] 'header' string-literal | 
 | void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, | 
 |                                       SourceLocation LeadingLoc) { | 
 |   assert(Tok.is(MMToken::HeaderKeyword)); | 
 |   consumeToken(); | 
 |  | 
 |   // Parse the header name. | 
 |   if (!Tok.is(MMToken::StringLiteral)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)  | 
 |       << "header"; | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |   Module::HeaderDirective Header; | 
 |   Header.FileName = Tok.getString(); | 
 |   Header.FileNameLoc = consumeToken(); | 
 |    | 
 |   // Check whether we already have an umbrella. | 
 |   if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) { | 
 |     Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash) | 
 |       << ActiveModule->getFullModuleName(); | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Look for this file. | 
 |   const FileEntry *File = nullptr; | 
 |   const FileEntry *BuiltinFile = nullptr; | 
 |   SmallString<128> PathName; | 
 |   if (llvm::sys::path::is_absolute(Header.FileName)) { | 
 |     PathName = Header.FileName; | 
 |     File = SourceMgr.getFileManager().getFile(PathName); | 
 |   } else { | 
 |     // Search for the header file within the search directory. | 
 |     PathName = Directory->getName(); | 
 |     unsigned PathLength = PathName.size(); | 
 |      | 
 |     if (ActiveModule->isPartOfFramework()) { | 
 |       appendSubframeworkPaths(ActiveModule, PathName); | 
 |        | 
 |       // Check whether this file is in the public headers. | 
 |       llvm::sys::path::append(PathName, "Headers", Header.FileName); | 
 |       File = SourceMgr.getFileManager().getFile(PathName); | 
 |        | 
 |       if (!File) { | 
 |         // Check whether this file is in the private headers. | 
 |         PathName.resize(PathLength); | 
 |         llvm::sys::path::append(PathName, "PrivateHeaders", Header.FileName); | 
 |         File = SourceMgr.getFileManager().getFile(PathName); | 
 |       } | 
 |     } else { | 
 |       // Lookup for normal headers. | 
 |       llvm::sys::path::append(PathName, Header.FileName); | 
 |       File = SourceMgr.getFileManager().getFile(PathName); | 
 |        | 
 |       // If this is a system module with a top-level header, this header | 
 |       // may have a counterpart (or replacement) in the set of headers | 
 |       // supplied by Clang. Find that builtin header. | 
 |       if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword && | 
 |           BuiltinIncludeDir && BuiltinIncludeDir != Directory && | 
 |           isBuiltinHeader(Header.FileName)) { | 
 |         SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName()); | 
 |         llvm::sys::path::append(BuiltinPathName, Header.FileName); | 
 |         BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName); | 
 |          | 
 |         // If Clang supplies this header but the underlying system does not, | 
 |         // just silently swap in our builtin version. Otherwise, we'll end | 
 |         // up adding both (later). | 
 |         if (!File && BuiltinFile) { | 
 |           File = BuiltinFile; | 
 |           BuiltinFile = nullptr; | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |    | 
 |   // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. | 
 |   // Come up with a lazy way to do this. | 
 |   if (File) { | 
 |     if (LeadingToken == MMToken::UmbrellaKeyword) { | 
 |       const DirectoryEntry *UmbrellaDir = File->getDir(); | 
 |       if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) { | 
 |         Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash) | 
 |           << UmbrellaModule->getFullModuleName(); | 
 |         HadError = true; | 
 |       } else { | 
 |         // Record this umbrella header. | 
 |         Map.setUmbrellaHeader(ActiveModule, File); | 
 |       } | 
 |     } else { | 
 |       // Record this header. | 
 |       ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader; | 
 |       if (LeadingToken == MMToken::ExcludeKeyword) | 
 |         Role = ModuleMap::ExcludedHeader; | 
 |       else if (LeadingToken == MMToken::PrivateKeyword) | 
 |         Role = ModuleMap::PrivateHeader; | 
 |       else | 
 |         assert(LeadingToken == MMToken::HeaderKeyword); | 
 |          | 
 |       Map.addHeader(ActiveModule, File, Role); | 
 |        | 
 |       // If there is a builtin counterpart to this file, add it now. | 
 |       if (BuiltinFile) | 
 |         Map.addHeader(ActiveModule, BuiltinFile, Role); | 
 |     } | 
 |   } else if (LeadingToken != MMToken::ExcludeKeyword) { | 
 |     // Ignore excluded header files. They're optional anyway. | 
 |  | 
 |     // If we find a module that has a missing header, we mark this module as | 
 |     // unavailable and store the header directive for displaying diagnostics. | 
 |     Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword; | 
 |     ActiveModule->markUnavailable(); | 
 |     ActiveModule->MissingHeaders.push_back(Header); | 
 |   } | 
 | } | 
 |  | 
 | /// \brief Parse an umbrella directory declaration. | 
 | /// | 
 | ///   umbrella-dir-declaration: | 
 | ///     umbrella string-literal | 
 | void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) { | 
 |   // Parse the directory name. | 
 |   if (!Tok.is(MMToken::StringLiteral)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)  | 
 |       << "umbrella"; | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   std::string DirName = Tok.getString(); | 
 |   SourceLocation DirNameLoc = consumeToken(); | 
 |    | 
 |   // Check whether we already have an umbrella. | 
 |   if (ActiveModule->Umbrella) { | 
 |     Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash) | 
 |       << ActiveModule->getFullModuleName(); | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Look for this file. | 
 |   const DirectoryEntry *Dir = nullptr; | 
 |   if (llvm::sys::path::is_absolute(DirName)) | 
 |     Dir = SourceMgr.getFileManager().getDirectory(DirName); | 
 |   else { | 
 |     SmallString<128> PathName; | 
 |     PathName = Directory->getName(); | 
 |     llvm::sys::path::append(PathName, DirName); | 
 |     Dir = SourceMgr.getFileManager().getDirectory(PathName); | 
 |   } | 
 |    | 
 |   if (!Dir) { | 
 |     Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found) | 
 |       << DirName; | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |    | 
 |   if (Module *OwningModule = Map.UmbrellaDirs[Dir]) { | 
 |     Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) | 
 |       << OwningModule->getFullModuleName(); | 
 |     HadError = true; | 
 |     return; | 
 |   }  | 
 |    | 
 |   // Record this umbrella directory. | 
 |   Map.setUmbrellaDir(ActiveModule, Dir); | 
 | } | 
 |  | 
 | /// \brief Parse a module export declaration. | 
 | /// | 
 | ///   export-declaration: | 
 | ///     'export' wildcard-module-id | 
 | /// | 
 | ///   wildcard-module-id: | 
 | ///     identifier | 
 | ///     '*' | 
 | ///     identifier '.' wildcard-module-id | 
 | void ModuleMapParser::parseExportDecl() { | 
 |   assert(Tok.is(MMToken::ExportKeyword)); | 
 |   SourceLocation ExportLoc = consumeToken(); | 
 |    | 
 |   // Parse the module-id with an optional wildcard at the end. | 
 |   ModuleId ParsedModuleId; | 
 |   bool Wildcard = false; | 
 |   do { | 
 |     if (Tok.is(MMToken::Identifier)) { | 
 |       ParsedModuleId.push_back(std::make_pair(Tok.getString(),  | 
 |                                               Tok.getLocation())); | 
 |       consumeToken(); | 
 |        | 
 |       if (Tok.is(MMToken::Period)) { | 
 |         consumeToken(); | 
 |         continue; | 
 |       }  | 
 |        | 
 |       break; | 
 |     } | 
 |      | 
 |     if(Tok.is(MMToken::Star)) { | 
 |       Wildcard = true; | 
 |       consumeToken(); | 
 |       break; | 
 |     } | 
 |      | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_module_id); | 
 |     HadError = true; | 
 |     return; | 
 |   } while (true); | 
 |    | 
 |   Module::UnresolvedExportDecl Unresolved = {  | 
 |     ExportLoc, ParsedModuleId, Wildcard  | 
 |   }; | 
 |   ActiveModule->UnresolvedExports.push_back(Unresolved); | 
 | } | 
 |  | 
 | /// \brief Parse a module uses declaration. | 
 | /// | 
 | ///   uses-declaration: | 
 | ///     'uses' wildcard-module-id | 
 | void ModuleMapParser::parseUseDecl() { | 
 |   assert(Tok.is(MMToken::UseKeyword)); | 
 |   consumeToken(); | 
 |   // Parse the module-id. | 
 |   ModuleId ParsedModuleId; | 
 |   parseModuleId(ParsedModuleId); | 
 |  | 
 |   ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId); | 
 | } | 
 |  | 
 | /// \brief Parse a link declaration. | 
 | /// | 
 | ///   module-declaration: | 
 | ///     'link' 'framework'[opt] string-literal | 
 | void ModuleMapParser::parseLinkDecl() { | 
 |   assert(Tok.is(MMToken::LinkKeyword)); | 
 |   SourceLocation LinkLoc = consumeToken(); | 
 |  | 
 |   // Parse the optional 'framework' keyword. | 
 |   bool IsFramework = false; | 
 |   if (Tok.is(MMToken::FrameworkKeyword)) { | 
 |     consumeToken(); | 
 |     IsFramework = true; | 
 |   } | 
 |  | 
 |   // Parse the library name | 
 |   if (!Tok.is(MMToken::StringLiteral)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name) | 
 |       << IsFramework << SourceRange(LinkLoc); | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   std::string LibraryName = Tok.getString(); | 
 |   consumeToken(); | 
 |   ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName, | 
 |                                                             IsFramework)); | 
 | } | 
 |  | 
 | /// \brief Parse a configuration macro declaration. | 
 | /// | 
 | ///   module-declaration: | 
 | ///     'config_macros' attributes[opt] config-macro-list? | 
 | /// | 
 | ///   config-macro-list: | 
 | ///     identifier (',' identifier)? | 
 | void ModuleMapParser::parseConfigMacros() { | 
 |   assert(Tok.is(MMToken::ConfigMacros)); | 
 |   SourceLocation ConfigMacrosLoc = consumeToken(); | 
 |  | 
 |   // Only top-level modules can have configuration macros. | 
 |   if (ActiveModule->Parent) { | 
 |     Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule); | 
 |   } | 
 |  | 
 |   // Parse the optional attributes. | 
 |   Attributes Attrs; | 
 |   parseOptionalAttributes(Attrs); | 
 |   if (Attrs.IsExhaustive && !ActiveModule->Parent) { | 
 |     ActiveModule->ConfigMacrosExhaustive = true; | 
 |   } | 
 |  | 
 |   // If we don't have an identifier, we're done. | 
 |   if (!Tok.is(MMToken::Identifier)) | 
 |     return; | 
 |  | 
 |   // Consume the first identifier. | 
 |   if (!ActiveModule->Parent) { | 
 |     ActiveModule->ConfigMacros.push_back(Tok.getString().str()); | 
 |   } | 
 |   consumeToken(); | 
 |  | 
 |   do { | 
 |     // If there's a comma, consume it. | 
 |     if (!Tok.is(MMToken::Comma)) | 
 |       break; | 
 |     consumeToken(); | 
 |  | 
 |     // We expect to see a macro name here. | 
 |     if (!Tok.is(MMToken::Identifier)) { | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro); | 
 |       break; | 
 |     } | 
 |  | 
 |     // Consume the macro name. | 
 |     if (!ActiveModule->Parent) { | 
 |       ActiveModule->ConfigMacros.push_back(Tok.getString().str()); | 
 |     } | 
 |     consumeToken(); | 
 |   } while (true); | 
 | } | 
 |  | 
 | /// \brief Format a module-id into a string. | 
 | static std::string formatModuleId(const ModuleId &Id) { | 
 |   std::string result; | 
 |   { | 
 |     llvm::raw_string_ostream OS(result); | 
 |  | 
 |     for (unsigned I = 0, N = Id.size(); I != N; ++I) { | 
 |       if (I) | 
 |         OS << "."; | 
 |       OS << Id[I].first; | 
 |     } | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | /// \brief Parse a conflict declaration. | 
 | /// | 
 | ///   module-declaration: | 
 | ///     'conflict' module-id ',' string-literal | 
 | void ModuleMapParser::parseConflict() { | 
 |   assert(Tok.is(MMToken::Conflict)); | 
 |   SourceLocation ConflictLoc = consumeToken(); | 
 |   Module::UnresolvedConflict Conflict; | 
 |  | 
 |   // Parse the module-id. | 
 |   if (parseModuleId(Conflict.Id)) | 
 |     return; | 
 |  | 
 |   // Parse the ','. | 
 |   if (!Tok.is(MMToken::Comma)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma) | 
 |       << SourceRange(ConflictLoc); | 
 |     return; | 
 |   } | 
 |   consumeToken(); | 
 |  | 
 |   // Parse the message. | 
 |   if (!Tok.is(MMToken::StringLiteral)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message) | 
 |       << formatModuleId(Conflict.Id); | 
 |     return; | 
 |   } | 
 |   Conflict.Message = Tok.getString().str(); | 
 |   consumeToken(); | 
 |  | 
 |   // Add this unresolved conflict. | 
 |   ActiveModule->UnresolvedConflicts.push_back(Conflict); | 
 | } | 
 |  | 
 | /// \brief Parse an inferred module declaration (wildcard modules). | 
 | /// | 
 | ///   module-declaration: | 
 | ///     'explicit'[opt] 'framework'[opt] 'module' * attributes[opt] | 
 | ///       { inferred-module-member* } | 
 | /// | 
 | ///   inferred-module-member: | 
 | ///     'export' '*' | 
 | ///     'exclude' identifier | 
 | void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { | 
 |   assert(Tok.is(MMToken::Star)); | 
 |   SourceLocation StarLoc = consumeToken(); | 
 |   bool Failed = false; | 
 |  | 
 |   // Inferred modules must be submodules. | 
 |   if (!ActiveModule && !Framework) { | 
 |     Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule); | 
 |     Failed = true; | 
 |   } | 
 |  | 
 |   if (ActiveModule) { | 
 |     // Inferred modules must have umbrella directories. | 
 |     if (!Failed && ActiveModule->IsAvailable && | 
 |         !ActiveModule->getUmbrellaDir()) { | 
 |       Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella); | 
 |       Failed = true; | 
 |     } | 
 |      | 
 |     // Check for redefinition of an inferred module. | 
 |     if (!Failed && ActiveModule->InferSubmodules) { | 
 |       Diags.Report(StarLoc, diag::err_mmap_inferred_redef); | 
 |       if (ActiveModule->InferredSubmoduleLoc.isValid()) | 
 |         Diags.Report(ActiveModule->InferredSubmoduleLoc, | 
 |                      diag::note_mmap_prev_definition); | 
 |       Failed = true; | 
 |     } | 
 |  | 
 |     // Check for the 'framework' keyword, which is not permitted here. | 
 |     if (Framework) { | 
 |       Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule); | 
 |       Framework = false; | 
 |     } | 
 |   } else if (Explicit) { | 
 |     Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework); | 
 |     Explicit = false; | 
 |   } | 
 |  | 
 |   // If there were any problems with this inferred submodule, skip its body. | 
 |   if (Failed) { | 
 |     if (Tok.is(MMToken::LBrace)) { | 
 |       consumeToken(); | 
 |       skipUntil(MMToken::RBrace); | 
 |       if (Tok.is(MMToken::RBrace)) | 
 |         consumeToken(); | 
 |     } | 
 |     HadError = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Parse optional attributes. | 
 |   Attributes Attrs; | 
 |   parseOptionalAttributes(Attrs); | 
 |  | 
 |   if (ActiveModule) { | 
 |     // Note that we have an inferred submodule. | 
 |     ActiveModule->InferSubmodules = true; | 
 |     ActiveModule->InferredSubmoduleLoc = StarLoc; | 
 |     ActiveModule->InferExplicitSubmodules = Explicit; | 
 |   } else { | 
 |     // We'll be inferring framework modules for this directory. | 
 |     Map.InferredDirectories[Directory].InferModules = true; | 
 |     Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem; | 
 |     Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile; | 
 |     // FIXME: Handle the 'framework' keyword. | 
 |   } | 
 |  | 
 |   // Parse the opening brace. | 
 |   if (!Tok.is(MMToken::LBrace)) { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard); | 
 |     HadError = true; | 
 |     return; | 
 |   }   | 
 |   SourceLocation LBraceLoc = consumeToken(); | 
 |  | 
 |   // Parse the body of the inferred submodule. | 
 |   bool Done = false; | 
 |   do { | 
 |     switch (Tok.Kind) { | 
 |     case MMToken::EndOfFile: | 
 |     case MMToken::RBrace: | 
 |       Done = true; | 
 |       break; | 
 |  | 
 |     case MMToken::ExcludeKeyword: { | 
 |       if (ActiveModule) { | 
 |         Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) | 
 |           << (ActiveModule != nullptr); | 
 |         consumeToken(); | 
 |         break; | 
 |       } | 
 |  | 
 |       consumeToken(); | 
 |       if (!Tok.is(MMToken::Identifier)) { | 
 |         Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name); | 
 |         break; | 
 |       } | 
 |  | 
 |       Map.InferredDirectories[Directory].ExcludedModules | 
 |         .push_back(Tok.getString()); | 
 |       consumeToken(); | 
 |       break; | 
 |     } | 
 |  | 
 |     case MMToken::ExportKeyword: | 
 |       if (!ActiveModule) { | 
 |         Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) | 
 |           << (ActiveModule != nullptr); | 
 |         consumeToken(); | 
 |         break; | 
 |       } | 
 |  | 
 |       consumeToken(); | 
 |       if (Tok.is(MMToken::Star))  | 
 |         ActiveModule->InferExportWildcard = true; | 
 |       else | 
 |         Diags.Report(Tok.getLocation(),  | 
 |                      diag::err_mmap_expected_export_wildcard); | 
 |       consumeToken(); | 
 |       break; | 
 |  | 
 |     case MMToken::ExplicitKeyword: | 
 |     case MMToken::ModuleKeyword: | 
 |     case MMToken::HeaderKeyword: | 
 |     case MMToken::PrivateKeyword: | 
 |     case MMToken::UmbrellaKeyword: | 
 |     default: | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) | 
 |           << (ActiveModule != nullptr); | 
 |       consumeToken(); | 
 |       break;         | 
 |     } | 
 |   } while (!Done); | 
 |    | 
 |   if (Tok.is(MMToken::RBrace)) | 
 |     consumeToken(); | 
 |   else { | 
 |     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace); | 
 |     Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match); | 
 |     HadError = true; | 
 |   } | 
 | } | 
 |  | 
 | /// \brief Parse optional attributes. | 
 | /// | 
 | ///   attributes: | 
 | ///     attribute attributes | 
 | ///     attribute | 
 | /// | 
 | ///   attribute: | 
 | ///     [ identifier ] | 
 | /// | 
 | /// \param Attrs Will be filled in with the parsed attributes. | 
 | /// | 
 | /// \returns true if an error occurred, false otherwise. | 
 | bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { | 
 |   bool HadError = false; | 
 |    | 
 |   while (Tok.is(MMToken::LSquare)) { | 
 |     // Consume the '['. | 
 |     SourceLocation LSquareLoc = consumeToken(); | 
 |  | 
 |     // Check whether we have an attribute name here. | 
 |     if (!Tok.is(MMToken::Identifier)) { | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute); | 
 |       skipUntil(MMToken::RSquare); | 
 |       if (Tok.is(MMToken::RSquare)) | 
 |         consumeToken(); | 
 |       HadError = true; | 
 |     } | 
 |  | 
 |     // Decode the attribute name. | 
 |     AttributeKind Attribute | 
 |       = llvm::StringSwitch<AttributeKind>(Tok.getString()) | 
 |           .Case("exhaustive", AT_exhaustive) | 
 |           .Case("extern_c", AT_extern_c) | 
 |           .Case("system", AT_system) | 
 |           .Default(AT_unknown); | 
 |     switch (Attribute) { | 
 |     case AT_unknown: | 
 |       Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute) | 
 |         << Tok.getString(); | 
 |       break; | 
 |  | 
 |     case AT_system: | 
 |       Attrs.IsSystem = true; | 
 |       break; | 
 |  | 
 |     case AT_extern_c: | 
 |       Attrs.IsExternC = true; | 
 |       break; | 
 |  | 
 |     case AT_exhaustive: | 
 |       Attrs.IsExhaustive = true; | 
 |       break; | 
 |     } | 
 |     consumeToken(); | 
 |  | 
 |     // Consume the ']'. | 
 |     if (!Tok.is(MMToken::RSquare)) { | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare); | 
 |       Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match); | 
 |       skipUntil(MMToken::RSquare); | 
 |       HadError = true; | 
 |     } | 
 |  | 
 |     if (Tok.is(MMToken::RSquare)) | 
 |       consumeToken(); | 
 |   } | 
 |  | 
 |   return HadError; | 
 | } | 
 |  | 
 | /// \brief Parse a module map file. | 
 | /// | 
 | ///   module-map-file: | 
 | ///     module-declaration* | 
 | bool ModuleMapParser::parseModuleMapFile() { | 
 |   do { | 
 |     switch (Tok.Kind) { | 
 |     case MMToken::EndOfFile: | 
 |       return HadError; | 
 |        | 
 |     case MMToken::ExplicitKeyword: | 
 |     case MMToken::ExternKeyword: | 
 |     case MMToken::ModuleKeyword: | 
 |     case MMToken::FrameworkKeyword: | 
 |       parseModuleDecl(); | 
 |       break; | 
 |  | 
 |     case MMToken::Comma: | 
 |     case MMToken::ConfigMacros: | 
 |     case MMToken::Conflict: | 
 |     case MMToken::Exclaim: | 
 |     case MMToken::ExcludeKeyword: | 
 |     case MMToken::ExportKeyword: | 
 |     case MMToken::HeaderKeyword: | 
 |     case MMToken::Identifier: | 
 |     case MMToken::LBrace: | 
 |     case MMToken::LinkKeyword: | 
 |     case MMToken::LSquare: | 
 |     case MMToken::Period: | 
 |     case MMToken::PrivateKeyword: | 
 |     case MMToken::RBrace: | 
 |     case MMToken::RSquare: | 
 |     case MMToken::RequiresKeyword: | 
 |     case MMToken::Star: | 
 |     case MMToken::StringLiteral: | 
 |     case MMToken::UmbrellaKeyword: | 
 |     case MMToken::UseKeyword: | 
 |       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); | 
 |       HadError = true; | 
 |       consumeToken(); | 
 |       break; | 
 |     } | 
 |   } while (true); | 
 | } | 
 |  | 
 | bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) { | 
 |   llvm::DenseMap<const FileEntry *, bool>::iterator Known | 
 |     = ParsedModuleMap.find(File); | 
 |   if (Known != ParsedModuleMap.end()) | 
 |     return Known->second; | 
 |  | 
 |   assert(Target && "Missing target information"); | 
 |   auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; | 
 |   FileID ID = SourceMgr.createFileID(File, SourceLocation(), FileCharacter); | 
 |   const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID); | 
 |   if (!Buffer) | 
 |     return ParsedModuleMap[File] = true; | 
 |  | 
 |   // Find the directory for the module. For frameworks, that may require going | 
 |   // up from the 'Modules' directory. | 
 |   const DirectoryEntry *Dir = File->getDir(); | 
 |   StringRef DirName(Dir->getName()); | 
 |   if (llvm::sys::path::filename(DirName) == "Modules") { | 
 |     DirName = llvm::sys::path::parent_path(DirName); | 
 |     if (DirName.endswith(".framework")) | 
 |       Dir = SourceMgr.getFileManager().getDirectory(DirName); | 
 |     assert(Dir && "parent must exist"); | 
 |   } | 
 |    | 
 |   // Parse this module map file. | 
 |   Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts); | 
 |   ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir, | 
 |                          BuiltinIncludeDir, IsSystem); | 
 |   bool Result = Parser.parseModuleMapFile(); | 
 |   ParsedModuleMap[File] = Result; | 
 |   return Result; | 
 | } |