diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2017-12-22 02:53:30 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2017-12-22 02:53:30 +0000 |
commit | 2972991969b6841b361085d8c0dd0b964ebfd04f (patch) | |
tree | 772acc3f7a74cae4e3732a2d5b0d62c7c1c7cfa5 /clang/lib/Lex | |
parent | 67885f5d582ade8fc8ba8569e41666b2aeb81b5c (diff) | |
download | bcm5719-llvm-2972991969b6841b361085d8c0dd0b964ebfd04f.tar.gz bcm5719-llvm-2972991969b6841b361085d8c0dd0b964ebfd04f.zip |
[Modules] Change private modules rules and warnings
We used to advertise private modules to be declared as submodules
(Foo.Private). This has proven to not scale well since private headers
might carry several dependencies, introducing unwanted content into the
main module and often causing dep cycles.
Change the canonical way to name it to Foo_Private, forcing private
modules as top level ones, and provide warnings under -Wprivate-module
to suggest fixes for other private naming. Update documentation to
reflect that.
rdar://problem/31173501
llvm-svn: 321337
Diffstat (limited to 'clang/lib/Lex')
-rw-r--r-- | clang/lib/Lex/HeaderSearch.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 98 |
2 files changed, 71 insertions, 40 deletions
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index aa2588659dd..6976294a2ea 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -209,11 +209,14 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) { // The facility for "private modules" -- adjacent, optional module maps named // module.private.modulemap that are supposed to define private submodules -- - // is sometimes misused by frameworks that name their associated private - // module FooPrivate, rather than as a submodule named Foo.Private as - // intended. Here we compensate for such cases by looking in directories named - // Foo.framework, when we previously looked and failed to find a - // FooPrivate.framework. + // may have different flavors of names: FooPrivate, Foo_Private and Foo.Private. + // + // Foo.Private is now depracated in favor of Foo_Private. Users of FooPrivate + // should also rename to Foo_Private. Representing private as submodules + // could force building unwanted dependencies into the parent module and cause + // dependency cycles. + if (!Module && SearchName.consume_back("_Private")) + Module = lookupModule(ModuleName, SearchName); if (!Module && SearchName.consume_back("Private")) Module = lookupModule(ModuleName, SearchName); return Module; diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index fbbae7a0952..b3ac10c5c5a 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -1608,6 +1608,54 @@ namespace { } // namespace +/// Private modules are canonicalized as Foo_Private. Clang provides extra +/// module map search logic to find the appropriate private module when PCH +/// is used with implicit module maps. Warn when private modules are written +/// in other ways (FooPrivate and Foo.Private), providing notes and fixits. +static void diagnosePrivateModules(const ModuleMap &Map, + DiagnosticsEngine &Diags, + const Module *ActiveModule) { + + auto GenNoteAndFixIt = [&](StringRef BadName, StringRef Canonical, + const Module *M) { + auto D = Diags.Report(ActiveModule->DefinitionLoc, + diag::note_mmap_rename_top_level_private_module); + D << BadName << M->Name; + D << FixItHint::CreateReplacement(ActiveModule->DefinitionLoc, Canonical); + }; + + for (auto E = Map.module_begin(); E != Map.module_end(); ++E) { + auto const *M = E->getValue(); + if (M->Directory != ActiveModule->Directory) + continue; + + SmallString<128> FullName(ActiveModule->getFullModuleName()); + if (!FullName.startswith(M->Name) && !FullName.endswith("Private")) + continue; + SmallString<128> Canonical(M->Name); + Canonical.append("_Private"); + + // Foo.Private -> Foo_Private + if (ActiveModule->Parent && ActiveModule->Name == "Private" && !M->Parent && + M->Name == ActiveModule->Parent->Name) { + Diags.Report(ActiveModule->DefinitionLoc, + diag::warn_mmap_mismatched_private_submodule) + << FullName; + GenNoteAndFixIt(FullName, Canonical, M); + continue; + } + + // FooPrivate and whatnots -> Foo_Private + if (!ActiveModule->Parent && !M->Parent && M->Name != ActiveModule->Name && + ActiveModule->Name != Canonical) { + Diags.Report(ActiveModule->DefinitionLoc, + diag::warn_mmap_mismatched_private_module_name) + << ActiveModule->Name; + GenNoteAndFixIt(ActiveModule->Name, Canonical, M); + } + } +} + /// \brief Parse a module declaration. /// /// module-declaration: @@ -1791,41 +1839,21 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule->NoUndeclaredIncludes = true; ActiveModule->Directory = Directory; - if (!ActiveModule->Parent) { - StringRef MapFileName(ModuleMapFile->getName()); - if (MapFileName.endswith("module.private.modulemap") || - MapFileName.endswith("module_private.map")) { - // Adding a top-level module from a private modulemap is likely a - // user error; we check to see if there's another top-level module - // defined in the non-private map in the same dir, and if so emit a - // warning. - for (auto E = Map.module_begin(); E != Map.module_end(); ++E) { - auto const *M = E->getValue(); - if (!M->Parent && - M->Directory == ActiveModule->Directory && - M->Name != ActiveModule->Name) { - Diags.Report(ActiveModule->DefinitionLoc, - diag::warn_mmap_mismatched_top_level_private) - << ActiveModule->Name << M->Name; - // The pattern we're defending against here is typically due to - // a module named FooPrivate which is supposed to be a submodule - // called Foo.Private. Emit a fixit in that case. - auto D = - Diags.Report(ActiveModule->DefinitionLoc, - diag::note_mmap_rename_top_level_private_as_submodule); - D << ActiveModule->Name << M->Name; - StringRef Bad(ActiveModule->Name); - if (Bad.consume_back("Private")) { - SmallString<128> Fixed = Bad; - Fixed.append(".Private"); - D << FixItHint::CreateReplacement(ActiveModule->DefinitionLoc, - Fixed); - } - break; - } - } - } - } + + // Private modules named as FooPrivate, Foo.Private or similar are likely a + // user error; provide warnings, notes and fixits to direct users to use + // Foo_Private instead. + SourceLocation StartLoc = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + StringRef MapFileName(ModuleMapFile->getName()); + if (Map.HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps && + !Diags.isIgnored(diag::warn_mmap_mismatched_private_submodule, + StartLoc) && + !Diags.isIgnored(diag::warn_mmap_mismatched_private_module_name, + StartLoc) && + (MapFileName.endswith("module.private.modulemap") || + MapFileName.endswith("module_private.map"))) + diagnosePrivateModules(Map, Diags, ActiveModule); bool Done = false; do { |