aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Lex/HeaderSearch.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-01-27 22:06:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-01-27 22:06:42 +0000
commit6f8fc217eaa12bf657be1c6468ed9938d10168b3 (patch)
treea1fd89b864d9b93e2ad68fe1dcf7afee2e3c8d76 /clang/lib/Lex/HeaderSearch.cpp
parent77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (diff)
downloadsrc-6f8fc217eaa12bf657be1c6468ed9938d10168b3.tar.gz
src-6f8fc217eaa12bf657be1c6468ed9938d10168b3.zip
Diffstat (limited to 'clang/lib/Lex/HeaderSearch.cpp')
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp156
1 files changed, 108 insertions, 48 deletions
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index a0b60118a1a8..39c125c395ef 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -29,6 +29,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/Errc.h"
@@ -89,16 +90,10 @@ HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,
void HeaderSearch::PrintStats() {
llvm::errs() << "\n*** HeaderSearch Stats:\n"
<< FileInfo.size() << " files tracked.\n";
- unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
- for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
+ unsigned NumOnceOnlyFiles = 0;
+ for (unsigned i = 0, e = FileInfo.size(); i != e; ++i)
NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport);
- if (MaxNumIncludes < FileInfo[i].NumIncludes)
- MaxNumIncludes = FileInfo[i].NumIncludes;
- NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
- }
- llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n"
- << " " << NumSingleIncludedFiles << " included exactly once.\n"
- << " " << MaxNumIncludes << " max times a file is included.\n";
+ llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n";
llvm::errs() << " " << NumIncluded << " #include/#include_next/#import.\n"
<< " " << NumMultiIncludeFileOptzn
@@ -108,6 +103,30 @@ void HeaderSearch::PrintStats() {
<< NumSubFrameworkLookups << " subframework lookups.\n";
}
+void HeaderSearch::SetSearchPaths(
+ std::vector<DirectoryLookup> dirs, unsigned int angledDirIdx,
+ unsigned int systemDirIdx, bool noCurDirSearch,
+ llvm::DenseMap<unsigned int, unsigned int> searchDirToHSEntry) {
+ assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
+ "Directory indices are unordered");
+ SearchDirs = std::move(dirs);
+ SearchDirsUsage.assign(SearchDirs.size(), false);
+ AngledDirIdx = angledDirIdx;
+ SystemDirIdx = systemDirIdx;
+ NoCurDirSearch = noCurDirSearch;
+ SearchDirToHSEntry = std::move(searchDirToHSEntry);
+ //LookupFileCache.clear();
+}
+
+void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
+ unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
+ SearchDirs.insert(SearchDirs.begin() + idx, dir);
+ SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false);
+ if (!isAngled)
+ AngledDirIdx++;
+ SystemDirIdx++;
+}
+
std::vector<bool> HeaderSearch::computeUserEntryUsage() const {
std::vector<bool> UserEntryUsage(HSOpts->UserEntries.size());
for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) {
@@ -720,7 +739,8 @@ static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
}
static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
- SmallVectorImpl<char> &FrameworkName) {
+ SmallVectorImpl<char> &FrameworkName,
+ SmallVectorImpl<char> &IncludeSpelling) {
using namespace llvm::sys;
path::const_iterator I = path::begin(Path);
path::const_iterator E = path::end(Path);
@@ -736,15 +756,22 @@ static bool isFrameworkStylePath(StringRef Path, bool &IsPrivateHeader,
// and some other variations among these lines.
int FoundComp = 0;
while (I != E) {
- if (*I == "Headers")
+ if (*I == "Headers") {
++FoundComp;
- if (I->endswith(".framework")) {
- FrameworkName.append(I->begin(), I->end());
- ++FoundComp;
- }
- if (*I == "PrivateHeaders") {
+ } else if (*I == "PrivateHeaders") {
++FoundComp;
IsPrivateHeader = true;
+ } else if (I->endswith(".framework")) {
+ StringRef Name = I->drop_back(10); // Drop .framework
+ // Need to reset the strings and counter to support nested frameworks.
+ FrameworkName.clear();
+ FrameworkName.append(Name.begin(), Name.end());
+ IncludeSpelling.clear();
+ IncludeSpelling.append(Name.begin(), Name.end());
+ FoundComp = 1;
+ } else if (FoundComp >= 2) {
+ IncludeSpelling.push_back('/');
+ IncludeSpelling.append(I->begin(), I->end());
}
++I;
}
@@ -759,20 +786,24 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
bool FoundByHeaderMap = false) {
bool IsIncluderPrivateHeader = false;
SmallString<128> FromFramework, ToFramework;
- if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework))
+ SmallString<128> FromIncludeSpelling, ToIncludeSpelling;
+ if (!isFrameworkStylePath(Includer, IsIncluderPrivateHeader, FromFramework,
+ FromIncludeSpelling))
return;
bool IsIncludeePrivateHeader = false;
- bool IsIncludeeInFramework = isFrameworkStylePath(
- IncludeFE->getName(), IsIncludeePrivateHeader, ToFramework);
+ bool IsIncludeeInFramework =
+ isFrameworkStylePath(IncludeFE->getName(), IsIncludeePrivateHeader,
+ ToFramework, ToIncludeSpelling);
if (!isAngled && !FoundByHeaderMap) {
SmallString<128> NewInclude("<");
if (IsIncludeeInFramework) {
- NewInclude += ToFramework.str().drop_back(10); // drop .framework
- NewInclude += "/";
+ NewInclude += ToIncludeSpelling;
+ NewInclude += ">";
+ } else {
+ NewInclude += IncludeFilename;
+ NewInclude += ">";
}
- NewInclude += IncludeFilename;
- NewInclude += ">";
Diags.Report(IncludeLoc, diag::warn_quoted_include_in_framework_header)
<< IncludeFilename
<< FixItHint::CreateReplacement(IncludeLoc, NewInclude);
@@ -794,12 +825,15 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
/// search is needed. Microsoft mode will pass all \#including files.
Optional<FileEntryRef> HeaderSearch::LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
- const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
+ const DirectoryLookup *FromDir, const DirectoryLookup **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) {
+ const DirectoryLookup *CurDirLocal = nullptr;
+ const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
+
if (IsMapped)
*IsMapped = false;
@@ -1046,7 +1080,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
ScratchFilename += Filename;
Optional<FileEntryRef> File = LookupFile(
- ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
+ ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir,
Includers.front(), SearchPath, RelativePath, RequestingModule,
SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
@@ -1203,7 +1237,6 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
HFI.isImport |= OtherHFI.isImport;
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
HFI.isModuleHeader |= OtherHFI.isModuleHeader;
- HFI.NumIncludes += OtherHFI.NumIncludes;
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
HFI.ControllingMacro = OtherHFI.ControllingMacro;
@@ -1364,7 +1397,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
FileInfo.isImport = true;
// Has this already been #import'ed or #include'd?
- if (FileInfo.NumIncludes && !TryEnterImported())
+ if (PP.alreadyIncluded(File) && !TryEnterImported())
return false;
} else {
// Otherwise, if this is a #include of a file that was previously #import'd
@@ -1387,10 +1420,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
}
}
- // Increment the number of times this file has been included.
- ++FileInfo.NumIncludes;
-
- IsFirstIncludeOfFile = FileInfo.NumIncludes == 1;
+ IsFirstIncludeOfFile = PP.markIncluded(File);
return true;
}
@@ -1779,11 +1809,8 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
}
// Populate the list of modules.
- for (ModuleMap::module_iterator M = ModMap.module_begin(),
- MEnd = ModMap.module_end();
- M != MEnd; ++M) {
- Modules.push_back(M->getValue());
- }
+ llvm::transform(ModMap.modules(), std::back_inserter(Modules),
+ [](const auto &NameAndMod) { return NameAndMod.second; });
}
void HeaderSearch::loadTopLevelSystemModules() {
@@ -1843,9 +1870,9 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
using namespace llvm::sys;
unsigned BestPrefixLength = 0;
- // Checks whether Dir and File shares a common prefix, if they do and that's
- // the longest prefix we've seen so for it returns true and updates the
- // BestPrefixLength accordingly.
+ // 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());
if (!WorkingDir.empty() && !path::is_absolute(Dir))
@@ -1880,26 +1907,48 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
path::is_separator(NI->front()) && path::is_separator(DI->front()))
continue;
+ // Special case Apple .sdk folders since the search path is typically a
+ // symlink like `iPhoneSimulator14.5.sdk` while the file is instead
+ // located in `iPhoneSimulator.sdk` (the real folder).
+ if (NI->endswith(".sdk") && DI->endswith(".sdk")) {
+ StringRef NBasename = path::stem(*NI);
+ StringRef DBasename = path::stem(*DI);
+ if (DBasename.startswith(NBasename))
+ continue;
+ }
+
if (*NI != *DI)
break;
}
return false;
};
+ bool BestPrefixIsFramework = false;
for (unsigned I = 0; I != SearchDirs.size(); ++I) {
- // FIXME: Support this search within frameworks.
- if (!SearchDirs[I].isNormalDir())
- continue;
-
- StringRef Dir = SearchDirs[I].getDir()->getName();
- if (CheckDir(Dir) && IsSystem)
- *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
+ if (SearchDirs[I].isNormalDir()) {
+ StringRef Dir = SearchDirs[I].getDir()->getName();
+ if (CheckDir(Dir)) {
+ if (IsSystem)
+ *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
+ BestPrefixIsFramework = false;
+ }
+ } else if (SearchDirs[I].isFramework()) {
+ StringRef Dir = SearchDirs[I].getFrameworkDir()->getName();
+ if (CheckDir(Dir)) {
+ if (IsSystem)
+ *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
+ BestPrefixIsFramework = true;
+ }
+ }
}
// Try to shorten include path using TUs directory, if we couldn't find any
// suitable prefix in include search paths.
- if (!BestPrefixLength && CheckDir(path::parent_path(MainFile)) && IsSystem)
- *IsSystem = false;
+ if (!BestPrefixLength && CheckDir(path::parent_path(MainFile))) {
+ if (IsSystem)
+ *IsSystem = false;
+ BestPrefixIsFramework = false;
+ }
// Try resolving resulting filename via reverse search in header maps,
// key from header name is user prefered name for the include file.
@@ -1912,8 +1961,19 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
SearchDirs[I].getHeaderMap()->reverseLookupFilename(Filename);
if (!SpelledFilename.empty()) {
Filename = SpelledFilename;
+ BestPrefixIsFramework = false;
break;
}
}
+
+ // If the best prefix is a framework path, we need to compute the proper
+ // include spelling for the framework header.
+ bool IsPrivateHeader;
+ SmallString<128> FrameworkName, IncludeSpelling;
+ if (BestPrefixIsFramework &&
+ isFrameworkStylePath(Filename, IsPrivateHeader, FrameworkName,
+ IncludeSpelling)) {
+ Filename = IncludeSpelling;
+ }
return path::convert_to_slash(Filename);
}