Skip to content

Commit 4445135

Browse files
committed
[clang][lex] Remark on search path usage
For dependency scanning, it would be useful to collect header search paths (provided on command-line via `-I` and friends) that were actually used during preprocessing. This patch adds that feature to `HeaderSearch` along with a new remark that reports such paths as they get used. Previous version of this patch tried to use the existing `LookupFileCache` to report used paths via `HitIdx`. That doesn't work for `ComputeUserEntryUsage` (which is intended to be called *after* preprocessing), because it indexes used search paths by the file name. This means the values get overwritten when the code contains `#include_next`. Note that `HeaderSearch` doesn't use `HeaderSearchOptions::UserEntries` directly. Instead, `InitHeaderSearch` pre-processes them (adds platform-specific paths, removes duplicates, removes paths that don't exist) and creates `DirectoryLookup` instances. This means we need a mechanism for translating between those two. It's not possible to go from `DirectoryLookup` back to the original `HeaderSearch`, so `InitHeaderSearch` now tracks the relationships explicitly. Depends on D111557. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D102923
1 parent f4c1258 commit 4445135

File tree

18 files changed

+303
-60
lines changed

18 files changed

+303
-60
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">;
751751
def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">;
752752
def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">;
753753
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
754+
def UsedSearchPath : DiagGroup<"search-path-usage">;
754755
def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
755756
def UserDefinedWarnings : DiagGroup<"user-defined-warnings">;
756757
def ReorderCtor : DiagGroup<"reorder-ctor">;

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ def warn_pp_hdrstop_filename_ignored : Warning<
446446
"#pragma hdrstop filename not supported, "
447447
"/Fp can be used to specify precompiled header filename">,
448448
InGroup<ClangClPch>;
449+
def remark_pp_search_path_usage : Remark<
450+
"search path used: '%0'">,
451+
InGroup<UsedSearchPath>;
449452
def err_pp_file_not_found_angled_include_not_fatal : Error<
450453
"'%0' file not found with <angled> %select{include|import}1; "
451454
"use \"quotes\" instead">;

clang/include/clang/Lex/HeaderMap.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,6 @@ class HeaderMap : private HeaderMapImpl {
7777
static std::unique_ptr<HeaderMap> Create(const FileEntry *FE,
7878
FileManager &FM);
7979

80-
/// Check to see if the specified relative filename is located in this
81-
/// HeaderMap. If so, open it and return its FileEntry. If RawPath is not
82-
/// NULL and the file is found, RawPath will be set to the raw path at which
83-
/// the file was found in the file system. For example, for a search path
84-
/// ".." and a filename "../file.h" this would be "../../file.h".
85-
Optional<FileEntryRef> LookupFile(StringRef Filename, FileManager &FM) const;
86-
8780
using HeaderMapImpl::dump;
8881
using HeaderMapImpl::getFileName;
8982
using HeaderMapImpl::lookupFilename;

clang/include/clang/Lex/HeaderSearch.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ class HeaderSearch {
172172
/// Header-search options used to initialize this header search.
173173
std::shared_ptr<HeaderSearchOptions> HSOpts;
174174

175+
/// Mapping from SearchDir to HeaderSearchOptions::UserEntries indices.
176+
llvm::DenseMap<unsigned, unsigned> SearchDirToHSEntry;
177+
175178
DiagnosticsEngine &Diags;
176179
FileManager &FileMgr;
177180

@@ -182,6 +185,9 @@ class HeaderSearch {
182185
/// NoCurDirSearch is true, then the check for the file in the current
183186
/// directory is suppressed.
184187
std::vector<DirectoryLookup> SearchDirs;
188+
/// Whether the DirectoryLookup at the corresponding index in SearchDirs has
189+
/// been successfully used to lookup a file.
190+
std::vector<bool> SearchDirsUsage;
185191
unsigned AngledDirIdx = 0;
186192
unsigned SystemDirIdx = 0;
187193
bool NoCurDirSearch = false;
@@ -280,22 +286,25 @@ class HeaderSearch {
280286
DiagnosticsEngine &getDiags() const { return Diags; }
281287

282288
/// Interface for setting the file search paths.
283-
void SetSearchPaths(const std::vector<DirectoryLookup> &dirs,
284-
unsigned angledDirIdx, unsigned systemDirIdx,
285-
bool noCurDirSearch) {
289+
void SetSearchPaths(std::vector<DirectoryLookup> dirs, unsigned angledDirIdx,
290+
unsigned systemDirIdx, bool noCurDirSearch,
291+
llvm::DenseMap<unsigned, unsigned> searchDirToHSEntry) {
286292
assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
287293
"Directory indices are unordered");
288-
SearchDirs = dirs;
294+
SearchDirs = std::move(dirs);
295+
SearchDirsUsage.assign(SearchDirs.size(), false);
289296
AngledDirIdx = angledDirIdx;
290297
SystemDirIdx = systemDirIdx;
291298
NoCurDirSearch = noCurDirSearch;
299+
SearchDirToHSEntry = std::move(searchDirToHSEntry);
292300
//LookupFileCache.clear();
293301
}
294302

295303
/// Add an additional search path.
296304
void AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
297305
unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
298306
SearchDirs.insert(SearchDirs.begin() + idx, dir);
307+
SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false);
299308
if (!isAngled)
300309
AngledDirIdx++;
301310
SystemDirIdx++;
@@ -505,6 +514,10 @@ class HeaderSearch {
505514
return FI && FI->isImport;
506515
}
507516

517+
/// Determine which HeaderSearchOptions::UserEntries have been successfully
518+
/// used so far and mark their index with 'true' in the resulting bit vector.
519+
std::vector<bool> computeUserEntryUsage() const;
520+
508521
/// This method returns a HeaderMap for the specified
509522
/// FileEntry, uniquing them through the 'HeaderMaps' datastructure.
510523
const HeaderMap *CreateHeaderMap(const FileEntry *FE);
@@ -714,6 +727,14 @@ class HeaderSearch {
714727
Module *RequestingModule,
715728
ModuleMap::KnownHeader *SuggestedModule);
716729

730+
/// Cache the result of a successful lookup at the given include location
731+
/// using the search path at index `HitIdx`.
732+
void cacheLookupSuccess(LookupFileCacheInfo &CacheLookup, unsigned HitIdx,
733+
SourceLocation IncludeLoc);
734+
/// Note that a lookup at the given include location was successful using the
735+
/// search path at index `HitIdx`.
736+
void noteLookupUsage(unsigned HitIdx, SourceLocation IncludeLoc);
737+
717738
public:
718739
/// Retrieve the module map.
719740
ModuleMap &getModuleMap() { return ModMap; }
@@ -763,6 +784,9 @@ class HeaderSearch {
763784

764785
search_dir_iterator system_dir_end() const { return SearchDirs.end(); }
765786

787+
/// Get the index of the given search directory.
788+
Optional<unsigned> searchDirIdx(const DirectoryLookup &DL) const;
789+
766790
/// Retrieve a uniqued framework name.
767791
StringRef getUniqueFrameworkName(StringRef Framework);
768792

clang/lib/Frontend/InitHeaderSearch.cpp

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ namespace {
3636
struct DirectoryLookupInfo {
3737
IncludeDirGroup Group;
3838
DirectoryLookup Lookup;
39+
Optional<unsigned> UserEntryIdx;
3940

40-
DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup)
41-
: Group(Group), Lookup(Lookup) {}
41+
DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup,
42+
Optional<unsigned> UserEntryIdx)
43+
: Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}
4244
};
4345

4446
/// InitHeaderSearch - This class makes it easier to set the search paths of
@@ -60,13 +62,15 @@ class InitHeaderSearch {
6062
/// AddPath - Add the specified path to the specified group list, prefixing
6163
/// the sysroot if used.
6264
/// Returns true if the path exists, false if it was ignored.
63-
bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework);
65+
bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework,
66+
Optional<unsigned> UserEntryIdx = None);
6467

6568
/// AddUnmappedPath - Add the specified path to the specified group list,
6669
/// without performing any sysroot remapping.
6770
/// Returns true if the path exists, false if it was ignored.
6871
bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
69-
bool isFramework);
72+
bool isFramework,
73+
Optional<unsigned> UserEntryIdx = None);
7074

