From 75fa9eddae9bcc85aa4ed9125be1e5823a02d73e Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Fri, 14 Feb 2014 14:58:28 +0000 Subject: [PATCH] If the headermap maps the filename to a framework include ("Foo.h" -> "Foo/Foo.h"), continue header lookup using the framework include as filename. This allows us to conveniently treat #import "Foo.h" as an implicit module import if we can resolve "Foo/Foo.h" as such. rdar://16042979 llvm-svn: 201419 --- clang/include/clang/Lex/DirectoryLookup.h | 9 +++-- clang/include/clang/Lex/HeaderMap.h | 5 +++ clang/lib/Lex/HeaderMap.cpp | 25 +++++++++---- clang/lib/Lex/HeaderSearch.cpp | 33 +++++++++++++++--- .../headermap-rel/Foo.framework/Headers/Foo.h | 2 ++ .../test/Preprocessor/headermap-rel/foo.hmap | Bin 0 -> 804 bytes .../headermap-rel/headermap-rel.c | 10 ++++++ 7 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 clang/test/Preprocessor/headermap-rel/Foo.framework/Headers/Foo.h create mode 100644 clang/test/Preprocessor/headermap-rel/foo.hmap create mode 100644 clang/test/Preprocessor/headermap-rel/headermap-rel.c diff --git a/clang/include/clang/Lex/DirectoryLookup.h b/clang/include/clang/Lex/DirectoryLookup.h index dff3e8c3608d..89939c84cacf 100644 --- a/clang/include/clang/Lex/DirectoryLookup.h +++ b/clang/include/clang/Lex/DirectoryLookup.h @@ -161,11 +161,16 @@ public: /// \param [out] InUserSpecifiedSystemFramework If the file is found, /// set to true if the file is located in a framework that has been /// user-specified to be treated as a system framework. - const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS, + /// + /// \param [out] MappedName if this is a headermap which maps the filename to + /// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this + /// vector and point Filename to it. + const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, ModuleMap::KnownHeader *SuggestedModule, - bool &InUserSpecifiedSystemFramework) const; + bool &InUserSpecifiedSystemFramework, + SmallVectorImpl &MappedName) const; private: const FileEntry *DoFrameworkLookup( diff --git a/clang/include/clang/Lex/HeaderMap.h b/clang/include/clang/Lex/HeaderMap.h index 8473a6a4e752..8e78b5ac9884 100644 --- a/clang/include/clang/Lex/HeaderMap.h +++ b/clang/include/clang/Lex/HeaderMap.h @@ -55,6 +55,11 @@ public: /// "../../file.h". const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const; + /// If the specified relative filename is located in this HeaderMap return + /// the filename it is mapped to, otherwise return an empty StringRef. + StringRef lookupFilename(StringRef Filename, + SmallVectorImpl &DestPath) const; + /// getFileName - Return the filename of the headermap. const char *getFileName() const; diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp index 478462c3c20d..0432e09c0aad 100644 --- a/clang/lib/Lex/HeaderMap.cpp +++ b/clang/lib/Lex/HeaderMap.cpp @@ -201,18 +201,29 @@ void HeaderMap::dump() const { /// this HeaderMap. If so, open it and return its FileEntry. const FileEntry *HeaderMap::LookupFile( StringRef Filename, FileManager &FM) const { + + SmallString<1024> Path; + StringRef Dest = lookupFilename(Filename, Path); + if (Dest.empty()) + return 0; + + return FM.getFile(Dest); +} + +StringRef HeaderMap::lookupFilename(StringRef Filename, + SmallVectorImpl &DestPath) const { const HMapHeader &Hdr = getHeader(); unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); // If the number of buckets is not a power of two, the headermap is corrupt. // Don't probe infinitely. if (NumBuckets & (NumBuckets-1)) - return 0; + return StringRef(); // Linearly probe the hash table. for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) { HMapBucket B = getBucket(Bucket & (NumBuckets-1)); - if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss. + if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss. // See if the key matches. If not, probe on. if (!Filename.equals_lower(getString(B.Key))) @@ -220,9 +231,11 @@ const FileEntry *HeaderMap::LookupFile( // If so, we have a match in the hash table. Construct the destination // path. - SmallString<1024> DestPath; - DestPath += getString(B.Prefix); - DestPath += getString(B.Suffix); - return FM.getFile(DestPath.str()); + StringRef Prefix = getString(B.Prefix); + StringRef Suffix = getString(B.Suffix); + DestPath.clear(); + DestPath.append(Prefix.begin(), Prefix.end()); + DestPath.append(Suffix.begin(), Suffix.end()); + return StringRef(DestPath.begin(), DestPath.size()); } } diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 868c33bcb18d..b9dd22d64879 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -223,12 +223,13 @@ const char *DirectoryLookup::getName() const { /// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. const FileEntry *DirectoryLookup::LookupFile( - StringRef Filename, + StringRef &Filename, HeaderSearch &HS, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, ModuleMap::KnownHeader *SuggestedModule, - bool &InUserSpecifiedSystemFramework) const { + bool &InUserSpecifiedSystemFramework, + SmallVectorImpl &MappedName) const { InUserSpecifiedSystemFramework = false; SmallString<1024> TmpDir; @@ -271,8 +272,27 @@ const FileEntry *DirectoryLookup::LookupFile( SuggestedModule, InUserSpecifiedSystemFramework); assert(isHeaderMap() && "Unknown directory lookup"); - const FileEntry * const Result = getHeaderMap()->LookupFile( - Filename, HS.getFileMgr()); + const HeaderMap *HM = getHeaderMap(); + SmallString<1024> Path; + StringRef Dest = HM->lookupFilename(Filename, Path); + if (Dest.empty()) + return 0; + + const FileEntry *Result; + + // Check if the headermap maps the filename to a framework include + // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the + // framework include. + if (llvm::sys::path::is_relative(Dest)) { + MappedName.clear(); + MappedName.append(Dest.begin(), Dest.end()); + Filename = StringRef(MappedName.begin(), MappedName.size()); + Result = HM->LookupFile(Filename, HS.getFileMgr()); + + } else { + Result = HS.getFileMgr().getFile(Dest); + } + if (Result) { if (SearchPath != NULL) { StringRef SearchPathRef(getName()); @@ -620,12 +640,15 @@ const FileEntry *HeaderSearch::LookupFile( CacheLookup.first = i+1; } + SmallString<64> MappedName; + // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { bool InUserSpecifiedSystemFramework = false; const FileEntry *FE = SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath, - SuggestedModule, InUserSpecifiedSystemFramework); + SuggestedModule, InUserSpecifiedSystemFramework, + MappedName); if (!FE) continue; CurDir = &SearchDirs[i]; diff --git a/clang/test/Preprocessor/headermap-rel/Foo.framework/Headers/Foo.h b/clang/test/Preprocessor/headermap-rel/Foo.framework/Headers/Foo.h new file mode 100644 index 000000000000..04ffb5a488f9 --- /dev/null +++ b/clang/test/Preprocessor/headermap-rel/Foo.framework/Headers/Foo.h @@ -0,0 +1,2 @@ + +Foo.h is parsed diff --git a/clang/test/Preprocessor/headermap-rel/foo.hmap b/clang/test/Preprocessor/headermap-rel/foo.hmap new file mode 100644 index 0000000000000000000000000000000000000000..783c64e67bb80a38f23845ed54fac43e2dc101a4 GIT binary patch literal 804 ycmXR&%*|kAU|^77W?%r(4nWKa#KRSU{KyW(AbJ#xh5*hGaLdov%U}SK`V0V(7zHB$ literal 0 HcmV?d00001 diff --git a/clang/test/Preprocessor/headermap-rel/headermap-rel.c b/clang/test/Preprocessor/headermap-rel/headermap-rel.c new file mode 100644 index 000000000000..361918d99fde --- /dev/null +++ b/clang/test/Preprocessor/headermap-rel/headermap-rel.c @@ -0,0 +1,10 @@ + +// This uses a headermap with this entry: +// Foo.h -> Foo/Foo.h + +// RUN: %clang_cc1 -E %s -o %t.i -I %S/foo.hmap -F %S +// RUN: FileCheck %s -input-file %t.i + +// CHECK: Foo.h is parsed + +#include "Foo.h"