[clang] Track how headers get included generally during lookup time

tapi & clang-extractapi both attempt to construct then check against
how a header was included to determine api information when working
against multiple search paths, headermap, and vfsoverlay mechanisms.
Validating this against what the preprocessor sees during lookup time
makes this check more reliable.

Reviewed By: zixuw, jansvoboda11

Differential Revision: https://reviews.llvm.org/D124638
This commit is contained in:
Cyndy Ishida 2022-05-04 07:38:20 -07:00
parent 94d36fdbd7
commit b6c67c3c67
3 changed files with 24 additions and 1 deletions

View File

@ -20,6 +20,7 @@
#include "clang/Lex/ModuleMap.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@ -314,6 +315,9 @@ class HeaderSearch {
/// whether they were valid or not.
llvm::DenseMap<const FileEntry *, bool> LoadedModuleMaps;
// A map of discovered headers with their associated include file name.
llvm::DenseMap<const FileEntry *, llvm::SmallString<64>> IncludeNames;
/// Uniqued set of framework names, which is used to track which
/// headers were included as framework headers.
llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
@ -823,6 +827,13 @@ public:
/// Retrieve a uniqued framework name.
StringRef getUniqueFrameworkName(StringRef Framework);
/// Retrieve the include name for the header.
///
/// \param File The entry for a given header.
/// \returns The name of how the file was included when the header's location
/// was resolved.
StringRef getIncludeNameForHeader(const FileEntry *File) const;
/// Suggest a path by which the specified file could be found, for use in
/// diagnostics to suggest a #include. Returned path will only contain forward
/// slashes as separators. MainFile is the absolute path of the file that we

View File

@ -1030,8 +1030,11 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
CurDir = It;
const auto FE = &File->getFileEntry();
IncludeNames[FE] = Filename;
// This file is a system header or C++ unfriendly if the dir is.
HeaderFileInfo &HFI = getFileInfo(&File->getFileEntry());
HeaderFileInfo &HFI = getFileInfo(FE);
HFI.DirInfo = CurDir->getDirCharacteristic();
// If the directory characteristic is User but this framework was
@ -1460,6 +1463,13 @@ StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
return FrameworkNames.insert(Framework).first->first();
}
StringRef HeaderSearch::getIncludeNameForHeader(const FileEntry *File) const {
auto It = IncludeNames.find(File);
if (It == IncludeNames.end())
return {};
return It->second;
}
bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root,
bool IsSystem) {

View File

@ -207,6 +207,7 @@ TEST_F(HeaderSearchTest, HeaderFrameworkLookup) {
EXPECT_TRUE(FI);
EXPECT_TRUE(FI->IsValid);
EXPECT_EQ(FI->Framework.str(), "Foo");
EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
}
// Helper struct with null terminator character to make MemoryBuffer happy.
@ -275,6 +276,7 @@ TEST_F(HeaderSearchTest, HeaderMapFrameworkLookup) {
EXPECT_TRUE(FI);
EXPECT_TRUE(FI->IsValid);
EXPECT_EQ(FI->Framework.str(), "Foo");
EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
}
} // namespace