7175
/// AddSystemHeaderPrefix - Add the specified prefix to the system header
7276
/// prefix list.
@@ -119,22 +123,25 @@ static bool CanPrefixSysroot(StringRef Path) {
119123
}
120124

121125
bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,
122-
bool isFramework) {
126+
bool isFramework,
127+
Optional<unsigned> UserEntryIdx) {
123128
// Add the path with sysroot prepended, if desired and this is a system header
124129
// group.
125130
if (HasSysroot) {
126131
SmallString<256> MappedPathStorage;
127132
StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
128133
if (CanPrefixSysroot(MappedPathStr)) {
129-
return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework);
134+
return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework,
135+
UserEntryIdx);
130136
}
131137
}
132138

133-
return AddUnmappedPath(Path, Group, isFramework);
139+
return AddUnmappedPath(Path, Group, isFramework, UserEntryIdx);
134140
}
135141

136142
bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
137-
bool isFramework) {
143+
bool isFramework,
144+
Optional<unsigned> UserEntryIdx) {
138145
assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
139146

140147
FileManager &FM = Headers.getFileMgr();
@@ -160,7 +167,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
160167

161168
// If the directory exists, add it.
162169
if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) {
163-
IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework));
170+
IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework),
171+
UserEntryIdx);
164172
return true;
165173
}
166174

