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
This commit is contained in:
Argyrios Kyrtzidis 2014-02-14 14:58:28 +00:00
parent 96430645eb
commit 75fa9eddae
7 changed files with 71 additions and 13 deletions

View File

@ -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<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const;
bool &InUserSpecifiedSystemFramework,
SmallVectorImpl<char> &MappedName) const;
private:
const FileEntry *DoFrameworkLookup(

View File

@ -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<char> &DestPath) const;
/// getFileName - Return the filename of the headermap.
const char *getFileName() const;

View File

@ -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<char> &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());
}
}

View File

@ -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<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule,
bool &InUserSpecifiedSystemFramework) const {
bool &InUserSpecifiedSystemFramework,
SmallVectorImpl<char> &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];

View File

@ -0,0 +1,2 @@
Foo.h is parsed

Binary file not shown.

View File

@ -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"