Path: blob/main/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp
35232 views
//===- ModuleMap.cpp - Describe the layout of modules ---------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the ModuleMap implementation, which describes the layout9// of a module as it relates to headers.10//11//===----------------------------------------------------------------------===//1213#include "clang/Lex/ModuleMap.h"14#include "clang/Basic/CharInfo.h"15#include "clang/Basic/Diagnostic.h"16#include "clang/Basic/FileManager.h"17#include "clang/Basic/LLVM.h"18#include "clang/Basic/LangOptions.h"19#include "clang/Basic/Module.h"20#include "clang/Basic/SourceLocation.h"21#include "clang/Basic/SourceManager.h"22#include "clang/Basic/TargetInfo.h"23#include "clang/Lex/HeaderSearch.h"24#include "clang/Lex/HeaderSearchOptions.h"25#include "clang/Lex/LexDiagnostic.h"26#include "clang/Lex/Lexer.h"27#include "clang/Lex/LiteralSupport.h"28#include "clang/Lex/Token.h"29#include "llvm/ADT/DenseMap.h"30#include "llvm/ADT/STLExtras.h"31#include "llvm/ADT/SmallPtrSet.h"32#include "llvm/ADT/SmallString.h"33#include "llvm/ADT/SmallVector.h"34#include "llvm/ADT/StringMap.h"35#include "llvm/ADT/StringRef.h"36#include "llvm/ADT/StringSwitch.h"37#include "llvm/Support/Allocator.h"38#include "llvm/Support/Compiler.h"39#include "llvm/Support/ErrorHandling.h"40#include "llvm/Support/MemoryBuffer.h"41#include "llvm/Support/Path.h"42#include "llvm/Support/VirtualFileSystem.h"43#include "llvm/Support/raw_ostream.h"44#include <algorithm>45#include <cassert>46#include <cstdint>47#include <cstring>48#include <optional>49#include <string>50#include <system_error>51#include <utility>5253using namespace clang;5455void ModuleMapCallbacks::anchor() {}5657void ModuleMap::resolveLinkAsDependencies(Module *Mod) {58auto PendingLinkAs = PendingLinkAsModule.find(Mod->Name);59if (PendingLinkAs != PendingLinkAsModule.end()) {60for (auto &Name : PendingLinkAs->second) {61auto *M = findModule(Name.getKey());62if (M)63M->UseExportAsModuleLinkName = true;64}65}66}6768void ModuleMap::addLinkAsDependency(Module *Mod) {69if (findModule(Mod->ExportAsModule))70Mod->UseExportAsModuleLinkName = true;71else72PendingLinkAsModule[Mod->ExportAsModule].insert(Mod->Name);73}7475Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {76switch ((int)Role) {77case NormalHeader:78return Module::HK_Normal;79case PrivateHeader:80return Module::HK_Private;81case TextualHeader:82return Module::HK_Textual;83case PrivateHeader | TextualHeader:84return Module::HK_PrivateTextual;85case ExcludedHeader:86return Module::HK_Excluded;87}88llvm_unreachable("unknown header role");89}9091ModuleMap::ModuleHeaderRole92ModuleMap::headerKindToRole(Module::HeaderKind Kind) {93switch ((int)Kind) {94case Module::HK_Normal:95return NormalHeader;96case Module::HK_Private:97return PrivateHeader;98case Module::HK_Textual:99return TextualHeader;100case Module::HK_PrivateTextual:101return ModuleHeaderRole(PrivateHeader | TextualHeader);102case Module::HK_Excluded:103return ExcludedHeader;104}105llvm_unreachable("unknown header kind");106}107108bool ModuleMap::isModular(ModuleHeaderRole Role) {109return !(Role & (ModuleMap::TextualHeader | ModuleMap::ExcludedHeader));110}111112Module::ExportDecl113ModuleMap::resolveExport(Module *Mod,114const Module::UnresolvedExportDecl &Unresolved,115bool Complain) const {116// We may have just a wildcard.117if (Unresolved.Id.empty()) {118assert(Unresolved.Wildcard && "Invalid unresolved export");119return Module::ExportDecl(nullptr, true);120}121122// Resolve the module-id.123Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain);124if (!Context)125return {};126127return Module::ExportDecl(Context, Unresolved.Wildcard);128}129130Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,131bool Complain) const {132// Find the starting module.133Module *Context = lookupModuleUnqualified(Id[0].first, Mod);134if (!Context) {135if (Complain)136Diags.Report(Id[0].second, diag::err_mmap_missing_module_unqualified)137<< Id[0].first << Mod->getFullModuleName();138139return nullptr;140}141142// Dig into the module path.143for (unsigned I = 1, N = Id.size(); I != N; ++I) {144Module *Sub = lookupModuleQualified(Id[I].first, Context);145if (!Sub) {146if (Complain)147Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)148<< Id[I].first << Context->getFullModuleName()149<< SourceRange(Id[0].second, Id[I-1].second);150151return nullptr;152}153154Context = Sub;155}156157return Context;158}159160/// Append to \p Paths the set of paths needed to get to the161/// subframework in which the given module lives.162static void appendSubframeworkPaths(Module *Mod,163SmallVectorImpl<char> &Path) {164// Collect the framework names from the given module to the top-level module.165SmallVector<StringRef, 2> Paths;166for (; Mod; Mod = Mod->Parent) {167if (Mod->IsFramework)168Paths.push_back(Mod->Name);169}170171if (Paths.empty())172return;173174// Add Frameworks/Name.framework for each subframework.175for (StringRef Framework : llvm::drop_begin(llvm::reverse(Paths)))176llvm::sys::path::append(Path, "Frameworks", Framework + ".framework");177}178179OptionalFileEntryRef ModuleMap::findHeader(180Module *M, const Module::UnresolvedHeaderDirective &Header,181SmallVectorImpl<char> &RelativePathName, bool &NeedsFramework) {182// Search for the header file within the module's home directory.183auto Directory = M->Directory;184SmallString<128> FullPathName(Directory->getName());185186auto GetFile = [&](StringRef Filename) -> OptionalFileEntryRef {187auto File =188expectedToOptional(SourceMgr.getFileManager().getFileRef(Filename));189if (!File || (Header.Size && File->getSize() != *Header.Size) ||190(Header.ModTime && File->getModificationTime() != *Header.ModTime))191return std::nullopt;192return *File;193};194195auto GetFrameworkFile = [&]() -> OptionalFileEntryRef {196unsigned FullPathLength = FullPathName.size();197appendSubframeworkPaths(M, RelativePathName);198unsigned RelativePathLength = RelativePathName.size();199200// Check whether this file is in the public headers.201llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);202llvm::sys::path::append(FullPathName, RelativePathName);203if (auto File = GetFile(FullPathName))204return File;205206// Check whether this file is in the private headers.207// Ideally, private modules in the form 'FrameworkName.Private' should208// be defined as 'module FrameworkName.Private', and not as209// 'framework module FrameworkName.Private', since a 'Private.Framework'210// does not usually exist. However, since both are currently widely used211// for private modules, make sure we find the right path in both cases.212if (M->IsFramework && M->Name == "Private")213RelativePathName.clear();214else215RelativePathName.resize(RelativePathLength);216FullPathName.resize(FullPathLength);217llvm::sys::path::append(RelativePathName, "PrivateHeaders",218Header.FileName);219llvm::sys::path::append(FullPathName, RelativePathName);220return GetFile(FullPathName);221};222223if (llvm::sys::path::is_absolute(Header.FileName)) {224RelativePathName.clear();225RelativePathName.append(Header.FileName.begin(), Header.FileName.end());226return GetFile(Header.FileName);227}228229if (M->isPartOfFramework())230return GetFrameworkFile();231232// Lookup for normal headers.233llvm::sys::path::append(RelativePathName, Header.FileName);234llvm::sys::path::append(FullPathName, RelativePathName);235auto NormalHdrFile = GetFile(FullPathName);236237if (!NormalHdrFile && Directory->getName().ends_with(".framework")) {238// The lack of 'framework' keyword in a module declaration it's a simple239// mistake we can diagnose when the header exists within the proper240// framework style path.241FullPathName.assign(Directory->getName());242RelativePathName.clear();243if (GetFrameworkFile()) {244Diags.Report(Header.FileNameLoc,245diag::warn_mmap_incomplete_framework_module_declaration)246<< Header.FileName << M->getFullModuleName();247NeedsFramework = true;248}249return std::nullopt;250}251252return NormalHdrFile;253}254255/// Determine whether the given file name is the name of a builtin256/// header, supplied by Clang to replace, override, or augment existing system257/// headers.258static bool isBuiltinHeaderName(StringRef FileName) {259return llvm::StringSwitch<bool>(FileName)260.Case("float.h", true)261.Case("iso646.h", true)262.Case("limits.h", true)263.Case("stdalign.h", true)264.Case("stdarg.h", true)265.Case("stdatomic.h", true)266.Case("stdbool.h", true)267.Case("stddef.h", true)268.Case("stdint.h", true)269.Case("tgmath.h", true)270.Case("unwind.h", true)271.Default(false);272}273274/// Determine whether the given module name is the name of a builtin275/// module that is cyclic with a system module on some platforms.276static bool isBuiltInModuleName(StringRef ModuleName) {277return llvm::StringSwitch<bool>(ModuleName)278.Case("_Builtin_float", true)279.Case("_Builtin_inttypes", true)280.Case("_Builtin_iso646", true)281.Case("_Builtin_limits", true)282.Case("_Builtin_stdalign", true)283.Case("_Builtin_stdarg", true)284.Case("_Builtin_stdatomic", true)285.Case("_Builtin_stdbool", true)286.Case("_Builtin_stddef", true)287.Case("_Builtin_stdint", true)288.Case("_Builtin_stdnoreturn", true)289.Case("_Builtin_tgmath", true)290.Case("_Builtin_unwind", true)291.Default(false);292}293294void ModuleMap::resolveHeader(Module *Mod,295const Module::UnresolvedHeaderDirective &Header,296bool &NeedsFramework) {297SmallString<128> RelativePathName;298if (OptionalFileEntryRef File =299findHeader(Mod, Header, RelativePathName, NeedsFramework)) {300if (Header.IsUmbrella) {301const DirectoryEntry *UmbrellaDir = &File->getDir().getDirEntry();302if (Module *UmbrellaMod = UmbrellaDirs[UmbrellaDir])303Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)304<< UmbrellaMod->getFullModuleName();305else306// Record this umbrella header.307setUmbrellaHeaderAsWritten(Mod, *File, Header.FileName,308RelativePathName.str());309} else {310Module::Header H = {Header.FileName, std::string(RelativePathName),311*File};312addHeader(Mod, H, headerKindToRole(Header.Kind));313}314} else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {315// There's a builtin header but no corresponding on-disk header. Assume316// this was supposed to modularize the builtin header alone.317} else if (Header.Kind == Module::HK_Excluded) {318// Ignore missing excluded header files. They're optional anyway.319} else {320// If we find a module that has a missing header, we mark this module as321// unavailable and store the header directive for displaying diagnostics.322Mod->MissingHeaders.push_back(Header);323// A missing header with stat information doesn't make the module324// unavailable; this keeps our behavior consistent as headers are lazily325// resolved. (Such a module still can't be built though, except from326// preprocessed source.)327if (!Header.Size && !Header.ModTime)328Mod->markUnavailable(/*Unimportable=*/false);329}330}331332bool ModuleMap::resolveAsBuiltinHeader(333Module *Mod, const Module::UnresolvedHeaderDirective &Header) {334if (Header.Kind == Module::HK_Excluded ||335llvm::sys::path::is_absolute(Header.FileName) ||336Mod->isPartOfFramework() || !Mod->IsSystem || Header.IsUmbrella ||337!BuiltinIncludeDir || BuiltinIncludeDir == Mod->Directory ||338!LangOpts.BuiltinHeadersInSystemModules || !isBuiltinHeaderName(Header.FileName))339return false;340341// This is a system module with a top-level header. This header342// may have a counterpart (or replacement) in the set of headers343// supplied by Clang. Find that builtin header.344SmallString<128> Path;345llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName);346auto File = SourceMgr.getFileManager().getOptionalFileRef(Path);347if (!File)348return false;349350Module::Header H = {Header.FileName, Header.FileName, *File};351auto Role = headerKindToRole(Header.Kind);352addHeader(Mod, H, Role);353return true;354}355356ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,357const LangOptions &LangOpts, const TargetInfo *Target,358HeaderSearch &HeaderInfo)359: SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target),360HeaderInfo(HeaderInfo) {361MMapLangOpts.LineComment = true;362}363364ModuleMap::~ModuleMap() {365for (auto &M : Modules)366delete M.getValue();367for (auto *M : ShadowModules)368delete M;369}370371void ModuleMap::setTarget(const TargetInfo &Target) {372assert((!this->Target || this->Target == &Target) &&373"Improper target override");374this->Target = &Target;375}376377/// "Sanitize" a filename so that it can be used as an identifier.378static StringRef sanitizeFilenameAsIdentifier(StringRef Name,379SmallVectorImpl<char> &Buffer) {380if (Name.empty())381return Name;382383if (!isValidAsciiIdentifier(Name)) {384// If we don't already have something with the form of an identifier,385// create a buffer with the sanitized name.386Buffer.clear();387if (isDigit(Name[0]))388Buffer.push_back('_');389Buffer.reserve(Buffer.size() + Name.size());390for (unsigned I = 0, N = Name.size(); I != N; ++I) {391if (isAsciiIdentifierContinue(Name[I]))392Buffer.push_back(Name[I]);393else394Buffer.push_back('_');395}396397Name = StringRef(Buffer.data(), Buffer.size());398}399400while (llvm::StringSwitch<bool>(Name)401#define KEYWORD(Keyword,Conditions) .Case(#Keyword, true)402#define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true)403#include "clang/Basic/TokenKinds.def"404.Default(false)) {405if (Name.data() != Buffer.data())406Buffer.append(Name.begin(), Name.end());407Buffer.push_back('_');408Name = StringRef(Buffer.data(), Buffer.size());409}410411return Name;412}413414bool ModuleMap::isBuiltinHeader(FileEntryRef File) {415return File.getDir() == BuiltinIncludeDir && LangOpts.BuiltinHeadersInSystemModules &&416isBuiltinHeaderName(llvm::sys::path::filename(File.getName()));417}418419bool ModuleMap::shouldImportRelativeToBuiltinIncludeDir(StringRef FileName,420Module *Module) const {421return LangOpts.BuiltinHeadersInSystemModules && BuiltinIncludeDir &&422Module->IsSystem && !Module->isPartOfFramework() &&423isBuiltinHeaderName(FileName);424}425426ModuleMap::HeadersMap::iterator ModuleMap::findKnownHeader(FileEntryRef File) {427resolveHeaderDirectives(File);428HeadersMap::iterator Known = Headers.find(File);429if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&430Known == Headers.end() && ModuleMap::isBuiltinHeader(File)) {431HeaderInfo.loadTopLevelSystemModules();432return Headers.find(File);433}434return Known;435}436437ModuleMap::KnownHeader ModuleMap::findHeaderInUmbrellaDirs(438FileEntryRef File, SmallVectorImpl<DirectoryEntryRef> &IntermediateDirs) {439if (UmbrellaDirs.empty())440return {};441442OptionalDirectoryEntryRef Dir = File.getDir();443444// Note: as an egregious but useful hack we use the real path here, because445// frameworks moving from top-level frameworks to embedded frameworks tend446// to be symlinked from the top-level location to the embedded location,447// and we need to resolve lookups as if we had found the embedded location.448StringRef DirName = SourceMgr.getFileManager().getCanonicalName(*Dir);449450// Keep walking up the directory hierarchy, looking for a directory with451// an umbrella header.452do {453auto KnownDir = UmbrellaDirs.find(*Dir);454if (KnownDir != UmbrellaDirs.end())455return KnownHeader(KnownDir->second, NormalHeader);456457IntermediateDirs.push_back(*Dir);458459// Retrieve our parent path.460DirName = llvm::sys::path::parent_path(DirName);461if (DirName.empty())462break;463464// Resolve the parent path to a directory entry.465Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName);466} while (Dir);467return {};468}469470static bool violatesPrivateInclude(Module *RequestingModule,471const FileEntry *IncFileEnt,472ModuleMap::KnownHeader Header) {473#ifndef NDEBUG474if (Header.getRole() & ModuleMap::PrivateHeader) {475// Check for consistency between the module header role476// as obtained from the lookup and as obtained from the module.477// This check is not cheap, so enable it only for debugging.478bool IsPrivate = false;479SmallVectorImpl<Module::Header> *HeaderList[] = {480&Header.getModule()->Headers[Module::HK_Private],481&Header.getModule()->Headers[Module::HK_PrivateTextual]};482for (auto *Hs : HeaderList)483IsPrivate |= llvm::any_of(484*Hs, [&](const Module::Header &H) { return H.Entry == IncFileEnt; });485assert(IsPrivate && "inconsistent headers and roles");486}487#endif488return !Header.isAccessibleFrom(RequestingModule);489}490491static Module *getTopLevelOrNull(Module *M) {492return M ? M->getTopLevelModule() : nullptr;493}494495void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,496bool RequestingModuleIsModuleInterface,497SourceLocation FilenameLoc,498StringRef Filename, FileEntryRef File) {499// No errors for indirect modules. This may be a bit of a problem for modules500// with no source files.501if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))502return;503504if (RequestingModule) {505resolveUses(RequestingModule, /*Complain=*/false);506resolveHeaderDirectives(RequestingModule, /*File=*/std::nullopt);507}508509bool Excluded = false;510Module *Private = nullptr;511Module *NotUsed = nullptr;512513HeadersMap::iterator Known = findKnownHeader(File);514if (Known != Headers.end()) {515for (const KnownHeader &Header : Known->second) {516// Excluded headers don't really belong to a module.517if (Header.getRole() == ModuleMap::ExcludedHeader) {518Excluded = true;519continue;520}521522// Remember private headers for later printing of a diagnostic.523if (violatesPrivateInclude(RequestingModule, File, Header)) {524Private = Header.getModule();525continue;526}527528// If uses need to be specified explicitly, we are only allowed to return529// modules that are explicitly used by the requesting module.530if (RequestingModule && LangOpts.ModulesDeclUse &&531!RequestingModule->directlyUses(Header.getModule())) {532NotUsed = Header.getModule();533continue;534}535536// We have found a module that we can happily use.537return;538}539540Excluded = true;541}542543// We have found a header, but it is private.544if (Private) {545Diags.Report(FilenameLoc, diag::warn_use_of_private_header_outside_module)546<< Filename;547return;548}549550// We have found a module, but we don't use it.551if (NotUsed) {552Diags.Report(FilenameLoc, diag::err_undeclared_use_of_module_indirect)553<< RequestingModule->getTopLevelModule()->Name << Filename554<< NotUsed->Name;555return;556}557558if (Excluded || isHeaderInUmbrellaDirs(File))559return;560561// At this point, only non-modular includes remain.562563if (RequestingModule && LangOpts.ModulesStrictDeclUse) {564Diags.Report(FilenameLoc, diag::err_undeclared_use_of_module)565<< RequestingModule->getTopLevelModule()->Name << Filename;566} else if (RequestingModule && RequestingModuleIsModuleInterface &&567LangOpts.isCompilingModule()) {568// Do not diagnose when we are not compiling a module.569diag::kind DiagID = RequestingModule->getTopLevelModule()->IsFramework ?570diag::warn_non_modular_include_in_framework_module :571diag::warn_non_modular_include_in_module;572Diags.Report(FilenameLoc, DiagID) << RequestingModule->getFullModuleName()573<< File.getName();574}575}576577static bool isBetterKnownHeader(const ModuleMap::KnownHeader &New,578const ModuleMap::KnownHeader &Old) {579// Prefer available modules.580// FIXME: Considering whether the module is available rather than merely581// importable is non-hermetic and can result in surprising behavior for582// prebuilt modules. Consider only checking for importability here.583if (New.getModule()->isAvailable() && !Old.getModule()->isAvailable())584return true;585586// Prefer a public header over a private header.587if ((New.getRole() & ModuleMap::PrivateHeader) !=588(Old.getRole() & ModuleMap::PrivateHeader))589return !(New.getRole() & ModuleMap::PrivateHeader);590591// Prefer a non-textual header over a textual header.592if ((New.getRole() & ModuleMap::TextualHeader) !=593(Old.getRole() & ModuleMap::TextualHeader))594return !(New.getRole() & ModuleMap::TextualHeader);595596// Prefer a non-excluded header over an excluded header.597if ((New.getRole() == ModuleMap::ExcludedHeader) !=598(Old.getRole() == ModuleMap::ExcludedHeader))599return New.getRole() != ModuleMap::ExcludedHeader;600601// Don't have a reason to choose between these. Just keep the first one.602return false;603}604605ModuleMap::KnownHeader ModuleMap::findModuleForHeader(FileEntryRef File,606bool AllowTextual,607bool AllowExcluded) {608auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader {609if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader)610return {};611return R;612};613614HeadersMap::iterator Known = findKnownHeader(File);615if (Known != Headers.end()) {616ModuleMap::KnownHeader Result;617// Iterate over all modules that 'File' is part of to find the best fit.618for (KnownHeader &H : Known->second) {619// Cannot use a module if the header is excluded in it.620if (!AllowExcluded && H.getRole() == ModuleMap::ExcludedHeader)621continue;622// Prefer a header from the source module over all others.623if (H.getModule()->getTopLevelModule() == SourceModule)624return MakeResult(H);625if (!Result || isBetterKnownHeader(H, Result))626Result = H;627}628return MakeResult(Result);629}630631return MakeResult(findOrCreateModuleForHeaderInUmbrellaDir(File));632}633634ModuleMap::KnownHeader635ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) {636assert(!Headers.count(File) && "already have a module for this header");637638SmallVector<DirectoryEntryRef, 2> SkippedDirs;639KnownHeader H = findHeaderInUmbrellaDirs(File, SkippedDirs);640if (H) {641Module *Result = H.getModule();642643// Search up the module stack until we find a module with an umbrella644// directory.645Module *UmbrellaModule = Result;646while (!UmbrellaModule->getEffectiveUmbrellaDir() && UmbrellaModule->Parent)647UmbrellaModule = UmbrellaModule->Parent;648649if (UmbrellaModule->InferSubmodules) {650FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule);651652// Infer submodules for each of the directories we found between653// the directory of the umbrella header and the directory where654// the actual header is located.655bool Explicit = UmbrellaModule->InferExplicitSubmodules;656657for (DirectoryEntryRef SkippedDir : llvm::reverse(SkippedDirs)) {658// Find or create the module that corresponds to this directory name.659SmallString<32> NameBuf;660StringRef Name = sanitizeFilenameAsIdentifier(661llvm::sys::path::stem(SkippedDir.getName()), NameBuf);662Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,663Explicit).first;664InferredModuleAllowedBy[Result] = UmbrellaModuleMap;665Result->IsInferred = true;666667// Associate the module and the directory.668UmbrellaDirs[SkippedDir] = Result;669670// If inferred submodules export everything they import, add a671// wildcard to the set of exports.672if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())673Result->Exports.push_back(Module::ExportDecl(nullptr, true));674}675676// Infer a submodule with the same name as this header file.677SmallString<32> NameBuf;678StringRef Name = sanitizeFilenameAsIdentifier(679llvm::sys::path::stem(File.getName()), NameBuf);680Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,681Explicit).first;682InferredModuleAllowedBy[Result] = UmbrellaModuleMap;683Result->IsInferred = true;684Result->addTopHeader(File);685686// If inferred submodules export everything they import, add a687// wildcard to the set of exports.688if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())689Result->Exports.push_back(Module::ExportDecl(nullptr, true));690} else {691// Record each of the directories we stepped through as being part of692// the module we found, since the umbrella header covers them all.693for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)694UmbrellaDirs[SkippedDirs[I]] = Result;695}696697KnownHeader Header(Result, NormalHeader);698Headers[File].push_back(Header);699return Header;700}701702return {};703}704705ArrayRef<ModuleMap::KnownHeader>706ModuleMap::findAllModulesForHeader(FileEntryRef File) {707HeadersMap::iterator Known = findKnownHeader(File);708if (Known != Headers.end())709return Known->second;710711if (findOrCreateModuleForHeaderInUmbrellaDir(File))712return Headers.find(File)->second;713714return std::nullopt;715}716717ArrayRef<ModuleMap::KnownHeader>718ModuleMap::findResolvedModulesForHeader(FileEntryRef File) const {719// FIXME: Is this necessary?720resolveHeaderDirectives(File);721auto It = Headers.find(File);722if (It == Headers.end())723return std::nullopt;724return It->second;725}726727bool ModuleMap::isHeaderInUnavailableModule(FileEntryRef Header) const {728return isHeaderUnavailableInModule(Header, nullptr);729}730731bool ModuleMap::isHeaderUnavailableInModule(732FileEntryRef Header, const Module *RequestingModule) const {733resolveHeaderDirectives(Header);734HeadersMap::const_iterator Known = Headers.find(Header);735if (Known != Headers.end()) {736for (SmallVectorImpl<KnownHeader>::const_iterator737I = Known->second.begin(),738E = Known->second.end();739I != E; ++I) {740741if (I->getRole() == ModuleMap::ExcludedHeader)742continue;743744if (I->isAvailable() &&745(!RequestingModule ||746I->getModule()->isSubModuleOf(RequestingModule))) {747// When no requesting module is available, the caller is looking if a748// header is part a module by only looking into the module map. This is749// done by warn_uncovered_module_header checks; don't consider textual750// headers part of it in this mode, otherwise we get misleading warnings751// that a umbrella header is not including a textual header.752if (!RequestingModule && I->getRole() == ModuleMap::TextualHeader)753continue;754return false;755}756}757return true;758}759760OptionalDirectoryEntryRef Dir = Header.getDir();761SmallVector<DirectoryEntryRef, 2> SkippedDirs;762StringRef DirName = Dir->getName();763764auto IsUnavailable = [&](const Module *M) {765return !M->isAvailable() && (!RequestingModule ||766M->isSubModuleOf(RequestingModule));767};768769// Keep walking up the directory hierarchy, looking for a directory with770// an umbrella header.771do {772auto KnownDir = UmbrellaDirs.find(*Dir);773if (KnownDir != UmbrellaDirs.end()) {774Module *Found = KnownDir->second;775if (IsUnavailable(Found))776return true;777778// Search up the module stack until we find a module with an umbrella779// directory.780Module *UmbrellaModule = Found;781while (!UmbrellaModule->getEffectiveUmbrellaDir() &&782UmbrellaModule->Parent)783UmbrellaModule = UmbrellaModule->Parent;784785if (UmbrellaModule->InferSubmodules) {786for (DirectoryEntryRef SkippedDir : llvm::reverse(SkippedDirs)) {787// Find or create the module that corresponds to this directory name.788SmallString<32> NameBuf;789StringRef Name = sanitizeFilenameAsIdentifier(790llvm::sys::path::stem(SkippedDir.getName()), NameBuf);791Found = lookupModuleQualified(Name, Found);792if (!Found)793return false;794if (IsUnavailable(Found))795return true;796}797798// Infer a submodule with the same name as this header file.799SmallString<32> NameBuf;800StringRef Name = sanitizeFilenameAsIdentifier(801llvm::sys::path::stem(Header.getName()),802NameBuf);803Found = lookupModuleQualified(Name, Found);804if (!Found)805return false;806}807808return IsUnavailable(Found);809}810811SkippedDirs.push_back(*Dir);812813// Retrieve our parent path.814DirName = llvm::sys::path::parent_path(DirName);815if (DirName.empty())816break;817818// Resolve the parent path to a directory entry.819Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName);820} while (Dir);821822return false;823}824825Module *ModuleMap::findModule(StringRef Name) const {826llvm::StringMap<Module *>::const_iterator Known = Modules.find(Name);827if (Known != Modules.end())828return Known->getValue();829830return nullptr;831}832833Module *ModuleMap::lookupModuleUnqualified(StringRef Name,834Module *Context) const {835for(; Context; Context = Context->Parent) {836if (Module *Sub = lookupModuleQualified(Name, Context))837return Sub;838}839840return findModule(Name);841}842843Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{844if (!Context)845return findModule(Name);846847return Context->findSubmodule(Name);848}849850std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,851Module *Parent,852bool IsFramework,853bool IsExplicit) {854// Try to find an existing module with this name.855if (Module *Sub = lookupModuleQualified(Name, Parent))856return std::make_pair(Sub, false);857858// Create a new module with this name.859Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,860IsExplicit, NumCreatedModules++);861if (!Parent) {862if (LangOpts.CurrentModule == Name)863SourceModule = Result;864Modules[Name] = Result;865ModuleScopeIDs[Result] = CurrentModuleScopeID;866}867return std::make_pair(Result, true);868}869870Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,871Module *Parent) {872auto *Result = new Module("<global>", Loc, Parent, /*IsFramework*/ false,873/*IsExplicit*/ true, NumCreatedModules++);874Result->Kind = Module::ExplicitGlobalModuleFragment;875// If the created module isn't owned by a parent, send it to PendingSubmodules876// to wait for its parent.877if (!Result->Parent)878PendingSubmodules.emplace_back(Result);879return Result;880}881882Module *883ModuleMap::createImplicitGlobalModuleFragmentForModuleUnit(SourceLocation Loc,884Module *Parent) {885assert(Parent && "We should only create an implicit global module fragment "886"in a module purview");887// Note: Here the `IsExplicit` parameter refers to the semantics in clang888// modules. All the non-explicit submodules in clang modules will be exported889// too. Here we simplify the implementation by using the concept.890auto *Result =891new Module("<implicit global>", Loc, Parent, /*IsFramework=*/false,892/*IsExplicit=*/false, NumCreatedModules++);893Result->Kind = Module::ImplicitGlobalModuleFragment;894return Result;895}896897Module *898ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent,899SourceLocation Loc) {900auto *Result =901new Module("<private>", Loc, Parent, /*IsFramework*/ false,902/*IsExplicit*/ true, NumCreatedModules++);903Result->Kind = Module::PrivateModuleFragment;904return Result;905}906907Module *ModuleMap::createModuleUnitWithKind(SourceLocation Loc, StringRef Name,908Module::ModuleKind Kind) {909auto *Result =910new Module(Name, Loc, nullptr, /*IsFramework*/ false,911/*IsExplicit*/ false, NumCreatedModules++);912Result->Kind = Kind;913914// Reparent any current global module fragment as a submodule of this module.915for (auto &Submodule : PendingSubmodules) {916Submodule->setParent(Result);917Submodule.release(); // now owned by parent918}919PendingSubmodules.clear();920return Result;921}922923Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,924StringRef Name) {925assert(LangOpts.CurrentModule == Name && "module name mismatch");926assert(!Modules[Name] && "redefining existing module");927928auto *Result =929createModuleUnitWithKind(Loc, Name, Module::ModuleInterfaceUnit);930Modules[Name] = SourceModule = Result;931932// Mark the main source file as being within the newly-created module so that933// declarations and macros are properly visibility-restricted to it.934auto MainFile = SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID());935assert(MainFile && "no input file for module interface");936Headers[*MainFile].push_back(KnownHeader(Result, PrivateHeader));937938return Result;939}940941Module *ModuleMap::createModuleForImplementationUnit(SourceLocation Loc,942StringRef Name) {943assert(LangOpts.CurrentModule == Name && "module name mismatch");944// The interface for this implementation must exist and be loaded.945assert(Modules[Name] && Modules[Name]->Kind == Module::ModuleInterfaceUnit &&946"creating implementation module without an interface");947948// Create an entry in the modules map to own the implementation unit module.949// User module names must not start with a period (so that this cannot clash950// with any legal user-defined module name).951StringRef IName = ".ImplementationUnit";952assert(!Modules[IName] && "multiple implementation units?");953954auto *Result =955createModuleUnitWithKind(Loc, Name, Module::ModuleImplementationUnit);956Modules[IName] = SourceModule = Result;957958// Check that the main file is present.959assert(SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()) &&960"no input file for module implementation");961962return Result;963}964965Module *ModuleMap::createHeaderUnit(SourceLocation Loc, StringRef Name,966Module::Header H) {967assert(LangOpts.CurrentModule == Name && "module name mismatch");968assert(!Modules[Name] && "redefining existing module");969970auto *Result = new Module(Name, Loc, nullptr, /*IsFramework*/ false,971/*IsExplicit*/ false, NumCreatedModules++);972Result->Kind = Module::ModuleHeaderUnit;973Modules[Name] = SourceModule = Result;974addHeader(Result, H, NormalHeader);975return Result;976}977978/// For a framework module, infer the framework against which we979/// should link.980static void inferFrameworkLink(Module *Mod) {981assert(Mod->IsFramework && "Can only infer linking for framework modules");982assert(!Mod->isSubFramework() &&983"Can only infer linking for top-level frameworks");984985StringRef FrameworkName(Mod->Name);986FrameworkName.consume_back("_Private");987Mod->LinkLibraries.push_back(Module::LinkLibrary(FrameworkName.str(),988/*IsFramework=*/true));989}990991Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,992bool IsSystem, Module *Parent) {993Attributes Attrs;994Attrs.IsSystem = IsSystem;995return inferFrameworkModule(FrameworkDir, Attrs, Parent);996}997998Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,999Attributes Attrs, Module *Parent) {1000// Note: as an egregious but useful hack we use the real path here, because1001// we might be looking at an embedded framework that symlinks out to a1002// top-level framework, and we need to infer as if we were naming the1003// top-level framework.1004StringRef FrameworkDirName =1005SourceMgr.getFileManager().getCanonicalName(FrameworkDir);10061007// In case this is a case-insensitive filesystem, use the canonical1008// directory name as the ModuleName, since modules are case-sensitive.1009// FIXME: we should be able to give a fix-it hint for the correct spelling.1010SmallString<32> ModuleNameStorage;1011StringRef ModuleName = sanitizeFilenameAsIdentifier(1012llvm::sys::path::stem(FrameworkDirName), ModuleNameStorage);10131014// Check whether we've already found this module.1015if (Module *Mod = lookupModuleQualified(ModuleName, Parent))1016return Mod;10171018FileManager &FileMgr = SourceMgr.getFileManager();10191020// If the framework has a parent path from which we're allowed to infer1021// a framework module, do so.1022FileID ModuleMapFID;1023if (!Parent) {1024// Determine whether we're allowed to infer a module map.1025bool canInfer = false;1026if (llvm::sys::path::has_parent_path(FrameworkDirName)) {1027// Figure out the parent path.1028StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);1029if (auto ParentDir = FileMgr.getOptionalDirectoryRef(Parent)) {1030// Check whether we have already looked into the parent directory1031// for a module map.1032llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator1033inferred = InferredDirectories.find(*ParentDir);1034if (inferred == InferredDirectories.end()) {1035// We haven't looked here before. Load a module map, if there is1036// one.1037bool IsFrameworkDir = Parent.ends_with(".framework");1038if (OptionalFileEntryRef ModMapFile =1039HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) {1040parseModuleMapFile(*ModMapFile, Attrs.IsSystem, *ParentDir);1041inferred = InferredDirectories.find(*ParentDir);1042}10431044if (inferred == InferredDirectories.end())1045inferred = InferredDirectories.insert(1046std::make_pair(*ParentDir, InferredDirectory())).first;1047}10481049if (inferred->second.InferModules) {1050// We're allowed to infer for this directory, but make sure it's okay1051// to infer this particular module.1052StringRef Name = llvm::sys::path::stem(FrameworkDirName);1053canInfer =1054!llvm::is_contained(inferred->second.ExcludedModules, Name);10551056Attrs.IsSystem |= inferred->second.Attrs.IsSystem;1057Attrs.IsExternC |= inferred->second.Attrs.IsExternC;1058Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive;1059Attrs.NoUndeclaredIncludes |=1060inferred->second.Attrs.NoUndeclaredIncludes;1061ModuleMapFID = inferred->second.ModuleMapFID;1062}1063}1064}10651066// If we're not allowed to infer a framework module, don't.1067if (!canInfer)1068return nullptr;1069} else {1070ModuleMapFID = getModuleMapFileIDForUniquing(Parent);1071}10721073// Look for an umbrella header.1074SmallString<128> UmbrellaName = FrameworkDir.getName();1075llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");1076auto UmbrellaHeader = FileMgr.getOptionalFileRef(UmbrellaName);10771078// FIXME: If there's no umbrella header, we could probably scan the1079// framework to load *everything*. But, it's not clear that this is a good1080// idea.1081if (!UmbrellaHeader)1082return nullptr;10831084Module *Result = new Module(ModuleName, SourceLocation(), Parent,1085/*IsFramework=*/true, /*IsExplicit=*/false,1086NumCreatedModules++);1087InferredModuleAllowedBy[Result] = ModuleMapFID;1088Result->IsInferred = true;1089if (!Parent) {1090if (LangOpts.CurrentModule == ModuleName)1091SourceModule = Result;1092Modules[ModuleName] = Result;1093ModuleScopeIDs[Result] = CurrentModuleScopeID;1094}10951096Result->IsSystem |= Attrs.IsSystem;1097Result->IsExternC |= Attrs.IsExternC;1098Result->ConfigMacrosExhaustive |= Attrs.IsExhaustive;1099Result->NoUndeclaredIncludes |= Attrs.NoUndeclaredIncludes;1100Result->Directory = FrameworkDir;11011102// Chop off the first framework bit, as that is implied.1103StringRef RelativePath = UmbrellaName.str().substr(1104Result->getTopLevelModule()->Directory->getName().size());1105RelativePath = llvm::sys::path::relative_path(RelativePath);11061107// umbrella header "umbrella-header-name"1108setUmbrellaHeaderAsWritten(Result, *UmbrellaHeader, ModuleName + ".h",1109RelativePath);11101111// export *1112Result->Exports.push_back(Module::ExportDecl(nullptr, true));11131114// module * { export * }1115Result->InferSubmodules = true;1116Result->InferExportWildcard = true;11171118// Look for subframeworks.1119std::error_code EC;1120SmallString<128> SubframeworksDirName = FrameworkDir.getName();1121llvm::sys::path::append(SubframeworksDirName, "Frameworks");1122llvm::sys::path::native(SubframeworksDirName);1123llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();1124for (llvm::vfs::directory_iterator1125Dir = FS.dir_begin(SubframeworksDirName, EC),1126DirEnd;1127Dir != DirEnd && !EC; Dir.increment(EC)) {1128if (!StringRef(Dir->path()).ends_with(".framework"))1129continue;11301131if (auto SubframeworkDir = FileMgr.getOptionalDirectoryRef(Dir->path())) {1132// Note: as an egregious but useful hack, we use the real path here and1133// check whether it is actually a subdirectory of the parent directory.1134// This will not be the case if the 'subframework' is actually a symlink1135// out to a top-level framework.1136StringRef SubframeworkDirName =1137FileMgr.getCanonicalName(*SubframeworkDir);1138bool FoundParent = false;1139do {1140// Get the parent directory name.1141SubframeworkDirName1142= llvm::sys::path::parent_path(SubframeworkDirName);1143if (SubframeworkDirName.empty())1144break;11451146if (auto SubDir = FileMgr.getDirectory(SubframeworkDirName)) {1147if (*SubDir == FrameworkDir) {1148FoundParent = true;1149break;1150}1151}1152} while (true);11531154if (!FoundParent)1155continue;11561157// FIXME: Do we want to warn about subframeworks without umbrella headers?1158inferFrameworkModule(*SubframeworkDir, Attrs, Result);1159}1160}11611162// If the module is a top-level framework, automatically link against the1163// framework.1164if (!Result->isSubFramework())1165inferFrameworkLink(Result);11661167return Result;1168}11691170Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,1171Module *ShadowingModule) {11721173// Create a new module with this name.1174Module *Result =1175new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework,1176/*IsExplicit=*/false, NumCreatedModules++);1177Result->ShadowingModule = ShadowingModule;1178Result->markUnavailable(/*Unimportable*/true);1179ModuleScopeIDs[Result] = CurrentModuleScopeID;1180ShadowModules.push_back(Result);11811182return Result;1183}11841185void ModuleMap::setUmbrellaHeaderAsWritten(1186Module *Mod, FileEntryRef UmbrellaHeader, const Twine &NameAsWritten,1187const Twine &PathRelativeToRootModuleDirectory) {1188Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));1189Mod->Umbrella = UmbrellaHeader;1190Mod->UmbrellaAsWritten = NameAsWritten.str();1191Mod->UmbrellaRelativeToRootModuleDirectory =1192PathRelativeToRootModuleDirectory.str();1193UmbrellaDirs[UmbrellaHeader.getDir()] = Mod;11941195// Notify callbacks that we just added a new header.1196for (const auto &Cb : Callbacks)1197Cb->moduleMapAddUmbrellaHeader(UmbrellaHeader);1198}11991200void ModuleMap::setUmbrellaDirAsWritten(1201Module *Mod, DirectoryEntryRef UmbrellaDir, const Twine &NameAsWritten,1202const Twine &PathRelativeToRootModuleDirectory) {1203Mod->Umbrella = UmbrellaDir;1204Mod->UmbrellaAsWritten = NameAsWritten.str();1205Mod->UmbrellaRelativeToRootModuleDirectory =1206PathRelativeToRootModuleDirectory.str();1207UmbrellaDirs[UmbrellaDir] = Mod;1208}12091210void ModuleMap::addUnresolvedHeader(Module *Mod,1211Module::UnresolvedHeaderDirective Header,1212bool &NeedsFramework) {1213// If there is a builtin counterpart to this file, add it now so it can1214// wrap the system header.1215if (resolveAsBuiltinHeader(Mod, Header)) {1216// If we have both a builtin and system version of the file, the1217// builtin version may want to inject macros into the system header, so1218// force the system header to be treated as a textual header in this1219// case.1220Header.Kind = headerRoleToKind(ModuleMap::ModuleHeaderRole(1221headerKindToRole(Header.Kind) | ModuleMap::TextualHeader));1222Header.HasBuiltinHeader = true;1223}12241225// If possible, don't stat the header until we need to. This requires the1226// user to have provided us with some stat information about the file.1227// FIXME: Add support for lazily stat'ing umbrella headers and excluded1228// headers.1229if ((Header.Size || Header.ModTime) && !Header.IsUmbrella &&1230Header.Kind != Module::HK_Excluded) {1231// We expect more variation in mtime than size, so if we're given both,1232// use the mtime as the key.1233if (Header.ModTime)1234LazyHeadersByModTime[*Header.ModTime].push_back(Mod);1235else1236LazyHeadersBySize[*Header.Size].push_back(Mod);1237Mod->UnresolvedHeaders.push_back(Header);1238return;1239}12401241// We don't have stat information or can't defer looking this file up.1242// Perform the lookup now.1243resolveHeader(Mod, Header, NeedsFramework);1244}12451246void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const {1247auto BySize = LazyHeadersBySize.find(File->getSize());1248if (BySize != LazyHeadersBySize.end()) {1249for (auto *M : BySize->second)1250resolveHeaderDirectives(M, File);1251LazyHeadersBySize.erase(BySize);1252}12531254auto ByModTime = LazyHeadersByModTime.find(File->getModificationTime());1255if (ByModTime != LazyHeadersByModTime.end()) {1256for (auto *M : ByModTime->second)1257resolveHeaderDirectives(M, File);1258LazyHeadersByModTime.erase(ByModTime);1259}1260}12611262void ModuleMap::resolveHeaderDirectives(1263Module *Mod, std::optional<const FileEntry *> File) const {1264bool NeedsFramework = false;1265SmallVector<Module::UnresolvedHeaderDirective, 1> NewHeaders;1266const auto Size = File ? (*File)->getSize() : 0;1267const auto ModTime = File ? (*File)->getModificationTime() : 0;12681269for (auto &Header : Mod->UnresolvedHeaders) {1270if (File && ((Header.ModTime && Header.ModTime != ModTime) ||1271(Header.Size && Header.Size != Size)))1272NewHeaders.push_back(Header);1273else1274// This operation is logically const; we're just changing how we represent1275// the header information for this file.1276const_cast<ModuleMap *>(this)->resolveHeader(Mod, Header, NeedsFramework);1277}1278Mod->UnresolvedHeaders.swap(NewHeaders);1279}12801281void ModuleMap::addHeader(Module *Mod, Module::Header Header,1282ModuleHeaderRole Role, bool Imported) {1283KnownHeader KH(Mod, Role);12841285// Only add each header to the headers list once.1286// FIXME: Should we diagnose if a header is listed twice in the1287// same module definition?1288auto &HeaderList = Headers[Header.Entry];1289if (llvm::is_contained(HeaderList, KH))1290return;12911292HeaderList.push_back(KH);1293Mod->Headers[headerRoleToKind(Role)].push_back(Header);12941295bool isCompilingModuleHeader = Mod->isForBuilding(LangOpts);1296if (!Imported || isCompilingModuleHeader) {1297// When we import HeaderFileInfo, the external source is expected to1298// set the isModuleHeader flag itself.1299HeaderInfo.MarkFileModuleHeader(Header.Entry, Role,1300isCompilingModuleHeader);1301}13021303// Notify callbacks that we just added a new header.1304for (const auto &Cb : Callbacks)1305Cb->moduleMapAddHeader(Header.Entry.getName());1306}13071308FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const {1309if (Module->DefinitionLoc.isInvalid())1310return {};13111312return SourceMgr.getFileID(Module->DefinitionLoc);1313}13141315OptionalFileEntryRef1316ModuleMap::getContainingModuleMapFile(const Module *Module) const {1317return SourceMgr.getFileEntryRefForID(getContainingModuleMapFileID(Module));1318}13191320FileID ModuleMap::getModuleMapFileIDForUniquing(const Module *M) const {1321if (M->IsInferred) {1322assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");1323return InferredModuleAllowedBy.find(M)->second;1324}1325return getContainingModuleMapFileID(M);1326}13271328OptionalFileEntryRef1329ModuleMap::getModuleMapFileForUniquing(const Module *M) const {1330return SourceMgr.getFileEntryRefForID(getModuleMapFileIDForUniquing(M));1331}13321333void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) {1334assert(M->IsInferred && "module not inferred");1335InferredModuleAllowedBy[M] = ModMapFID;1336}13371338std::error_code1339ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl<char> &Path) {1340StringRef Dir = llvm::sys::path::parent_path({Path.data(), Path.size()});13411342// Do not canonicalize within the framework; the module map parser expects1343// Modules/ not Versions/A/Modules.1344if (llvm::sys::path::filename(Dir) == "Modules") {1345StringRef Parent = llvm::sys::path::parent_path(Dir);1346if (Parent.ends_with(".framework"))1347Dir = Parent;1348}13491350FileManager &FM = SourceMgr.getFileManager();1351auto DirEntry = FM.getDirectoryRef(Dir.empty() ? "." : Dir);1352if (!DirEntry)1353return llvm::errorToErrorCode(DirEntry.takeError());13541355// Canonicalize the directory.1356StringRef CanonicalDir = FM.getCanonicalName(*DirEntry);1357if (CanonicalDir != Dir)1358llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir);13591360// In theory, the filename component should also be canonicalized if it1361// on a case-insensitive filesystem. However, the extra canonicalization is1362// expensive and if clang looked up the filename it will always be lowercase.13631364// Remove ., remove redundant separators, and switch to native separators.1365// This is needed for separators between CanonicalDir and the filename.1366llvm::sys::path::remove_dots(Path);13671368return std::error_code();1369}13701371void ModuleMap::addAdditionalModuleMapFile(const Module *M,1372FileEntryRef ModuleMap) {1373AdditionalModMaps[M].insert(ModuleMap);1374}13751376LLVM_DUMP_METHOD void ModuleMap::dump() {1377llvm::errs() << "Modules:";1378for (llvm::StringMap<Module *>::iterator M = Modules.begin(),1379MEnd = Modules.end();1380M != MEnd; ++M)1381M->getValue()->print(llvm::errs(), 2);13821383llvm::errs() << "Headers:";1384for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();1385H != HEnd; ++H) {1386llvm::errs() << " \"" << H->first.getName() << "\" -> ";1387for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(),1388E = H->second.end();1389I != E; ++I) {1390if (I != H->second.begin())1391llvm::errs() << ",";1392llvm::errs() << I->getModule()->getFullModuleName();1393}1394llvm::errs() << "\n";1395}1396}13971398bool ModuleMap::resolveExports(Module *Mod, bool Complain) {1399auto Unresolved = std::move(Mod->UnresolvedExports);1400Mod->UnresolvedExports.clear();1401for (auto &UE : Unresolved) {1402Module::ExportDecl Export = resolveExport(Mod, UE, Complain);1403if (Export.getPointer() || Export.getInt())1404Mod->Exports.push_back(Export);1405else1406Mod->UnresolvedExports.push_back(UE);1407}1408return !Mod->UnresolvedExports.empty();1409}14101411bool ModuleMap::resolveUses(Module *Mod, bool Complain) {1412auto *Top = Mod->getTopLevelModule();1413auto Unresolved = std::move(Top->UnresolvedDirectUses);1414Top->UnresolvedDirectUses.clear();1415for (auto &UDU : Unresolved) {1416Module *DirectUse = resolveModuleId(UDU, Top, Complain);1417if (DirectUse)1418Top->DirectUses.push_back(DirectUse);1419else1420Top->UnresolvedDirectUses.push_back(UDU);1421}1422return !Top->UnresolvedDirectUses.empty();1423}14241425bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {1426auto Unresolved = std::move(Mod->UnresolvedConflicts);1427Mod->UnresolvedConflicts.clear();1428for (auto &UC : Unresolved) {1429if (Module *OtherMod = resolveModuleId(UC.Id, Mod, Complain)) {1430Module::Conflict Conflict;1431Conflict.Other = OtherMod;1432Conflict.Message = UC.Message;1433Mod->Conflicts.push_back(Conflict);1434} else1435Mod->UnresolvedConflicts.push_back(UC);1436}1437return !Mod->UnresolvedConflicts.empty();1438}14391440//----------------------------------------------------------------------------//1441// Module map file parser1442//----------------------------------------------------------------------------//14431444namespace clang {14451446/// A token in a module map file.1447struct MMToken {1448enum TokenKind {1449Comma,1450ConfigMacros,1451Conflict,1452EndOfFile,1453HeaderKeyword,1454Identifier,1455Exclaim,1456ExcludeKeyword,1457ExplicitKeyword,1458ExportKeyword,1459ExportAsKeyword,1460ExternKeyword,1461FrameworkKeyword,1462LinkKeyword,1463ModuleKeyword,1464Period,1465PrivateKeyword,1466UmbrellaKeyword,1467UseKeyword,1468RequiresKeyword,1469Star,1470StringLiteral,1471IntegerLiteral,1472TextualKeyword,1473LBrace,1474RBrace,1475LSquare,1476RSquare1477} Kind;14781479SourceLocation::UIntTy Location;1480unsigned StringLength;1481union {1482// If Kind != IntegerLiteral.1483const char *StringData;14841485// If Kind == IntegerLiteral.1486uint64_t IntegerValue;1487};14881489void clear() {1490Kind = EndOfFile;1491Location = 0;1492StringLength = 0;1493StringData = nullptr;1494}14951496bool is(TokenKind K) const { return Kind == K; }14971498SourceLocation getLocation() const {1499return SourceLocation::getFromRawEncoding(Location);1500}15011502uint64_t getInteger() const {1503return Kind == IntegerLiteral ? IntegerValue : 0;1504}15051506StringRef getString() const {1507return Kind == IntegerLiteral ? StringRef()1508: StringRef(StringData, StringLength);1509}1510};15111512class ModuleMapParser {1513Lexer &L;1514SourceManager &SourceMgr;15151516/// Default target information, used only for string literal1517/// parsing.1518const TargetInfo *Target;15191520DiagnosticsEngine &Diags;1521ModuleMap ⤅15221523/// The current module map file.1524FileID ModuleMapFID;15251526/// Source location of most recent parsed module declaration1527SourceLocation CurrModuleDeclLoc;15281529/// The directory that file names in this module map file should1530/// be resolved relative to.1531DirectoryEntryRef Directory;15321533/// Whether this module map is in a system header directory.1534bool IsSystem;15351536/// Whether an error occurred.1537bool HadError = false;15381539/// Stores string data for the various string literals referenced1540/// during parsing.1541llvm::BumpPtrAllocator StringData;15421543/// The current token.1544MMToken Tok;15451546/// The active module.1547Module *ActiveModule = nullptr;15481549/// Whether a module uses the 'requires excluded' hack to mark its1550/// contents as 'textual'.1551///1552/// On older Darwin SDK versions, 'requires excluded' is used to mark the1553/// contents of the Darwin.C.excluded (assert.h) and Tcl.Private modules as1554/// non-modular headers. For backwards compatibility, we continue to1555/// support this idiom for just these modules, and map the headers to1556/// 'textual' to match the original intent.1557llvm::SmallPtrSet<Module *, 2> UsesRequiresExcludedHack;15581559/// Consume the current token and return its location.1560SourceLocation consumeToken();15611562/// Skip tokens until we reach the a token with the given kind1563/// (or the end of the file).1564void skipUntil(MMToken::TokenKind K);15651566bool parseModuleId(ModuleId &Id);1567void parseModuleDecl();1568void parseExternModuleDecl();1569void parseRequiresDecl();1570void parseHeaderDecl(MMToken::TokenKind, SourceLocation LeadingLoc);1571void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);1572void parseExportDecl();1573void parseExportAsDecl();1574void parseUseDecl();1575void parseLinkDecl();1576void parseConfigMacros();1577void parseConflict();1578void parseInferredModuleDecl(bool Framework, bool Explicit);15791580/// Private modules are canonicalized as Foo_Private. Clang provides extra1581/// module map search logic to find the appropriate private module when PCH1582/// is used with implicit module maps. Warn when private modules are written1583/// in other ways (FooPrivate and Foo.Private), providing notes and fixits.1584void diagnosePrivateModules(SourceLocation ExplicitLoc,1585SourceLocation FrameworkLoc);15861587using Attributes = ModuleMap::Attributes;15881589bool parseOptionalAttributes(Attributes &Attrs);15901591public:1592ModuleMapParser(Lexer &L, SourceManager &SourceMgr,1593const TargetInfo *Target, DiagnosticsEngine &Diags,1594ModuleMap &Map, FileID ModuleMapFID,1595DirectoryEntryRef Directory, bool IsSystem)1596: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),1597ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) {1598Tok.clear();1599consumeToken();1600}16011602bool parseModuleMapFile();16031604bool terminatedByDirective() { return false; }1605SourceLocation getLocation() { return Tok.getLocation(); }1606};16071608} // namespace clang16091610SourceLocation ModuleMapParser::consumeToken() {1611SourceLocation Result = Tok.getLocation();16121613retry:1614Tok.clear();1615Token LToken;1616L.LexFromRawLexer(LToken);1617Tok.Location = LToken.getLocation().getRawEncoding();1618switch (LToken.getKind()) {1619case tok::raw_identifier: {1620StringRef RI = LToken.getRawIdentifier();1621Tok.StringData = RI.data();1622Tok.StringLength = RI.size();1623Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)1624.Case("config_macros", MMToken::ConfigMacros)1625.Case("conflict", MMToken::Conflict)1626.Case("exclude", MMToken::ExcludeKeyword)1627.Case("explicit", MMToken::ExplicitKeyword)1628.Case("export", MMToken::ExportKeyword)1629.Case("export_as", MMToken::ExportAsKeyword)1630.Case("extern", MMToken::ExternKeyword)1631.Case("framework", MMToken::FrameworkKeyword)1632.Case("header", MMToken::HeaderKeyword)1633.Case("link", MMToken::LinkKeyword)1634.Case("module", MMToken::ModuleKeyword)1635.Case("private", MMToken::PrivateKeyword)1636.Case("requires", MMToken::RequiresKeyword)1637.Case("textual", MMToken::TextualKeyword)1638.Case("umbrella", MMToken::UmbrellaKeyword)1639.Case("use", MMToken::UseKeyword)1640.Default(MMToken::Identifier);1641break;1642}16431644case tok::comma:1645Tok.Kind = MMToken::Comma;1646break;16471648case tok::eof:1649Tok.Kind = MMToken::EndOfFile;1650break;16511652case tok::l_brace:1653Tok.Kind = MMToken::LBrace;1654break;16551656case tok::l_square:1657Tok.Kind = MMToken::LSquare;1658break;16591660case tok::period:1661Tok.Kind = MMToken::Period;1662break;16631664case tok::r_brace:1665Tok.Kind = MMToken::RBrace;1666break;16671668case tok::r_square:1669Tok.Kind = MMToken::RSquare;1670break;16711672case tok::star:1673Tok.Kind = MMToken::Star;1674break;16751676case tok::exclaim:1677Tok.Kind = MMToken::Exclaim;1678break;16791680case tok::string_literal: {1681if (LToken.hasUDSuffix()) {1682Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);1683HadError = true;1684goto retry;1685}16861687// Parse the string literal.1688LangOptions LangOpts;1689StringLiteralParser StringLiteral(LToken, SourceMgr, LangOpts, *Target);1690if (StringLiteral.hadError)1691goto retry;16921693// Copy the string literal into our string data allocator.1694unsigned Length = StringLiteral.GetStringLength();1695char *Saved = StringData.Allocate<char>(Length + 1);1696memcpy(Saved, StringLiteral.GetString().data(), Length);1697Saved[Length] = 0;16981699// Form the token.1700Tok.Kind = MMToken::StringLiteral;1701Tok.StringData = Saved;1702Tok.StringLength = Length;1703break;1704}17051706case tok::numeric_constant: {1707// We don't support any suffixes or other complications.1708SmallString<32> SpellingBuffer;1709SpellingBuffer.resize(LToken.getLength() + 1);1710const char *Start = SpellingBuffer.data();1711unsigned Length =1712Lexer::getSpelling(LToken, Start, SourceMgr, Map.LangOpts);1713uint64_t Value;1714if (StringRef(Start, Length).getAsInteger(0, Value)) {1715Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);1716HadError = true;1717goto retry;1718}17191720Tok.Kind = MMToken::IntegerLiteral;1721Tok.IntegerValue = Value;1722break;1723}17241725case tok::comment:1726goto retry;17271728case tok::hash:1729// A module map can be terminated prematurely by1730// #pragma clang module contents1731// When building the module, we'll treat the rest of the file as the1732// contents of the module.1733{1734auto NextIsIdent = [&](StringRef Str) -> bool {1735L.LexFromRawLexer(LToken);1736return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&1737LToken.getRawIdentifier() == Str;1738};1739if (NextIsIdent("pragma") && NextIsIdent("clang") &&1740NextIsIdent("module") && NextIsIdent("contents")) {1741Tok.Kind = MMToken::EndOfFile;1742break;1743}1744}1745[[fallthrough]];17461747default:1748Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);1749HadError = true;1750goto retry;1751}17521753return Result;1754}17551756void ModuleMapParser::skipUntil(MMToken::TokenKind K) {1757unsigned braceDepth = 0;1758unsigned squareDepth = 0;1759do {1760switch (Tok.Kind) {1761case MMToken::EndOfFile:1762return;17631764case MMToken::LBrace:1765if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)1766return;17671768++braceDepth;1769break;17701771case MMToken::LSquare:1772if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)1773return;17741775++squareDepth;1776break;17771778case MMToken::RBrace:1779if (braceDepth > 0)1780--braceDepth;1781else if (Tok.is(K))1782return;1783break;17841785case MMToken::RSquare:1786if (squareDepth > 0)1787--squareDepth;1788else if (Tok.is(K))1789return;1790break;17911792default:1793if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))1794return;1795break;1796}17971798consumeToken();1799} while (true);1800}18011802/// Parse a module-id.1803///1804/// module-id:1805/// identifier1806/// identifier '.' module-id1807///1808/// \returns true if an error occurred, false otherwise.1809bool ModuleMapParser::parseModuleId(ModuleId &Id) {1810Id.clear();1811do {1812if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {1813Id.push_back(1814std::make_pair(std::string(Tok.getString()), Tok.getLocation()));1815consumeToken();1816} else {1817Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);1818return true;1819}18201821if (!Tok.is(MMToken::Period))1822break;18231824consumeToken();1825} while (true);18261827return false;1828}18291830namespace {18311832/// Enumerates the known attributes.1833enum AttributeKind {1834/// An unknown attribute.1835AT_unknown,18361837/// The 'system' attribute.1838AT_system,18391840/// The 'extern_c' attribute.1841AT_extern_c,18421843/// The 'exhaustive' attribute.1844AT_exhaustive,18451846/// The 'no_undeclared_includes' attribute.1847AT_no_undeclared_includes1848};18491850} // namespace18511852/// Private modules are canonicalized as Foo_Private. Clang provides extra1853/// module map search logic to find the appropriate private module when PCH1854/// is used with implicit module maps. Warn when private modules are written1855/// in other ways (FooPrivate and Foo.Private), providing notes and fixits.1856void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,1857SourceLocation FrameworkLoc) {1858auto GenNoteAndFixIt = [&](StringRef BadName, StringRef Canonical,1859const Module *M, SourceRange ReplLoc) {1860auto D = Diags.Report(ActiveModule->DefinitionLoc,1861diag::note_mmap_rename_top_level_private_module);1862D << BadName << M->Name;1863D << FixItHint::CreateReplacement(ReplLoc, Canonical);1864};18651866for (auto E = Map.module_begin(); E != Map.module_end(); ++E) {1867auto const *M = E->getValue();1868if (M->Directory != ActiveModule->Directory)1869continue;18701871SmallString<128> FullName(ActiveModule->getFullModuleName());1872if (!FullName.starts_with(M->Name) && !FullName.ends_with("Private"))1873continue;1874SmallString<128> FixedPrivModDecl;1875SmallString<128> Canonical(M->Name);1876Canonical.append("_Private");18771878// Foo.Private -> Foo_Private1879if (ActiveModule->Parent && ActiveModule->Name == "Private" && !M->Parent &&1880M->Name == ActiveModule->Parent->Name) {1881Diags.Report(ActiveModule->DefinitionLoc,1882diag::warn_mmap_mismatched_private_submodule)1883<< FullName;18841885SourceLocation FixItInitBegin = CurrModuleDeclLoc;1886if (FrameworkLoc.isValid())1887FixItInitBegin = FrameworkLoc;1888if (ExplicitLoc.isValid())1889FixItInitBegin = ExplicitLoc;18901891if (FrameworkLoc.isValid() || ActiveModule->Parent->IsFramework)1892FixedPrivModDecl.append("framework ");1893FixedPrivModDecl.append("module ");1894FixedPrivModDecl.append(Canonical);18951896GenNoteAndFixIt(FullName, FixedPrivModDecl, M,1897SourceRange(FixItInitBegin, ActiveModule->DefinitionLoc));1898continue;1899}19001901// FooPrivate and whatnots -> Foo_Private1902if (!ActiveModule->Parent && !M->Parent && M->Name != ActiveModule->Name &&1903ActiveModule->Name != Canonical) {1904Diags.Report(ActiveModule->DefinitionLoc,1905diag::warn_mmap_mismatched_private_module_name)1906<< ActiveModule->Name;1907GenNoteAndFixIt(ActiveModule->Name, Canonical, M,1908SourceRange(ActiveModule->DefinitionLoc));1909}1910}1911}19121913/// Parse a module declaration.1914///1915/// module-declaration:1916/// 'extern' 'module' module-id string-literal1917/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]1918/// { module-member* }1919///1920/// module-member:1921/// requires-declaration1922/// header-declaration1923/// submodule-declaration1924/// export-declaration1925/// export-as-declaration1926/// link-declaration1927///1928/// submodule-declaration:1929/// module-declaration1930/// inferred-submodule-declaration1931void ModuleMapParser::parseModuleDecl() {1932assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||1933Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword));1934if (Tok.is(MMToken::ExternKeyword)) {1935parseExternModuleDecl();1936return;1937}19381939// Parse 'explicit' or 'framework' keyword, if present.1940SourceLocation ExplicitLoc;1941SourceLocation FrameworkLoc;1942bool Explicit = false;1943bool Framework = false;19441945// Parse 'explicit' keyword, if present.1946if (Tok.is(MMToken::ExplicitKeyword)) {1947ExplicitLoc = consumeToken();1948Explicit = true;1949}19501951// Parse 'framework' keyword, if present.1952if (Tok.is(MMToken::FrameworkKeyword)) {1953FrameworkLoc = consumeToken();1954Framework = true;1955}19561957// Parse 'module' keyword.1958if (!Tok.is(MMToken::ModuleKeyword)) {1959Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);1960consumeToken();1961HadError = true;1962return;1963}1964CurrModuleDeclLoc = consumeToken(); // 'module' keyword19651966// If we have a wildcard for the module name, this is an inferred submodule.1967// Parse it.1968if (Tok.is(MMToken::Star))1969return parseInferredModuleDecl(Framework, Explicit);19701971// Parse the module name.1972ModuleId Id;1973if (parseModuleId(Id)) {1974HadError = true;1975return;1976}19771978if (ActiveModule) {1979if (Id.size() > 1) {1980Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)1981<< SourceRange(Id.front().second, Id.back().second);19821983HadError = true;1984return;1985}1986} else if (Id.size() == 1 && Explicit) {1987// Top-level modules can't be explicit.1988Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);1989Explicit = false;1990ExplicitLoc = SourceLocation();1991HadError = true;1992}19931994Module *PreviousActiveModule = ActiveModule;1995if (Id.size() > 1) {1996// This module map defines a submodule. Go find the module of which it1997// is a submodule.1998ActiveModule = nullptr;1999const Module *TopLevelModule = nullptr;2000for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {2001if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {2002if (I == 0)2003TopLevelModule = Next;2004ActiveModule = Next;2005continue;2006}20072008Diags.Report(Id[I].second, diag::err_mmap_missing_parent_module)2009<< Id[I].first << (ActiveModule != nullptr)2010<< (ActiveModule2011? ActiveModule->getTopLevelModule()->getFullModuleName()2012: "");2013HadError = true;2014}20152016if (TopLevelModule &&2017ModuleMapFID != Map.getContainingModuleMapFileID(TopLevelModule)) {2018assert(ModuleMapFID !=2019Map.getModuleMapFileIDForUniquing(TopLevelModule) &&2020"submodule defined in same file as 'module *' that allowed its "2021"top-level module");2022Map.addAdditionalModuleMapFile(2023TopLevelModule, *SourceMgr.getFileEntryRefForID(ModuleMapFID));2024}2025}20262027StringRef ModuleName = Id.back().first;2028SourceLocation ModuleNameLoc = Id.back().second;20292030// Parse the optional attribute list.2031Attributes Attrs;2032if (parseOptionalAttributes(Attrs))2033return;20342035// Parse the opening brace.2036if (!Tok.is(MMToken::LBrace)) {2037Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)2038<< ModuleName;2039HadError = true;2040return;2041}2042SourceLocation LBraceLoc = consumeToken();20432044// Determine whether this (sub)module has already been defined.2045Module *ShadowingModule = nullptr;2046if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {2047// We might see a (re)definition of a module that we already have a2048// definition for in four cases:2049// - If we loaded one definition from an AST file and we've just found a2050// corresponding definition in a module map file, or2051bool LoadedFromASTFile = Existing->IsFromModuleFile;2052// - If we previously inferred this module from different module map file.2053bool Inferred = Existing->IsInferred;2054// - If we're building a framework that vends a module map, we might've2055// previously seen the one in intermediate products and now the system2056// one.2057// FIXME: If we're parsing module map file that looks like this:2058// framework module FW { ... }2059// module FW.Sub { ... }2060// We can't check the framework qualifier, since it's not attached to2061// the definition of Sub. Checking that qualifier on \c Existing is2062// not correct either, since we might've previously seen:2063// module FW { ... }2064// module FW.Sub { ... }2065// We should enforce consistency of redefinitions so that we can rely2066// that \c Existing is part of a framework iff the redefinition of FW2067// we have just skipped had it too. Once we do that, stop checking2068// the local framework qualifier and only rely on \c Existing.2069bool PartOfFramework = Framework || Existing->isPartOfFramework();2070// - If we're building a (preprocessed) module and we've just loaded the2071// module map file from which it was created.2072bool ParsedAsMainInput =2073Map.LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap &&2074Map.LangOpts.CurrentModule == ModuleName &&2075SourceMgr.getDecomposedLoc(ModuleNameLoc).first !=2076SourceMgr.getDecomposedLoc(Existing->DefinitionLoc).first;2077if (LoadedFromASTFile || Inferred || PartOfFramework || ParsedAsMainInput) {2078ActiveModule = PreviousActiveModule;2079// Skip the module definition.2080skipUntil(MMToken::RBrace);2081if (Tok.is(MMToken::RBrace))2082consumeToken();2083else {2084Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);2085Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);2086HadError = true;2087}2088return;2089}20902091if (!Existing->Parent && Map.mayShadowNewModule(Existing)) {2092ShadowingModule = Existing;2093} else {2094// This is not a shawdowed module decl, it is an illegal redefinition.2095Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)2096<< ModuleName;2097Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);20982099// Skip the module definition.2100skipUntil(MMToken::RBrace);2101if (Tok.is(MMToken::RBrace))2102consumeToken();21032104HadError = true;2105return;2106}2107}21082109// Start defining this module.2110if (ShadowingModule) {2111ActiveModule =2112Map.createShadowedModule(ModuleName, Framework, ShadowingModule);2113} else {2114ActiveModule =2115Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit)2116.first;2117}21182119ActiveModule->DefinitionLoc = ModuleNameLoc;2120if (Attrs.IsSystem || IsSystem)2121ActiveModule->IsSystem = true;2122if (Attrs.IsExternC)2123ActiveModule->IsExternC = true;2124if (Attrs.NoUndeclaredIncludes)2125ActiveModule->NoUndeclaredIncludes = true;2126ActiveModule->Directory = Directory;21272128StringRef MapFileName(2129SourceMgr.getFileEntryRefForID(ModuleMapFID)->getName());2130if (MapFileName.ends_with("module.private.modulemap") ||2131MapFileName.ends_with("module_private.map")) {2132ActiveModule->ModuleMapIsPrivate = true;2133}21342135// Private modules named as FooPrivate, Foo.Private or similar are likely a2136// user error; provide warnings, notes and fixits to direct users to use2137// Foo_Private instead.2138SourceLocation StartLoc =2139SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());2140if (Map.HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&2141!Diags.isIgnored(diag::warn_mmap_mismatched_private_submodule,2142StartLoc) &&2143!Diags.isIgnored(diag::warn_mmap_mismatched_private_module_name,2144StartLoc) &&2145ActiveModule->ModuleMapIsPrivate)2146diagnosePrivateModules(ExplicitLoc, FrameworkLoc);21472148bool Done = false;2149do {2150switch (Tok.Kind) {2151case MMToken::EndOfFile:2152case MMToken::RBrace:2153Done = true;2154break;21552156case MMToken::ConfigMacros:2157parseConfigMacros();2158break;21592160case MMToken::Conflict:2161parseConflict();2162break;21632164case MMToken::ExplicitKeyword:2165case MMToken::ExternKeyword:2166case MMToken::FrameworkKeyword:2167case MMToken::ModuleKeyword:2168parseModuleDecl();2169break;21702171case MMToken::ExportKeyword:2172parseExportDecl();2173break;21742175case MMToken::ExportAsKeyword:2176parseExportAsDecl();2177break;21782179case MMToken::UseKeyword:2180parseUseDecl();2181break;21822183case MMToken::RequiresKeyword:2184parseRequiresDecl();2185break;21862187case MMToken::TextualKeyword:2188parseHeaderDecl(MMToken::TextualKeyword, consumeToken());2189break;21902191case MMToken::UmbrellaKeyword: {2192SourceLocation UmbrellaLoc = consumeToken();2193if (Tok.is(MMToken::HeaderKeyword))2194parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);2195else2196parseUmbrellaDirDecl(UmbrellaLoc);2197break;2198}21992200case MMToken::ExcludeKeyword:2201parseHeaderDecl(MMToken::ExcludeKeyword, consumeToken());2202break;22032204case MMToken::PrivateKeyword:2205parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());2206break;22072208case MMToken::HeaderKeyword:2209parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());2210break;22112212case MMToken::LinkKeyword:2213parseLinkDecl();2214break;22152216default:2217Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);2218consumeToken();2219break;2220}2221} while (!Done);22222223if (Tok.is(MMToken::RBrace))2224consumeToken();2225else {2226Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);2227Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);2228HadError = true;2229}22302231// If the active module is a top-level framework, and there are no link2232// libraries, automatically link against the framework.2233if (ActiveModule->IsFramework && !ActiveModule->isSubFramework() &&2234ActiveModule->LinkLibraries.empty())2235inferFrameworkLink(ActiveModule);22362237// If the module meets all requirements but is still unavailable, mark the2238// whole tree as unavailable to prevent it from building.2239if (!ActiveModule->IsAvailable && !ActiveModule->IsUnimportable &&2240ActiveModule->Parent) {2241ActiveModule->getTopLevelModule()->markUnavailable(/*Unimportable=*/false);2242ActiveModule->getTopLevelModule()->MissingHeaders.append(2243ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());2244}22452246// We're done parsing this module. Pop back to the previous module.2247ActiveModule = PreviousActiveModule;2248}22492250/// Parse an extern module declaration.2251///2252/// extern module-declaration:2253/// 'extern' 'module' module-id string-literal2254void ModuleMapParser::parseExternModuleDecl() {2255assert(Tok.is(MMToken::ExternKeyword));2256SourceLocation ExternLoc = consumeToken(); // 'extern' keyword22572258// Parse 'module' keyword.2259if (!Tok.is(MMToken::ModuleKeyword)) {2260Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);2261consumeToken();2262HadError = true;2263return;2264}2265consumeToken(); // 'module' keyword22662267// Parse the module name.2268ModuleId Id;2269if (parseModuleId(Id)) {2270HadError = true;2271return;2272}22732274// Parse the referenced module map file name.2275if (!Tok.is(MMToken::StringLiteral)) {2276Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file);2277HadError = true;2278return;2279}2280std::string FileName = std::string(Tok.getString());2281consumeToken(); // filename22822283StringRef FileNameRef = FileName;2284SmallString<128> ModuleMapFileName;2285if (llvm::sys::path::is_relative(FileNameRef)) {2286ModuleMapFileName += Directory.getName();2287llvm::sys::path::append(ModuleMapFileName, FileName);2288FileNameRef = ModuleMapFileName;2289}2290if (auto File = SourceMgr.getFileManager().getOptionalFileRef(FileNameRef))2291Map.parseModuleMapFile(2292*File, IsSystem,2293Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd2294? Directory2295: File->getDir(),2296FileID(), nullptr, ExternLoc);2297}22982299/// Whether to add the requirement \p Feature to the module \p M.2300///2301/// This preserves backwards compatibility for two hacks in the Darwin system2302/// module map files:2303///2304/// 1. The use of 'requires excluded' to make headers non-modular, which2305/// should really be mapped to 'textual' now that we have this feature. We2306/// drop the 'excluded' requirement, and set \p IsRequiresExcludedHack to2307/// true. Later, this bit will be used to map all the headers inside this2308/// module to 'textual'.2309///2310/// This affects Darwin.C.excluded (for assert.h) and Tcl.Private.2311///2312/// 2. Removes a bogus cplusplus requirement from IOKit.avc. This requirement2313/// was never correct and causes issues now that we check it, so drop it.2314static bool shouldAddRequirement(Module *M, StringRef Feature,2315bool &IsRequiresExcludedHack) {2316if (Feature == "excluded" &&2317(M->fullModuleNameIs({"Darwin", "C", "excluded"}) ||2318M->fullModuleNameIs({"Tcl", "Private"}))) {2319IsRequiresExcludedHack = true;2320return false;2321} else if (Feature == "cplusplus" && M->fullModuleNameIs({"IOKit", "avc"})) {2322return false;2323}23242325return true;2326}23272328/// Parse a requires declaration.2329///2330/// requires-declaration:2331/// 'requires' feature-list2332///2333/// feature-list:2334/// feature ',' feature-list2335/// feature2336///2337/// feature:2338/// '!'[opt] identifier2339void ModuleMapParser::parseRequiresDecl() {2340assert(Tok.is(MMToken::RequiresKeyword));23412342// Parse 'requires' keyword.2343consumeToken();23442345// Parse the feature-list.2346do {2347bool RequiredState = true;2348if (Tok.is(MMToken::Exclaim)) {2349RequiredState = false;2350consumeToken();2351}23522353if (!Tok.is(MMToken::Identifier)) {2354Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);2355HadError = true;2356return;2357}23582359// Consume the feature name.2360std::string Feature = std::string(Tok.getString());2361consumeToken();23622363bool IsRequiresExcludedHack = false;2364bool ShouldAddRequirement =2365shouldAddRequirement(ActiveModule, Feature, IsRequiresExcludedHack);23662367if (IsRequiresExcludedHack)2368UsesRequiresExcludedHack.insert(ActiveModule);23692370if (ShouldAddRequirement) {2371// Add this feature.2372ActiveModule->addRequirement(Feature, RequiredState, Map.LangOpts,2373*Map.Target);2374}23752376if (!Tok.is(MMToken::Comma))2377break;23782379// Consume the comma.2380consumeToken();2381} while (true);2382}23832384/// Parse a header declaration.2385///2386/// header-declaration:2387/// 'textual'[opt] 'header' string-literal2388/// 'private' 'textual'[opt] 'header' string-literal2389/// 'exclude' 'header' string-literal2390/// 'umbrella' 'header' string-literal2391///2392/// FIXME: Support 'private textual header'.2393void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,2394SourceLocation LeadingLoc) {2395// We've already consumed the first token.2396ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;23972398if (LeadingToken == MMToken::PrivateKeyword) {2399Role = ModuleMap::PrivateHeader;2400// 'private' may optionally be followed by 'textual'.2401if (Tok.is(MMToken::TextualKeyword)) {2402LeadingToken = Tok.Kind;2403consumeToken();2404}2405} else if (LeadingToken == MMToken::ExcludeKeyword) {2406Role = ModuleMap::ExcludedHeader;2407}24082409if (LeadingToken == MMToken::TextualKeyword)2410Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);24112412if (UsesRequiresExcludedHack.count(ActiveModule)) {2413// Mark this header 'textual' (see doc comment for2414// Module::UsesRequiresExcludedHack).2415Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);2416}24172418if (LeadingToken != MMToken::HeaderKeyword) {2419if (!Tok.is(MMToken::HeaderKeyword)) {2420Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)2421<< (LeadingToken == MMToken::PrivateKeyword ? "private" :2422LeadingToken == MMToken::ExcludeKeyword ? "exclude" :2423LeadingToken == MMToken::TextualKeyword ? "textual" : "umbrella");2424return;2425}2426consumeToken();2427}24282429// Parse the header name.2430if (!Tok.is(MMToken::StringLiteral)) {2431Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)2432<< "header";2433HadError = true;2434return;2435}2436Module::UnresolvedHeaderDirective Header;2437Header.FileName = std::string(Tok.getString());2438Header.FileNameLoc = consumeToken();2439Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;2440Header.Kind = Map.headerRoleToKind(Role);24412442// Check whether we already have an umbrella.2443if (Header.IsUmbrella &&2444!std::holds_alternative<std::monostate>(ActiveModule->Umbrella)) {2445Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)2446<< ActiveModule->getFullModuleName();2447HadError = true;2448return;2449}24502451// If we were given stat information, parse it so we can skip looking for2452// the file.2453if (Tok.is(MMToken::LBrace)) {2454SourceLocation LBraceLoc = consumeToken();24552456while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {2457enum Attribute { Size, ModTime, Unknown };2458StringRef Str = Tok.getString();2459SourceLocation Loc = consumeToken();2460switch (llvm::StringSwitch<Attribute>(Str)2461.Case("size", Size)2462.Case("mtime", ModTime)2463.Default(Unknown)) {2464case Size:2465if (Header.Size)2466Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;2467if (!Tok.is(MMToken::IntegerLiteral)) {2468Diags.Report(Tok.getLocation(),2469diag::err_mmap_invalid_header_attribute_value) << Str;2470skipUntil(MMToken::RBrace);2471break;2472}2473Header.Size = Tok.getInteger();2474consumeToken();2475break;24762477case ModTime:2478if (Header.ModTime)2479Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;2480if (!Tok.is(MMToken::IntegerLiteral)) {2481Diags.Report(Tok.getLocation(),2482diag::err_mmap_invalid_header_attribute_value) << Str;2483skipUntil(MMToken::RBrace);2484break;2485}2486Header.ModTime = Tok.getInteger();2487consumeToken();2488break;24892490case Unknown:2491Diags.Report(Loc, diag::err_mmap_expected_header_attribute);2492skipUntil(MMToken::RBrace);2493break;2494}2495}24962497if (Tok.is(MMToken::RBrace))2498consumeToken();2499else {2500Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);2501Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);2502HadError = true;2503}2504}25052506bool NeedsFramework = false;2507// Don't add headers to the builtin modules if the builtin headers belong to2508// the system modules, with the exception of __stddef_max_align_t.h which2509// always had its own module.2510if (!Map.LangOpts.BuiltinHeadersInSystemModules ||2511!isBuiltInModuleName(ActiveModule->getTopLevelModuleName()) ||2512ActiveModule->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}))2513Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);25142515if (NeedsFramework)2516Diags.Report(CurrModuleDeclLoc, diag::note_mmap_add_framework_keyword)2517<< ActiveModule->getFullModuleName()2518<< FixItHint::CreateReplacement(CurrModuleDeclLoc, "framework module");2519}25202521static bool compareModuleHeaders(const Module::Header &A,2522const Module::Header &B) {2523return A.NameAsWritten < B.NameAsWritten;2524}25252526/// Parse an umbrella directory declaration.2527///2528/// umbrella-dir-declaration:2529/// umbrella string-literal2530void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {2531// Parse the directory name.2532if (!Tok.is(MMToken::StringLiteral)) {2533Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)2534<< "umbrella";2535HadError = true;2536return;2537}25382539std::string DirName = std::string(Tok.getString());2540std::string DirNameAsWritten = DirName;2541SourceLocation DirNameLoc = consumeToken();25422543// Check whether we already have an umbrella.2544if (!std::holds_alternative<std::monostate>(ActiveModule->Umbrella)) {2545Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash)2546<< ActiveModule->getFullModuleName();2547HadError = true;2548return;2549}25502551// Look for this file.2552OptionalDirectoryEntryRef Dir;2553if (llvm::sys::path::is_absolute(DirName)) {2554Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName);2555} else {2556SmallString<128> PathName;2557PathName = Directory.getName();2558llvm::sys::path::append(PathName, DirName);2559Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(PathName);2560}25612562if (!Dir) {2563Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found)2564<< DirName;2565return;2566}25672568if (UsesRequiresExcludedHack.count(ActiveModule)) {2569// Mark this header 'textual' (see doc comment for2570// ModuleMapParser::UsesRequiresExcludedHack). Although iterating over the2571// directory is relatively expensive, in practice this only applies to the2572// uncommonly used Tcl module on Darwin platforms.2573std::error_code EC;2574SmallVector<Module::Header, 6> Headers;2575llvm::vfs::FileSystem &FS =2576SourceMgr.getFileManager().getVirtualFileSystem();2577for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E;2578I != E && !EC; I.increment(EC)) {2579if (auto FE = SourceMgr.getFileManager().getOptionalFileRef(I->path())) {2580Module::Header Header = {"", std::string(I->path()), *FE};2581Headers.push_back(std::move(Header));2582}2583}25842585// Sort header paths so that the pcm doesn't depend on iteration order.2586std::stable_sort(Headers.begin(), Headers.end(), compareModuleHeaders);25872588for (auto &Header : Headers)2589Map.addHeader(ActiveModule, std::move(Header), ModuleMap::TextualHeader);2590return;2591}25922593if (Module *OwningModule = Map.UmbrellaDirs[*Dir]) {2594Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)2595<< OwningModule->getFullModuleName();2596HadError = true;2597return;2598}25992600// Record this umbrella directory.2601Map.setUmbrellaDirAsWritten(ActiveModule, *Dir, DirNameAsWritten, DirName);2602}26032604/// Parse a module export declaration.2605///2606/// export-declaration:2607/// 'export' wildcard-module-id2608///2609/// wildcard-module-id:2610/// identifier2611/// '*'2612/// identifier '.' wildcard-module-id2613void ModuleMapParser::parseExportDecl() {2614assert(Tok.is(MMToken::ExportKeyword));2615SourceLocation ExportLoc = consumeToken();26162617// Parse the module-id with an optional wildcard at the end.2618ModuleId ParsedModuleId;2619bool Wildcard = false;2620do {2621// FIXME: Support string-literal module names here.2622if (Tok.is(MMToken::Identifier)) {2623ParsedModuleId.push_back(2624std::make_pair(std::string(Tok.getString()), Tok.getLocation()));2625consumeToken();26262627if (Tok.is(MMToken::Period)) {2628consumeToken();2629continue;2630}26312632break;2633}26342635if(Tok.is(MMToken::Star)) {2636Wildcard = true;2637consumeToken();2638break;2639}26402641Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);2642HadError = true;2643return;2644} while (true);26452646Module::UnresolvedExportDecl Unresolved = {2647ExportLoc, ParsedModuleId, Wildcard2648};2649ActiveModule->UnresolvedExports.push_back(Unresolved);2650}26512652/// Parse a module export_as declaration.2653///2654/// export-as-declaration:2655/// 'export_as' identifier2656void ModuleMapParser::parseExportAsDecl() {2657assert(Tok.is(MMToken::ExportAsKeyword));2658consumeToken();26592660if (!Tok.is(MMToken::Identifier)) {2661Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);2662HadError = true;2663return;2664}26652666if (ActiveModule->Parent) {2667Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as);2668consumeToken();2669return;2670}26712672if (!ActiveModule->ExportAsModule.empty()) {2673if (ActiveModule->ExportAsModule == Tok.getString()) {2674Diags.Report(Tok.getLocation(), diag::warn_mmap_redundant_export_as)2675<< ActiveModule->Name << Tok.getString();2676} else {2677Diags.Report(Tok.getLocation(), diag::err_mmap_conflicting_export_as)2678<< ActiveModule->Name << ActiveModule->ExportAsModule2679<< Tok.getString();2680}2681}26822683ActiveModule->ExportAsModule = std::string(Tok.getString());2684Map.addLinkAsDependency(ActiveModule);26852686consumeToken();2687}26882689/// Parse a module use declaration.2690///2691/// use-declaration:2692/// 'use' wildcard-module-id2693void ModuleMapParser::parseUseDecl() {2694assert(Tok.is(MMToken::UseKeyword));2695auto KWLoc = consumeToken();2696// Parse the module-id.2697ModuleId ParsedModuleId;2698parseModuleId(ParsedModuleId);26992700if (ActiveModule->Parent)2701Diags.Report(KWLoc, diag::err_mmap_use_decl_submodule);2702else2703ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);2704}27052706/// Parse a link declaration.2707///2708/// module-declaration:2709/// 'link' 'framework'[opt] string-literal2710void ModuleMapParser::parseLinkDecl() {2711assert(Tok.is(MMToken::LinkKeyword));2712SourceLocation LinkLoc = consumeToken();27132714// Parse the optional 'framework' keyword.2715bool IsFramework = false;2716if (Tok.is(MMToken::FrameworkKeyword)) {2717consumeToken();2718IsFramework = true;2719}27202721// Parse the library name2722if (!Tok.is(MMToken::StringLiteral)) {2723Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)2724<< IsFramework << SourceRange(LinkLoc);2725HadError = true;2726return;2727}27282729std::string LibraryName = std::string(Tok.getString());2730consumeToken();2731ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName,2732IsFramework));2733}27342735/// Parse a configuration macro declaration.2736///2737/// module-declaration:2738/// 'config_macros' attributes[opt] config-macro-list?2739///2740/// config-macro-list:2741/// identifier (',' identifier)?2742void ModuleMapParser::parseConfigMacros() {2743assert(Tok.is(MMToken::ConfigMacros));2744SourceLocation ConfigMacrosLoc = consumeToken();27452746// Only top-level modules can have configuration macros.2747if (ActiveModule->Parent) {2748Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule);2749}27502751// Parse the optional attributes.2752Attributes Attrs;2753if (parseOptionalAttributes(Attrs))2754return;27552756if (Attrs.IsExhaustive && !ActiveModule->Parent) {2757ActiveModule->ConfigMacrosExhaustive = true;2758}27592760// If we don't have an identifier, we're done.2761// FIXME: Support macros with the same name as a keyword here.2762if (!Tok.is(MMToken::Identifier))2763return;27642765// Consume the first identifier.2766if (!ActiveModule->Parent) {2767ActiveModule->ConfigMacros.push_back(Tok.getString().str());2768}2769consumeToken();27702771do {2772// If there's a comma, consume it.2773if (!Tok.is(MMToken::Comma))2774break;2775consumeToken();27762777// We expect to see a macro name here.2778// FIXME: Support macros with the same name as a keyword here.2779if (!Tok.is(MMToken::Identifier)) {2780Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);2781break;2782}27832784// Consume the macro name.2785if (!ActiveModule->Parent) {2786ActiveModule->ConfigMacros.push_back(Tok.getString().str());2787}2788consumeToken();2789} while (true);2790}27912792/// Format a module-id into a string.2793static std::string formatModuleId(const ModuleId &Id) {2794std::string result;2795{2796llvm::raw_string_ostream OS(result);27972798for (unsigned I = 0, N = Id.size(); I != N; ++I) {2799if (I)2800OS << ".";2801OS << Id[I].first;2802}2803}28042805return result;2806}28072808/// Parse a conflict declaration.2809///2810/// module-declaration:2811/// 'conflict' module-id ',' string-literal2812void ModuleMapParser::parseConflict() {2813assert(Tok.is(MMToken::Conflict));2814SourceLocation ConflictLoc = consumeToken();2815Module::UnresolvedConflict Conflict;28162817// Parse the module-id.2818if (parseModuleId(Conflict.Id))2819return;28202821// Parse the ','.2822if (!Tok.is(MMToken::Comma)) {2823Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)2824<< SourceRange(ConflictLoc);2825return;2826}2827consumeToken();28282829// Parse the message.2830if (!Tok.is(MMToken::StringLiteral)) {2831Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)2832<< formatModuleId(Conflict.Id);2833return;2834}2835Conflict.Message = Tok.getString().str();2836consumeToken();28372838// Add this unresolved conflict.2839ActiveModule->UnresolvedConflicts.push_back(Conflict);2840}28412842/// Parse an inferred module declaration (wildcard modules).2843///2844/// module-declaration:2845/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]2846/// { inferred-module-member* }2847///2848/// inferred-module-member:2849/// 'export' '*'2850/// 'exclude' identifier2851void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {2852assert(Tok.is(MMToken::Star));2853SourceLocation StarLoc = consumeToken();2854bool Failed = false;28552856// Inferred modules must be submodules.2857if (!ActiveModule && !Framework) {2858Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);2859Failed = true;2860}28612862if (ActiveModule) {2863// Inferred modules must have umbrella directories.2864if (!Failed && ActiveModule->IsAvailable &&2865!ActiveModule->getEffectiveUmbrellaDir()) {2866Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);2867Failed = true;2868}28692870// Check for redefinition of an inferred module.2871if (!Failed && ActiveModule->InferSubmodules) {2872Diags.Report(StarLoc, diag::err_mmap_inferred_redef);2873if (ActiveModule->InferredSubmoduleLoc.isValid())2874Diags.Report(ActiveModule->InferredSubmoduleLoc,2875diag::note_mmap_prev_definition);2876Failed = true;2877}28782879// Check for the 'framework' keyword, which is not permitted here.2880if (Framework) {2881Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule);2882Framework = false;2883}2884} else if (Explicit) {2885Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework);2886Explicit = false;2887}28882889// If there were any problems with this inferred submodule, skip its body.2890if (Failed) {2891if (Tok.is(MMToken::LBrace)) {2892consumeToken();2893skipUntil(MMToken::RBrace);2894if (Tok.is(MMToken::RBrace))2895consumeToken();2896}2897HadError = true;2898return;2899}29002901// Parse optional attributes.2902Attributes Attrs;2903if (parseOptionalAttributes(Attrs))2904return;29052906if (ActiveModule) {2907// Note that we have an inferred submodule.2908ActiveModule->InferSubmodules = true;2909ActiveModule->InferredSubmoduleLoc = StarLoc;2910ActiveModule->InferExplicitSubmodules = Explicit;2911} else {2912// We'll be inferring framework modules for this directory.2913Map.InferredDirectories[Directory].InferModules = true;2914Map.InferredDirectories[Directory].Attrs = Attrs;2915Map.InferredDirectories[Directory].ModuleMapFID = ModuleMapFID;2916// FIXME: Handle the 'framework' keyword.2917}29182919// Parse the opening brace.2920if (!Tok.is(MMToken::LBrace)) {2921Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);2922HadError = true;2923return;2924}2925SourceLocation LBraceLoc = consumeToken();29262927// Parse the body of the inferred submodule.2928bool Done = false;2929do {2930switch (Tok.Kind) {2931case MMToken::EndOfFile:2932case MMToken::RBrace:2933Done = true;2934break;29352936case MMToken::ExcludeKeyword:2937if (ActiveModule) {2938Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)2939<< (ActiveModule != nullptr);2940consumeToken();2941break;2942}29432944consumeToken();2945// FIXME: Support string-literal module names here.2946if (!Tok.is(MMToken::Identifier)) {2947Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);2948break;2949}29502951Map.InferredDirectories[Directory].ExcludedModules.push_back(2952std::string(Tok.getString()));2953consumeToken();2954break;29552956case MMToken::ExportKeyword:2957if (!ActiveModule) {2958Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)2959<< (ActiveModule != nullptr);2960consumeToken();2961break;2962}29632964consumeToken();2965if (Tok.is(MMToken::Star))2966ActiveModule->InferExportWildcard = true;2967else2968Diags.Report(Tok.getLocation(),2969diag::err_mmap_expected_export_wildcard);2970consumeToken();2971break;29722973case MMToken::ExplicitKeyword:2974case MMToken::ModuleKeyword:2975case MMToken::HeaderKeyword:2976case MMToken::PrivateKeyword:2977case MMToken::UmbrellaKeyword:2978default:2979Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)2980<< (ActiveModule != nullptr);2981consumeToken();2982break;2983}2984} while (!Done);29852986if (Tok.is(MMToken::RBrace))2987consumeToken();2988else {2989Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);2990Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);2991HadError = true;2992}2993}29942995/// Parse optional attributes.2996///2997/// attributes:2998/// attribute attributes2999/// attribute3000///3001/// attribute:3002/// [ identifier ]3003///3004/// \param Attrs Will be filled in with the parsed attributes.3005///3006/// \returns true if an error occurred, false otherwise.3007bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {3008bool HadError = false;30093010while (Tok.is(MMToken::LSquare)) {3011// Consume the '['.3012SourceLocation LSquareLoc = consumeToken();30133014// Check whether we have an attribute name here.3015if (!Tok.is(MMToken::Identifier)) {3016Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);3017skipUntil(MMToken::RSquare);3018if (Tok.is(MMToken::RSquare))3019consumeToken();3020HadError = true;3021}30223023// Decode the attribute name.3024AttributeKind Attribute3025= llvm::StringSwitch<AttributeKind>(Tok.getString())3026.Case("exhaustive", AT_exhaustive)3027.Case("extern_c", AT_extern_c)3028.Case("no_undeclared_includes", AT_no_undeclared_includes)3029.Case("system", AT_system)3030.Default(AT_unknown);3031switch (Attribute) {3032case AT_unknown:3033Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)3034<< Tok.getString();3035break;30363037case AT_system:3038Attrs.IsSystem = true;3039break;30403041case AT_extern_c:3042Attrs.IsExternC = true;3043break;30443045case AT_exhaustive:3046Attrs.IsExhaustive = true;3047break;30483049case AT_no_undeclared_includes:3050Attrs.NoUndeclaredIncludes = true;3051break;3052}3053consumeToken();30543055// Consume the ']'.3056if (!Tok.is(MMToken::RSquare)) {3057Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);3058Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);3059skipUntil(MMToken::RSquare);3060HadError = true;3061}30623063if (Tok.is(MMToken::RSquare))3064consumeToken();3065}30663067return HadError;3068}30693070/// Parse a module map file.3071///3072/// module-map-file:3073/// module-declaration*3074bool ModuleMapParser::parseModuleMapFile() {3075do {3076switch (Tok.Kind) {3077case MMToken::EndOfFile:3078return HadError;30793080case MMToken::ExplicitKeyword:3081case MMToken::ExternKeyword:3082case MMToken::ModuleKeyword:3083case MMToken::FrameworkKeyword:3084parseModuleDecl();3085break;30863087case MMToken::Comma:3088case MMToken::ConfigMacros:3089case MMToken::Conflict:3090case MMToken::Exclaim:3091case MMToken::ExcludeKeyword:3092case MMToken::ExportKeyword:3093case MMToken::ExportAsKeyword:3094case MMToken::HeaderKeyword:3095case MMToken::Identifier:3096case MMToken::LBrace:3097case MMToken::LinkKeyword:3098case MMToken::LSquare:3099case MMToken::Period:3100case MMToken::PrivateKeyword:3101case MMToken::RBrace:3102case MMToken::RSquare:3103case MMToken::RequiresKeyword:3104case MMToken::Star:3105case MMToken::StringLiteral:3106case MMToken::IntegerLiteral:3107case MMToken::TextualKeyword:3108case MMToken::UmbrellaKeyword:3109case MMToken::UseKeyword:3110Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);3111HadError = true;3112consumeToken();3113break;3114}3115} while (true);3116}31173118bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem,3119DirectoryEntryRef Dir, FileID ID,3120unsigned *Offset,3121SourceLocation ExternModuleLoc) {3122assert(Target && "Missing target information");3123llvm::DenseMap<const FileEntry *, bool>::iterator Known3124= ParsedModuleMap.find(File);3125if (Known != ParsedModuleMap.end())3126return Known->second;31273128// If the module map file wasn't already entered, do so now.3129if (ID.isInvalid()) {3130auto FileCharacter =3131IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap;3132ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter);3133}31343135assert(Target && "Missing target information");3136std::optional<llvm::MemoryBufferRef> Buffer = SourceMgr.getBufferOrNone(ID);3137if (!Buffer)3138return ParsedModuleMap[File] = true;3139assert((!Offset || *Offset <= Buffer->getBufferSize()) &&3140"invalid buffer offset");31413142// Parse this module map file.3143Lexer L(SourceMgr.getLocForStartOfFile(ID), MMapLangOpts,3144Buffer->getBufferStart(),3145Buffer->getBufferStart() + (Offset ? *Offset : 0),3146Buffer->getBufferEnd());3147SourceLocation Start = L.getSourceLocation();3148ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem);3149bool Result = Parser.parseModuleMapFile();3150ParsedModuleMap[File] = Result;31513152if (Offset) {3153auto Loc = SourceMgr.getDecomposedLoc(Parser.getLocation());3154assert(Loc.first == ID && "stopped in a different file?");3155*Offset = Loc.second;3156}31573158// Notify callbacks that we parsed it.3159for (const auto &Cb : Callbacks)3160Cb->moduleMapFileRead(Start, File, IsSystem);31613162return Result;3163}316431653166