@@ -171,7 +179,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
171179
if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) {
172180
// It is a headermap, add it to the search path.
173181
IncludePath.emplace_back(
174-
Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap));
182+
Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap),
183+
UserEntryIdx);
175184
return true;
176185
}
177186
}
@@ -471,7 +480,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
471480
/// RemoveDuplicates - If there are duplicate directory entries in the specified
472481
/// search list, remove the later (dead) ones. Returns the number of non-system
473482
/// headers removed, which is used to update NumAngled.
474-
static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
483+
static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList,
475484
unsigned First, bool Verbose) {
476485
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
477486
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
@@ -480,7 +489,7 @@ static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
480489
for (unsigned i = First; i != SearchList.size(); ++i) {
481490
unsigned DirToRemove = i;
482491

483-
const DirectoryLookup &CurEntry = SearchList[i];
492+
const DirectoryLookup &CurEntry = SearchList[i].Lookup;
484493

485494
if (CurEntry.isNormalDir()) {
486495
// If this isn't the first time we've seen this dir, remove it.
@@ -510,7 +519,7 @@ static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
510519
for (FirstDir = First;; ++FirstDir) {
511520
assert(FirstDir != i && "Didn't find dupe?");
512521

513-
const DirectoryLookup &SearchEntry = SearchList[FirstDir];
522+
const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup;
514523

515524
// If these are different lookup types, then they can't be the dupe.
516525
if (SearchEntry.getLookupType() != CurEntry.getLookupType())
@@ -532,7 +541,7 @@ static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
532541

533542
// If the first dir in the search path is a non-system dir, zap it
534543
// instead of the system one.
535-
if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User)
544+
if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User)
536545
DirToRemove = FirstDir;
537546
}
538547

@@ -554,24 +563,45 @@ static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
554563
return NonSystemRemoved;
555564
}
556565

566+
/// Extract DirectoryLookups from DirectoryLookupInfos.
567+
static std::vector<DirectoryLookup>
568+
extractLookups(const std::vector<DirectoryLookupInfo> &Infos) {
569+
std::vector<DirectoryLookup> Lookups;
570+
Lookups.reserve(Infos.size());
571+
llvm::transform(Infos, std::back_inserter(Lookups),
572+
[](const DirectoryLookupInfo &Info) { return Info.Lookup; });
573+
return Lookups;
574+
}
575+
576+
/// Collect the mapping between indices of DirectoryLookups and UserEntries.
577+
static llvm::DenseMap<unsigned, unsigned>
578+
mapToUserEntries(const std::vector<DirectoryLookupInfo> &Infos) {
579+
llvm::DenseMap<unsigned, unsigned> LookupsToUserEntries;
580+
for (unsigned I = 0, E = Infos.size(); I < E; ++I) {
581+
// Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry.
582+
if (Infos[I].UserEntryIdx)
583+
LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx});
584+
}
585+
return LookupsToUserEntries;
586+
}
557587

558588
void InitHeaderSearch::Realize(const LangOptions &Lang) {
559589
// Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
560-
std::vector<DirectoryLookup> SearchList;
590+
std::vector<DirectoryLookupInfo> SearchList;
561591
SearchList.reserve(IncludePath.size());
562592

563593
// Quoted arguments go first.
564594
for (auto &Include : IncludePath)
565595
if (Include.Group == Quoted)
566-
SearchList.push_back(Include.Lookup);
596+
SearchList.push_back(Include);
567597

568598
// Deduplicate and remember index.
569599
RemoveDuplicates(SearchList, 0, Verbose);
570600
unsigned NumQuoted = SearchList.size();
571601

572602
for (auto &Include : IncludePath)
573603
if (Include.Group == Angled || Include.Group == IndexHeaderMap)
574-
SearchList.push_back(Include.Lookup);
604+
SearchList.push_back(Include);
575605

576606
RemoveDuplicates(SearchList, NumQuoted, Verbose);
577607
unsigned NumAngled = SearchList.size();
@@ -583,11 +613,11 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
583613
Include.Group == CXXSystem) ||
584614
(Lang.ObjC && !Lang.CPlusPlus && Include.Group == ObjCSystem) ||
585615
(Lang.ObjC && Lang.CPlusPlus && Include.Group == ObjCXXSystem))
586-
SearchList.push_back(Include.Lookup);
616+
SearchList.push_back(Include);
587617

588618
for (auto &Include : IncludePath)
589619
if (Include.Group == After)
590-
SearchList.push_back(Include.Lookup);
620+
SearchList.push_back(Include);
591621

592622
// Remove duplicates across both the Angled and System directories. GCC does
593623
// this and failing to remove duplicates across these two groups breaks
@@ -596,7 +626,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
596626
NumAngled -= NonSystemRemoved;
597627

598628
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
599-
Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir);
629+
Headers.SetSearchPaths(extractLookups(SearchList), NumQuoted, NumAngled,
630+
DontSearchCurDir, mapToUserEntries(SearchList));
600631

601632
Headers.SetSystemHeaderPrefixes(SystemHeaderPrefixes);
602633

@@ -606,14 +637,14 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
606637
for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
607638
if (i == NumQuoted)
608639
llvm::errs() << "#include <...> search starts here:\n";
609-
StringRef Name = SearchList[i].getName();
640+
StringRef Name = SearchList[i].Lookup.getName();
610641
const char *Suffix;
611-
if (SearchList[i].isNormalDir())
642+
if (SearchList[i].Lookup.isNormalDir())
612643
Suffix = "";
613-
else if (SearchList[i].isFramework())
644+
else if (SearchList[i].Lookup.isFramework())
614645
Suffix = " (framework directory)";
615646
else {
616-
assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
647+
assert(SearchList[i].Lookup.isHeaderMap() && "Unknown DirectoryLookup");
617648
Suffix = " (headermap)";
618649
}
619650
llvm::errs() << " " << Name << Suffix << "\n";
@@ -632,9 +663,9 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
632663
for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
633664
const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
634665
if (E.IgnoreSysRoot) {
635-
Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework);
666+
Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework, i);
636667
} else {
637-
Init.AddPath(E.Path, E.Group, E.IsFramework);
668+
Init.AddPath(E.Path, E.Group, E.IsFramework, i);
638669
}
639670
}
640671

clang/lib/Lex/HeaderMap.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,6 @@ LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
194194
}
195195
}
196196

197-
/// LookupFile - Check to see if the specified relative filename is located in
198-
/// this HeaderMap. If so, open it and return its FileEntry.
199-
Optional<FileEntryRef> HeaderMap::LookupFile(StringRef Filename,
200-
FileManager &FM) const {
201-
202-
SmallString<1024> Path;
203-
StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
204-
if (Dest.empty())
205-
return None;
206-
207-
return FM.getOptionalFileRef(Dest);
208-
}
209-
210197
StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
211198
SmallVectorImpl<char> &DestPath) const {
212199
const HMapHeader &Hdr = getHeader();

0 commit comments

Comments
 (0)