зеркало из https://github.com/microsoft/clang-1.git
Implement the notion of umbrella directories, which implicity cover
all of the headers below that particular directory. Use umbrella directories as a clean way to deal with (1) directories/frameworks that don't have an umbrella header, but don't want to enumerate all of their headers, and (2) PrivateHeaders, which we never want to enumerate and want to keep separate from the main umbrella header. This also eliminates a little more of the "magic" for private headers, and frameworks in general. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146235 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
71088d1af2
Коммит
6a1db484f3
|
@ -194,6 +194,12 @@ public:
|
|||
return Umbrella.dyn_cast<const FileEntry *>();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this module has an umbrella directory that is
|
||||
/// not based on an umbrella header.
|
||||
bool hasUmbrellaDir() const {
|
||||
return Umbrella && Umbrella.is<const DirectoryEntry *>();
|
||||
}
|
||||
|
||||
/// \brief Print the module map for this module to the given stream.
|
||||
///
|
||||
void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;
|
||||
|
|
|
@ -115,27 +115,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
|
|||
// Infer submodules for each of the directories we found between
|
||||
// the directory of the umbrella header and the directory where
|
||||
// the actual header is located.
|
||||
|
||||
// For a framework module, the umbrella directory is the framework
|
||||
// directory, so strip off the "Headers" or "PrivateHeaders".
|
||||
bool Explicit = UmbrellaModule->InferExplicitSubmodules;
|
||||
unsigned LastSkippedDir = SkippedDirs.size();
|
||||
if (LastSkippedDir && UmbrellaModule->IsFramework) {
|
||||
if (llvm::sys::path::filename(SkippedDirs.back()->getName())
|
||||
== "PrivateHeaders") {
|
||||
// For private headers, add an explicit "Private" module.
|
||||
// FIXME: This feels somewhat hackish. Do we want to introduce
|
||||
// some kind of "umbrella directory" here?
|
||||
Result = findOrCreateModule("Private", Result,
|
||||
/*IsFramework=*/false,
|
||||
/*IsExplicit=*/true).first;
|
||||
Explicit = true;
|
||||
}
|
||||
|
||||
--LastSkippedDir;
|
||||
}
|
||||
|
||||
for (unsigned I = LastSkippedDir; I != 0; --I) {
|
||||
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
|
||||
// Find or create the module that corresponds to this directory name.
|
||||
StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
|
||||
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
|
||||
|
@ -294,41 +276,16 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
|
|||
}
|
||||
|
||||
// Look for private headers.
|
||||
Module *ModulePrivate = 0;
|
||||
llvm::SmallString<128> PrivateHeadersDirName(FrameworkDir->getName());
|
||||
llvm::sys::path::append(PrivateHeadersDirName, "PrivateHeaders");
|
||||
llvm::SmallString<128> PrivateHeadersDirNameNative;
|
||||
llvm::sys::path::native(PrivateHeadersDirName.str(),
|
||||
PrivateHeadersDirNameNative);
|
||||
for (llvm::sys::fs::directory_iterator
|
||||
Dir(PrivateHeadersDirNameNative.str(), EC), DirEnd;
|
||||
Dir != DirEnd && !EC; Dir.increment(EC)) {
|
||||
// Check whether this entry has an extension typically associated with
|
||||
// headers.
|
||||
if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
|
||||
.Cases(".h", ".H", ".hh", ".hpp", true)
|
||||
.Default(false))
|
||||
continue;
|
||||
|
||||
if (const FileEntry *PrivateHeader = FileMgr.getFile(Dir->path())) {
|
||||
// Create the "private" submodule, if we haven't done so already.
|
||||
if (!ModulePrivate) {
|
||||
ModulePrivate = findOrCreateModule("Private", Result,
|
||||
/*IsFramework=*/false,
|
||||
/*IsExplicit=*/true).first;
|
||||
}
|
||||
|
||||
Module *Sub = findOrCreateModule(llvm::sys::path::stem(Dir->path()),
|
||||
ModulePrivate, /*IsFramework=*/false,
|
||||
/*IsExplicit=*/true).first;
|
||||
// header "the private header"
|
||||
Sub->Headers.push_back(PrivateHeader);
|
||||
|
||||
// export *
|
||||
Sub->Exports.push_back(Module::ExportDecl(0, true));
|
||||
|
||||
Headers[PrivateHeader] = Sub;
|
||||
}
|
||||
if (const DirectoryEntry *Dir = FileMgr.getDirectory(PrivateHeadersDirName)) {
|
||||
Module *Private = findOrCreateModule("Private", Result,
|
||||
/*IsFramework=*/false,
|
||||
/*IsExplicit=*/true).first;
|
||||
setUmbrellaDir(Private, Dir);
|
||||
Private->InferSubmodules = true;
|
||||
Private->InferExplicitSubmodules = true;
|
||||
Private->InferExportWildcard = true;
|
||||
}
|
||||
|
||||
return Result;
|
||||
|
@ -337,13 +294,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
|
|||
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
|
||||
Headers[UmbrellaHeader] = Mod;
|
||||
Mod->Umbrella = UmbrellaHeader;
|
||||
|
||||
const DirectoryEntry *UmbrellaDir = UmbrellaHeader->getDir();
|
||||
if (Mod->IsFramework)
|
||||
UmbrellaDir = SourceMgr->getFileManager().getDirectory(
|
||||
llvm::sys::path::parent_path(UmbrellaDir->getName()));
|
||||
|
||||
UmbrellaDirs[UmbrellaDir] = Mod;
|
||||
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
|
||||
}
|
||||
|
||||
void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
|
||||
|
@ -503,6 +454,8 @@ namespace clang {
|
|||
void parseExportDecl();
|
||||
void parseInferredSubmoduleDecl(bool Explicit);
|
||||
|
||||
const DirectoryEntry *getOverriddenHeaderSearchDir();
|
||||
|
||||
public:
|
||||
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
|
||||
DiagnosticsEngine &Diags,
|
||||
|
@ -888,9 +841,13 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
|
|||
if (llvm::sys::path::is_absolute(FileName)) {
|
||||
PathName = FileName;
|
||||
File = SourceMgr.getFileManager().getFile(PathName);
|
||||
} else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) {
|
||||
PathName = Dir->getName();
|
||||
llvm::sys::path::append(PathName, FileName);
|
||||
File = SourceMgr.getFileManager().getFile(PathName);
|
||||
} else {
|
||||
// Search for the header file within the search directory.
|
||||
PathName += Directory->getName();
|
||||
PathName = Directory->getName();
|
||||
unsigned PathLength = PathName.size();
|
||||
|
||||
if (ActiveModule->isPartOfFramework()) {
|
||||
|
@ -924,13 +881,6 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
|
|||
HadError = true;
|
||||
} else if (Umbrella) {
|
||||
const DirectoryEntry *UmbrellaDir = File->getDir();
|
||||
if (ActiveModule->IsFramework) {
|
||||
// For framework modules, use the framework directory as the umbrella
|
||||
// directory.
|
||||
UmbrellaDir = SourceMgr.getFileManager().getDirectory(
|
||||
llvm::sys::path::parent_path(UmbrellaDir->getName()));
|
||||
}
|
||||
|
||||
if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
|
||||
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
|
||||
<< OwningModule->getFullModuleName();
|
||||
|
@ -1141,6 +1091,22 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief If there is a specific header search directory due the presence
|
||||
/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
|
||||
const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
|
||||
for (Module *Mod = ActiveModule; Mod; Mod = Mod->Parent) {
|
||||
// If we have an umbrella directory, use that.
|
||||
if (Mod->hasUmbrellaDir())
|
||||
return Mod->getUmbrellaDir();
|
||||
|
||||
// If we have a framework directory, stop looking.
|
||||
if (Mod->IsFramework)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Parse a module map file.
|
||||
///
|
||||
/// module-map-file:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
int no_umbrella_A;
|
|
@ -0,0 +1 @@
|
|||
int no_umbrella_B;
|
|
@ -0,0 +1 @@
|
|||
int no_umbrella_A_private;
|
|
@ -0,0 +1 @@
|
|||
int no_umbrella_B_private;
|
|
@ -0,0 +1,4 @@
|
|||
framework module NoUmbrella {
|
||||
umbrella "Headers"
|
||||
module * { }
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
explicit module NoUmbrella.Private {
|
||||
umbrella "PrivateHeaders"
|
||||
explicit module * { }
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
// other file: expected-note{{'no_umbrella_A_private' declared here}}
|
||||
|
||||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
|
||||
|
@ -23,6 +24,10 @@ void testSubframeworkOther() {
|
|||
double *sfo1 = sub_framework_other; // expected-error{{use of undeclared identifier 'sub_framework_other'}}
|
||||
}
|
||||
|
||||
// Test umbrella-less submodule includes
|
||||
#include <NoUmbrella/A.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.A'}}
|
||||
int getNoUmbrellaA() { return no_umbrella_A; }
|
||||
|
||||
// Test header cross-subframework include pattern.
|
||||
#include <DependsOnModule/../Frameworks/SubFramework.framework/Headers/Other.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.SubFramework.Other'}}
|
||||
|
||||
|
@ -48,3 +53,8 @@ int getDependsOnModulePrivate() { return depends_on_module_private; }
|
|||
#include <Module/ModulePrivate.h> // expected-warning{{treating #include as an import of module 'Module.Private.ModulePrivate'}}
|
||||
|
||||
int getModulePrivate() { return module_private; }
|
||||
|
||||
#include <NoUmbrella/A_Private.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.Private.A_Private'}}
|
||||
int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
|
||||
|
||||
int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{use of undeclared identifier 'no_umbrella_B_private'; did you mean 'no_umbrella_A_private'?}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче