aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Lex/HeaderSearch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Lex/HeaderSearch.cpp')
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp220
1 files changed, 127 insertions, 93 deletions
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 60fd42bc1127..074c147ba3c5 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -116,6 +116,7 @@ void HeaderSearch::SetSearchPaths(
NoCurDirSearch = noCurDirSearch;
SearchDirToHSEntry = std::move(searchDirToHSEntry);
//LookupFileCache.clear();
+ indexInitialHeaderMaps();
}
void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
@@ -170,11 +171,11 @@ void HeaderSearch::getHeaderMapFileNames(
}
std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
- const FileEntry *ModuleMap =
+ OptionalFileEntryRef ModuleMap =
getModuleMap().getModuleMapFileForUniquing(Module);
// The ModuleMap maybe a nullptr, when we load a cached C++ module without
// *.modulemap file. In this case, just return an empty string.
- if (ModuleMap == nullptr)
+ if (!ModuleMap)
return {};
return getCachedModuleFileName(Module->Name, ModuleMap->getName());
}
@@ -211,7 +212,7 @@ std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
}
std::string HeaderSearch::getPrebuiltImplicitModuleFileName(Module *Module) {
- const FileEntry *ModuleMap =
+ OptionalFileEntryRef ModuleMap =
getModuleMap().getModuleMapFileForUniquing(Module);
StringRef ModuleName = Module->Name;
StringRef ModuleMapPath = ModuleMap->getName();
@@ -255,18 +256,11 @@ std::string HeaderSearch::getCachedModuleFileNameImpl(StringRef ModuleName,
//
// To avoid false-negatives, we form as canonical a path as we can, and map
// to lower-case in case we're on a case-insensitive file system.
- std::string Parent =
- std::string(llvm::sys::path::parent_path(ModuleMapPath));
- if (Parent.empty())
- Parent = ".";
- auto Dir = FileMgr.getDirectory(Parent);
- if (!Dir)
+ SmallString<128> CanonicalPath(ModuleMapPath);
+ if (getModuleMap().canonicalizeModuleMapPath(CanonicalPath))
return {};
- auto DirName = FileMgr.getCanonicalName(*Dir);
- auto FileName = llvm::sys::path::filename(ModuleMapPath);
- llvm::hash_code Hash =
- llvm::hash_combine(DirName.lower(), FileName.lower());
+ llvm::hash_code Hash = llvm::hash_combine(CanonicalPath.str().lower());
SmallString<128> HashStr;
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
@@ -311,7 +305,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
// Look through the various header search paths to load any available module
// maps, searching for a module map that describes this module.
- for (DirectoryLookup Dir : search_dir_range()) {
+ for (DirectoryLookup &Dir : search_dir_range()) {
if (Dir.isFramework()) {
// Search for or infer a module map for a framework. Here we use
// SearchName rather than ModuleName, to permit finding private modules
@@ -335,7 +329,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
continue;
bool IsSystem = Dir.isSystemHeaderDirectory();
- // Only returns None if not a normal directory, which we just checked
+ // Only returns std::nullopt if not a normal directory, which we just
+ // checked
DirectoryEntryRef NormalDir = *Dir.getDirRef();
// Search for a module map file in this directory.
if (loadModuleMapFile(NormalDir, IsSystem,
@@ -379,6 +374,31 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
return Module;
}
+void HeaderSearch::indexInitialHeaderMaps() {
+ llvm::StringMap<unsigned, llvm::BumpPtrAllocator> Index(SearchDirs.size());
+
+ // Iterate over all filename keys and associate them with the index i.
+ unsigned i = 0;
+ for (; i != SearchDirs.size(); ++i) {
+ auto &Dir = SearchDirs[i];
+
+ // We're concerned with only the initial contiguous run of header
+ // maps within SearchDirs, which can be 99% of SearchDirs when
+ // SearchDirs.size() is ~10000.
+ if (!Dir.isHeaderMap())
+ break;
+
+ // Give earlier keys precedence over identical later keys.
+ auto Callback = [&](StringRef Filename) {
+ Index.try_emplace(Filename.lower(), i);
+ };
+ Dir.getHeaderMap()->forEachKey(Callback);
+ }
+
+ SearchDirHeaderMapIndex = std::move(Index);
+ FirstNonHeaderMapSearchDirIdx = i;
+}
+
//===----------------------------------------------------------------------===//
// File lookup within a DirectoryLookup scope
//===----------------------------------------------------------------------===//
@@ -395,13 +415,14 @@ StringRef DirectoryLookup::getName() const {
return getHeaderMap()->getFileName();
}
-Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
+OptionalFileEntryRef HeaderSearch::getFileAndSuggestModule(
StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
bool IsSystemHeaderDir, Module *RequestingModule,
- ModuleMap::KnownHeader *SuggestedModule) {
+ ModuleMap::KnownHeader *SuggestedModule, bool OpenFile /*=true*/,
+ bool CacheFailures /*=true*/) {
// If we have a module map that might map this header, load it and
// check whether we'll have a suggestion for a module.
- auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
+ auto File = getFileMgr().getFileRef(FileName, OpenFile, CacheFailures);
if (!File) {
// For rare, surprising errors (e.g. "out of file handles"), diag the EC
// message.
@@ -412,26 +433,27 @@ Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
Diags.Report(IncludeLoc, diag::err_cannot_open_file)
<< FileName << EC.message();
}
- return None;
+ return std::nullopt;
}
// If there is a module that corresponds to this header, suggest it.
if (!findUsableModuleForHeader(
&File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
RequestingModule, SuggestedModule, IsSystemHeaderDir))
- return None;
+ return std::nullopt;
return *File;
}
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
-Optional<FileEntryRef> DirectoryLookup::LookupFile(
+OptionalFileEntryRef DirectoryLookup::LookupFile(
StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
- bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName) const {
+ bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName,
+ bool OpenFile) const {
InUserSpecifiedSystemFramework = false;
IsInHeaderMap = false;
MappedName.clear();
@@ -451,9 +473,9 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
RelativePath->append(Filename.begin(), Filename.end());
}
- return HS.getFileAndSuggestModule(TmpDir, IncludeLoc, getDir(),
- isSystemHeaderDirectory(),
- RequestingModule, SuggestedModule);
+ return HS.getFileAndSuggestModule(
+ TmpDir, IncludeLoc, getDir(), isSystemHeaderDirectory(),
+ RequestingModule, SuggestedModule, OpenFile);
}
if (isFramework())
@@ -466,7 +488,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
SmallString<1024> Path;
StringRef Dest = HM->lookupFilename(Filename, Path);
if (Dest.empty())
- return None;
+ return std::nullopt;
IsInHeaderMap = true;
@@ -491,7 +513,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
Dest = HM->lookupFilename(Filename, Path);
}
- if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) {
+ if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest, OpenFile)) {
FixupSearchPath();
return *Res;
}
@@ -501,7 +523,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
// function as part of the regular logic that applies to include search paths.
// The case where the target file **does not exist** is handled here:
HS.noteLookupUsage(HS.searchDirIdx(*this), IncludeLoc);
- return None;
+ return std::nullopt;
}
/// Given a framework directory, find the top-most framework directory.
@@ -510,7 +532,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
/// \param DirName The name of the framework directory.
/// \param SubmodulePath Will be populated with the submodule path from the
/// returned top-level module to the originally named framework.
-static Optional<DirectoryEntryRef>
+static OptionalDirectoryEntryRef
getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
SmallVectorImpl<std::string> &SubmodulePath) {
assert(llvm::sys::path::extension(DirName) == ".framework" &&
@@ -564,7 +586,7 @@ static bool needModuleLookup(Module *RequestingModule,
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
-Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
+OptionalFileEntryRef DirectoryLookup::DoFrameworkLookup(
StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule,
@@ -574,7 +596,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
// Framework names must have a '/' in the filename.
size_t SlashPos = Filename.find('/');
if (SlashPos == StringRef::npos)
- return None;
+ return std::nullopt;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answers are yes/no and unknown.
@@ -583,7 +605,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
// If it is known and in some other directory, fail.
if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDirRef())
- return None;
+ return std::nullopt;
// Otherwise, construct the path to this framework dir.
@@ -607,7 +629,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
// If the framework dir doesn't exist, we fail.
auto Dir = FileMgr.getDirectory(FrameworkName);
if (!Dir)
- return None;
+ return std::nullopt;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
@@ -690,17 +712,17 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
if (!HS.findUsableModuleForFrameworkHeader(
&File->getFileEntry(), FrameworkPath, RequestingModule,
SuggestedModule, IsSystem))
- return None;
+ return std::nullopt;
} else {
if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(),
RequestingModule, SuggestedModule,
IsSystem))
- return None;
+ return std::nullopt;
}
}
if (File)
return *File;
- return None;
+ return std::nullopt;
}
void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup,
@@ -833,14 +855,14 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
/// non-empty, indicates where the \#including file(s) are, in case a relative
/// search is needed. Microsoft mode will pass all \#including files.
-Optional<FileEntryRef> HeaderSearch::LookupFile(
+OptionalFileEntryRef HeaderSearch::LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
ConstSearchDirIterator FromDir, ConstSearchDirIterator *CurDirArg,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
bool *IsMapped, bool *IsFrameworkFound, bool SkipCache,
- bool BuildSystemModule) {
+ bool BuildSystemModule, bool OpenFile, bool CacheFailures) {
ConstSearchDirIterator CurDirLocal = nullptr;
ConstSearchDirIterator &CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
@@ -859,7 +881,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
// If this was an #include_next "/absolute/file", fail.
if (FromDir)
- return None;
+ return std::nullopt;
if (SearchPath)
SearchPath->clear();
@@ -869,13 +891,14 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
}
// Otherwise, just return the file.
return getFileAndSuggestModule(Filename, IncludeLoc, nullptr,
- /*IsSystemHeaderDir*/false,
- RequestingModule, SuggestedModule);
+ /*IsSystemHeaderDir*/ false,
+ RequestingModule, SuggestedModule, OpenFile,
+ CacheFailures);
}
// This is the header that MSVC's header search would have found.
ModuleMap::KnownHeader MSSuggestedModule;
- Optional<FileEntryRef> MSFE;
+ OptionalFileEntryRef MSFE;
// Unless disabled, check to see if the file is in the #includer's
// directory. This cannot be based on CurDir, because each includer could be
@@ -904,7 +927,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
bool IncluderIsSystemHeader =
Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
BuildSystemModule;
- if (Optional<FileEntryRef> FE = getFileAndSuggestModule(
+ if (OptionalFileEntryRef FE = getFileAndSuggestModule(
TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
RequestingModule, SuggestedModule)) {
if (!Includer) {
@@ -981,24 +1004,37 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
ConstSearchDirIterator NextIt = std::next(It);
- // If the entry has been previously looked up, the first value will be
- // non-zero. If the value is equal to i (the start point of our search), then
- // this is a matching hit.
- if (!SkipCache && CacheLookup.StartIt == NextIt) {
- // Skip querying potentially lots of directories for this lookup.
- if (CacheLookup.HitIt)
- It = CacheLookup.HitIt;
- if (CacheLookup.MappedName) {
- Filename = CacheLookup.MappedName;
- if (IsMapped)
- *IsMapped = true;
+ if (!SkipCache) {
+ if (CacheLookup.StartIt == NextIt) {
+ // HIT: Skip querying potentially lots of directories for this lookup.
+ if (CacheLookup.HitIt)
+ It = CacheLookup.HitIt;
+ if (CacheLookup.MappedName) {
+ Filename = CacheLookup.MappedName;
+ if (IsMapped)
+ *IsMapped = true;
+ }
+ } else {
+ // MISS: This is the first query, or the previous query didn't match
+ // our search start. We will fill in our found location below, so prime
+ // the start point value.
+ CacheLookup.reset(/*NewStartIt=*/NextIt);
+
+ if (It == search_dir_begin() && FirstNonHeaderMapSearchDirIdx > 0) {
+ // Handle cold misses of user includes in the presence of many header
+ // maps. We avoid searching perhaps thousands of header maps by
+ // jumping directly to the correct one or jumping beyond all of them.
+ auto Iter = SearchDirHeaderMapIndex.find(Filename.lower());
+ if (Iter == SearchDirHeaderMapIndex.end())
+ // Not in index => Skip to first SearchDir after initial header maps
+ It = search_dir_nth(FirstNonHeaderMapSearchDirIdx);
+ else
+ // In index => Start with a specific header map
+ It = search_dir_nth(Iter->second);
+ }
}
- } else {
- // Otherwise, this is the first query, or the previous query didn't match
- // our search start. We will fill in our found location below, so prime the
- // start point value.
+ } else
CacheLookup.reset(/*NewStartIt=*/NextIt);
- }
SmallString<64> MappedName;
@@ -1007,10 +1043,10 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
bool InUserSpecifiedSystemFramework = false;
bool IsInHeaderMap = false;
bool IsFrameworkFoundInDir = false;
- Optional<FileEntryRef> File = It->LookupFile(
+ OptionalFileEntryRef File = It->LookupFile(
Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
- IsInHeaderMap, MappedName);
+ IsInHeaderMap, MappedName, OpenFile);
if (!MappedName.empty()) {
assert(IsInHeaderMap && "MappedName should come from a header map");
CacheLookup.MappedName =
@@ -1102,7 +1138,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
ScratchFilename += '/';
ScratchFilename += Filename;
- Optional<FileEntryRef> File = LookupFile(
+ OptionalFileEntryRef File = LookupFile(
ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir,
Includers.front(), SearchPath, RelativePath, RequestingModule,
SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
@@ -1131,7 +1167,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
// Otherwise, didn't find it. Remember we didn't find this.
CacheLookup.HitIt = search_dir_end();
- return None;
+ return std::nullopt;
}
/// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -1139,7 +1175,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
-Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
+OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader(
StringRef Filename, const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
@@ -1149,7 +1185,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
// FIXME: Should we permit '\' on Windows?
size_t SlashPos = Filename.find('/');
if (SlashPos == StringRef::npos)
- return None;
+ return std::nullopt;
// Look up the base framework name of the ContextFileEnt.
StringRef ContextName = ContextFileEnt->getName();
@@ -1160,7 +1196,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
if (FrameworkPos == StringRef::npos ||
(ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
- return None;
+ return std::nullopt;
SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
FrameworkPos +
@@ -1180,7 +1216,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
CacheLookup.first().size() == FrameworkName.size() &&
memcmp(CacheLookup.first().data(), &FrameworkName[0],
CacheLookup.first().size()) != 0)
- return None;
+ return std::nullopt;
// Cache subframework.
if (!CacheLookup.second.Directory) {
@@ -1189,7 +1225,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
// If the framework dir doesn't exist, we fail.
auto Dir = FileMgr.getOptionalDirectoryRef(FrameworkName);
if (!Dir)
- return None;
+ return std::nullopt;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
@@ -1227,7 +1263,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
if (!File)
- return None;
+ return std::nullopt;
}
// This file is a system header or C++ unfriendly if the old file is.
@@ -1242,7 +1278,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName,
RequestingModule, SuggestedModule,
/*IsSystem*/ false))
- return None;
+ return std::nullopt;
return *File;
}
@@ -1348,7 +1384,7 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
ModuleMap::ModuleHeaderRole Role,
bool isCompilingModuleHeader) {
- bool isModularHeader = !(Role & ModuleMap::TextualHeader);
+ bool isModularHeader = ModuleMap::isModular(Role);
// Don't mark the file info as non-external if there's nothing to change.
if (!isCompilingModuleHeader) {
@@ -1519,14 +1555,14 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
}
ModuleMap::KnownHeader
-HeaderSearch::findModuleForHeader(const FileEntry *File,
- bool AllowTextual) const {
+HeaderSearch::findModuleForHeader(const FileEntry *File, bool AllowTextual,
+ bool AllowExcluded) const {
if (ExternalSource) {
// Make sure the external source has handled header info about this file,
// which includes whether the file is part of a module.
(void)getExistingFileInfo(File);
}
- return ModMap.findModuleForHeader(File, AllowTextual);
+ return ModMap.findModuleForHeader(File, AllowTextual, AllowExcluded);
}
ArrayRef<ModuleMap::KnownHeader>
@@ -1560,6 +1596,8 @@ static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
*SuggestedModule = ModuleMap::KnownHeader();
return true;
}
+ // TODO: Add this module (or just its module map file) into something like
+ // `RequestingModule->AffectingClangModules`.
return false;
}
}
@@ -1590,7 +1628,7 @@ bool HeaderSearch::findUsableModuleForFrameworkHeader(
if (needModuleLookup(RequestingModule, SuggestedModule)) {
// Find the top-level framework based on this framework.
SmallVector<std::string, 4> SubmodulePath;
- Optional<DirectoryEntryRef> TopFrameworkDir =
+ OptionalDirectoryEntryRef TopFrameworkDir =
::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
assert(TopFrameworkDir && "Could not find the top-most framework dir");
@@ -1630,7 +1668,7 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
StringRef OriginalModuleMapFile) {
// Find the directory for the module. For frameworks, that may require going
// up from the 'Modules' directory.
- Optional<DirectoryEntryRef> Dir;
+ OptionalDirectoryEntryRef Dir;
if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd) {
Dir = FileMgr.getOptionalDirectoryRef(".");
} else {
@@ -1891,32 +1929,28 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
llvm::StringRef File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
bool *IsSystem) {
using namespace llvm::sys;
+
+ llvm::SmallString<32> FilePath = File;
+ // remove_dots switches to backslashes on windows as a side-effect!
+ // We always want to suggest forward slashes for includes.
+ // (not remove_dots(..., posix) as that misparses windows paths).
+ path::remove_dots(FilePath, /*remove_dot_dot=*/true);
+ path::native(FilePath, path::Style::posix);
+ File = FilePath;
unsigned BestPrefixLength = 0;
// Checks whether `Dir` is a strict path prefix of `File`. If so and that's
// the longest prefix we've seen so for it, returns true and updates the
// `BestPrefixLength` accordingly.
- auto CheckDir = [&](llvm::StringRef Dir) -> bool {
- llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
+ auto CheckDir = [&](llvm::SmallString<32> Dir) -> bool {
if (!WorkingDir.empty() && !path::is_absolute(Dir))
- fs::make_absolute(WorkingDir, DirPath);
- path::remove_dots(DirPath, /*remove_dot_dot=*/true);
- Dir = DirPath;
+ fs::make_absolute(WorkingDir, Dir);
+ path::remove_dots(Dir, /*remove_dot_dot=*/true);
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 File are ignored.
- while (NI != NE && *NI == ".")
- ++NI;
- if (NI == NE)
- break;
-
- // '.' components in Dir are ignored.
- while (DI != DE && *DI == ".")
- ++DI;
+ NI != NE; ++NI, ++DI) {
if (DI == DE) {
- // Dir is a prefix of File, up to '.' components and choice of path
- // separators.
+ // Dir is a prefix of File, up to choice of path separators.
unsigned PrefixLength = NI - path::begin(File);
if (PrefixLength > BestPrefixLength) {
BestPrefixLength = PrefixLength;