summaryrefslogtreecommitdiffstats
path: root/clang/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r--clang/lib/Lex/ModuleMap.cpp98
1 files changed, 63 insertions, 35 deletions
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 {
OpenPOWER on IntegriCloud