summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp')
-rw-r--r--gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp172
1 files changed, 132 insertions, 40 deletions
diff --git a/gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
index 6976294a2ea..fbfa54b2fff 100644
--- a/gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
+++ b/gnu/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
@@ -124,7 +124,7 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
return nullptr;
}
-/// \brief Get filenames for all registered header maps.
+/// Get filenames for all registered header maps.
void HeaderSearch::getHeaderMapFileNames(
SmallVectorImpl<std::string> &Names) const {
for (auto &HM : HeaderMaps)
@@ -198,31 +198,33 @@ std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName,
return Result.str().str();
}
-Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
+Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch,
+ bool AllowExtraModuleMapSearch) {
// Look in the module map to determine if there is a module by this name.
Module *Module = ModMap.findModule(ModuleName);
if (Module || !AllowSearch || !HSOpts->ImplicitModuleMaps)
return Module;
StringRef SearchName = ModuleName;
- Module = lookupModule(ModuleName, SearchName);
+ Module = lookupModule(ModuleName, SearchName, AllowExtraModuleMapSearch);
// The facility for "private modules" -- adjacent, optional module maps named
// module.private.modulemap that are supposed to define private submodules --
// 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
+ // Foo.Private is now deprecated 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);
+ Module = lookupModule(ModuleName, SearchName, AllowExtraModuleMapSearch);
if (!Module && SearchName.consume_back("Private"))
- Module = lookupModule(ModuleName, SearchName);
+ Module = lookupModule(ModuleName, SearchName, AllowExtraModuleMapSearch);
return Module;
}
-Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName) {
+Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
+ bool AllowExtraModuleMapSearch) {
Module *Module = nullptr;
// Look through the various header search paths to load any available module
@@ -244,9 +246,9 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName) {
break;
}
}
-
+
// FIXME: Figure out how header maps and module maps will work together.
-
+
// Only deal with normal search directories.
if (!SearchDirs[Idx].isNormalDir())
continue;
@@ -261,7 +263,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName) {
if (Module)
break;
}
-
+
// Search for a module map in a subdirectory with the same name as the
// module.
SmallString<128> NestedModuleMapDirName;
@@ -281,8 +283,9 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName) {
continue;
// Load all module maps in the immediate subdirectories of this search
- // directory.
- loadSubdirectoryModuleMaps(SearchDirs[Idx]);
+ // directory if ModuleName was from @import.
+ if (AllowExtraModuleMapSearch)
+ loadSubdirectoryModuleMaps(SearchDirs[Idx]);
// Look again for the module.
Module = ModMap.findModule(ModuleName);
@@ -404,7 +407,7 @@ const FileEntry *DirectoryLookup::LookupFile(
return Result;
}
-/// \brief Given a framework directory, find the top-most framework directory.
+/// Given a framework directory, find the top-most framework directory.
///
/// \param FileMgr The file manager to use for directory lookups.
/// \param DirName The name of the framework directory.
@@ -527,7 +530,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
-
+
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
unsigned OrigSize = FrameworkName.size();
@@ -600,7 +603,7 @@ void HeaderSearch::setTarget(const TargetInfo &Target) {
// Header File Location.
//===----------------------------------------------------------------------===//
-/// \brief Return true with a diagnostic if the file that MSVC would have found
+/// Return true with a diagnostic if the file that MSVC would have found
/// fails to match the one that Clang would have found with MSVC header search
/// disabled.
static bool checkMSVCHeaderSearch(DiagnosticsEngine &Diags,
@@ -621,6 +624,74 @@ static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
return CopyStr;
}
+static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
+ SmallVectorImpl<char> &FrameworkName) {
+ using namespace llvm::sys;
+ path::const_iterator I = path::begin(Path);
+ path::const_iterator E = path::end(Path);
+ IsPrivateHeader = false;
+
+ // Detect different types of framework style paths:
+ //
+ // ...Foo.framework/{Headers,PrivateHeaders}
+ // ...Foo.framework/Versions/{A,Current}/{Headers,PrivateHeaders}
+ // ...Foo.framework/Frameworks/Nested.framework/{Headers,PrivateHeaders}
+ // ...<other variations with 'Versions' like in the above path>
+ //
+ // and some other variations among these lines.
+ int FoundComp = 0;
+ while (I != E) {
+ if (*I == "Headers")
+ ++FoundComp;
+ if (I->endswith(".framework")) {
+ FrameworkName.append(I->begin(), I->end());
+ ++FoundComp;
+ }
+ if (*I == "PrivateHeaders") {
+ ++FoundComp;
+ IsPrivateHeader = true;
+ }
+ ++I;
+ }
+
+ return FoundComp >= 2;
+}
+
+static void
+diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
+ StringRef Includer, StringRef IncludeFilename,
+ const FileEntry *IncludeFE, bool isAngled = false,
+ bool FoundByHeaderMap = false) {
+ bool IsIncluderPrivateHeader = false;
+ SmallString<128> FromFramework, ToFramework;
+ if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework))
+ return;
+ bool IsIncludeePrivateHeader = false;
+ bool IsIncludeeInFramework = isFrameworkStylePath(
+ IncludeFE->getName(), IsIncludeePrivateHeader, ToFramework);
+
+ if (!isAngled && !FoundByHeaderMap) {
+ SmallString<128> NewInclude("<");
+ if (IsIncludeeInFramework) {
+ NewInclude += StringRef(ToFramework).drop_back(10); // drop .framework
+ NewInclude += "/";
+ }
+ NewInclude += IncludeFilename;
+ NewInclude += ">";
+ Diags.Report(IncludeLoc, diag::warn_quoted_include_in_framework_header)
+ << IncludeFilename
+ << FixItHint::CreateReplacement(IncludeLoc, NewInclude);
+ }
+
+ // Headers in Foo.framework/Headers should not include headers
+ // from Foo.framework/PrivateHeaders, since this violates public/private
+ // API boundaries and can cause modular dependency cycles.
+ if (!IsIncluderPrivateHeader && IsIncludeeInFramework &&
+ IsIncludeePrivateHeader && FromFramework == ToFramework)
+ Diags.Report(IncludeLoc, diag::warn_framework_include_private_from_public)
+ << IncludeFilename;
+}
+
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
@@ -638,7 +709,7 @@ const FileEntry *HeaderSearch::LookupFile(
if (SuggestedModule)
*SuggestedModule = ModuleMap::KnownHeader();
-
+
// If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) {
CurDir = nullptr;
@@ -722,8 +793,12 @@ const FileEntry *HeaderSearch::LookupFile(
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
- if (First)
+ if (First) {
+ diagnoseFrameworkInclude(Diags, IncludeLoc,
+ IncluderAndDir.second->getName(), Filename,
+ FE);
return FE;
+ }
// Otherwise, we found the path via MSVC header search rules. If
// -Wmsvc-include is enabled, we have to keep searching to see if we
@@ -823,7 +898,7 @@ const FileEntry *HeaderSearch::LookupFile(
size_t SlashPos = Filename.find('/');
if (SlashPos != StringRef::npos) {
HFI.IndexHeaderMapHeader = 1;
- HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(),
+ HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(),
SlashPos));
}
}
@@ -834,6 +909,12 @@ const FileEntry *HeaderSearch::LookupFile(
return MSFE;
}
+ bool FoundByHeaderMap = !IsMapped ? false : *IsMapped;
+ if (!Includers.empty())
+ diagnoseFrameworkInclude(Diags, IncludeLoc,
+ Includers.front().second->getName(), Filename,
+ FE, isAngled, FoundByHeaderMap);
+
// Remember this location for the next lookup we do.
CacheLookup.HitIdx = i;
return FE;
@@ -996,9 +1077,9 @@ LookupSubframeworkHeader(StringRef Filename,
// File Info Management.
//===----------------------------------------------------------------------===//
-/// \brief Merge the header file info provided by \p OtherHFI into the current
+/// Merge the header file info provided by \p OtherHFI into the current
/// header file info (\p HFI)
-static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
+static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
const HeaderFileInfo &OtherHFI) {
assert(OtherHFI.External && "expected to merge external HFI");
@@ -1020,7 +1101,7 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
if (HFI.Framework.empty())
HFI.Framework = OtherHFI.Framework;
}
-
+
/// getFileInfo - Return the HeaderFileInfo structure for the specified
/// FileEntry.
HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
@@ -1204,14 +1285,14 @@ StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
return FrameworkNames.insert(Framework).first->first();
}
-bool HeaderSearch::hasModuleMap(StringRef FileName,
+bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root,
bool IsSystem) {
if (!HSOpts->ImplicitModuleMaps)
return false;
SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
-
+
StringRef DirName = FileName;
do {
// Get the parent directory name.
@@ -1244,7 +1325,7 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
// If we hit the top of our search, we're done.
if (Dir == Root)
return false;
-
+
// Keep track of all of the directories we checked, so we can mark them as
// having module maps if we eventually do find a module map.
FixUpDirectories.push_back(Dir);
@@ -1304,7 +1385,7 @@ bool HeaderSearch::findUsableModuleForFrameworkHeader(
SmallVector<std::string, 4> SubmodulePath;
const DirectoryEntry *TopFrameworkDir
= ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
-
+
// Determine the name of the top-level framework.
StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
@@ -1451,16 +1532,16 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
return ModMap.findModule(Name);
}
-HeaderSearch::LoadModuleMapResult
+HeaderSearch::LoadModuleMapResult
HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
bool IsFramework) {
if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
return loadModuleMapFile(Dir, IsSystem, IsFramework);
-
+
return LMM_NoDirectory;
}
-HeaderSearch::LoadModuleMapResult
+HeaderSearch::LoadModuleMapResult
HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
bool IsFramework) {
auto KnownDir = DirectoryHasModuleMap.find(Dir);
@@ -1529,7 +1610,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
}
// Populate the list of modules.
- for (ModuleMap::module_iterator M = ModMap.module_begin(),
+ for (ModuleMap::module_iterator M = ModMap.module_begin(),
MEnd = ModMap.module_end();
M != MEnd; ++M) {
Modules.push_back(M->getValue());
@@ -1580,9 +1661,15 @@ void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
bool *IsSystem) {
// FIXME: We assume that the path name currently cached in the FileEntry is
- // the most appropriate one for this analysis (and that it's spelled the same
- // way as the corresponding header search path).
- StringRef Name = File->getName();
+ // the most appropriate one for this analysis (and that it's spelled the
+ // same way as the corresponding header search path).
+ return suggestPathToFileForDiagnostics(File->getName(), /*BuildDir=*/"",
+ IsSystem);
+}
+
+std::string HeaderSearch::suggestPathToFileForDiagnostics(
+ llvm::StringRef File, llvm::StringRef WorkingDir, bool *IsSystem) {
+ using namespace llvm::sys;
unsigned BestPrefixLength = 0;
unsigned BestSearchDir;
@@ -1593,12 +1680,17 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
continue;
StringRef Dir = SearchDirs[I].getDir()->getName();
- for (auto NI = llvm::sys::path::begin(Name),
- NE = llvm::sys::path::end(Name),
- DI = llvm::sys::path::begin(Dir),
- DE = llvm::sys::path::end(Dir);
+ llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
+ if (!WorkingDir.empty() && !path::is_absolute(Dir)) {
+ auto err = fs::make_absolute(WorkingDir, DirPath);
+ if (!err)
+ path::remove_dots(DirPath, /*remove_dot_dot=*/true);
+ Dir = DirPath;
+ }
+ for (auto NI = path::begin(File), NE = path::end(File),
+ DI = path::begin(Dir), DE = path::end(Dir);
/*termination condition in loop*/; ++NI, ++DI) {
- // '.' components in Name are ignored.
+ // '.' components in File are ignored.
while (NI != NE && *NI == ".")
++NI;
if (NI == NE)
@@ -1608,9 +1700,9 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
while (DI != DE && *DI == ".")
++DI;
if (DI == DE) {
- // Dir is a prefix of Name, up to '.' components and choice of path
+ // Dir is a prefix of File, up to '.' components and choice of path
// separators.
- unsigned PrefixLength = NI - llvm::sys::path::begin(Name);
+ unsigned PrefixLength = NI - path::begin(File);
if (PrefixLength > BestPrefixLength) {
BestPrefixLength = PrefixLength;
BestSearchDir = I;
@@ -1625,5 +1717,5 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
if (IsSystem)
*IsSystem = BestPrefixLength ? BestSearchDir >= SystemDirIdx : false;
- return Name.drop_front(BestPrefixLength);
+ return File.drop_front(BestPrefixLength);
}