diff options
Diffstat (limited to 'lib/Lex/HeaderSearch.cpp')
-rw-r--r-- | lib/Lex/HeaderSearch.cpp | 208 |
1 files changed, 176 insertions, 32 deletions
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 86ab9564a235..931145a8d655 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Capacity.h" #include <cstdio> using namespace clang; @@ -97,6 +98,60 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { return 0; } +const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName, + std::string *ModuleFileName, + std::string *UmbrellaHeader) { + // If we don't have a module cache path, we can't do anything. + if (ModuleCachePath.empty()) { + if (ModuleFileName) + ModuleFileName->clear(); + return 0; + } + + // Try to find the module path. + llvm::SmallString<256> FileName(ModuleCachePath); + llvm::sys::path::append(FileName, ModuleName + ".pcm"); + if (ModuleFileName) + *ModuleFileName = FileName.str(); + + if (const FileEntry *ModuleFile + = getFileMgr().getFile(FileName, /*OpenFile=*/false, + /*CacheFailure=*/false)) + return ModuleFile; + + // We didn't find the module. If we're not supposed to look for an + // umbrella header, this is the end of the road. + if (!UmbrellaHeader) + return 0; + + // Look in each of the framework directories for an umbrella header with + // the same name as the module. + // FIXME: We need a way for non-frameworks to provide umbrella headers. + llvm::SmallString<128> UmbrellaHeaderName; + UmbrellaHeaderName = ModuleName; + UmbrellaHeaderName += '/'; + UmbrellaHeaderName += ModuleName; + UmbrellaHeaderName += ".h"; + for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) { + // Skip non-framework include paths + if (!SearchDirs[Idx].isFramework()) + continue; + + // Look for the umbrella header in this directory. + if (const FileEntry *HeaderFile + = SearchDirs[Idx].LookupFile(UmbrellaHeaderName, *this, 0, 0, + StringRef(), 0)) { + *UmbrellaHeader = HeaderFile->getName(); + return 0; + } + } + + // We did not find an umbrella header. Clear out the UmbrellaHeader pointee + // so our caller knows that we failed. + UmbrellaHeader->clear(); + return 0; +} + //===----------------------------------------------------------------------===// // File lookup within a DirectoryLookup scope //===----------------------------------------------------------------------===// @@ -116,17 +171,19 @@ 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( - llvm::StringRef Filename, + StringRef Filename, HeaderSearch &HS, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) const { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef BuildingModule, + StringRef *SuggestedModule) const { llvm::SmallString<1024> TmpDir; if (isNormalDir()) { // Concatenate the requested file onto the directory. TmpDir = getDir()->getName(); llvm::sys::path::append(TmpDir, Filename); if (SearchPath != NULL) { - llvm::StringRef SearchPathRef(getDir()->getName()); + StringRef SearchPathRef(getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } @@ -138,14 +195,15 @@ const FileEntry *DirectoryLookup::LookupFile( } if (isFramework()) - return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath); + return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath, + BuildingModule, SuggestedModule); assert(isHeaderMap() && "Unknown directory lookup"); const FileEntry * const Result = getHeaderMap()->LookupFile( Filename, HS.getFileMgr()); if (Result) { if (SearchPath != NULL) { - llvm::StringRef SearchPathRef(getName()); + StringRef SearchPathRef(getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } @@ -161,15 +219,18 @@ const FileEntry *DirectoryLookup::LookupFile( /// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. const FileEntry *DirectoryLookup::DoFrameworkLookup( - llvm::StringRef Filename, + StringRef Filename, HeaderSearch &HS, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) const { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef BuildingModule, + StringRef *SuggestedModule) const +{ FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. size_t SlashPos = Filename.find('/'); - if (SlashPos == llvm::StringRef::npos) return 0; + if (SlashPos == StringRef::npos) return 0; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answer are yes/no and unknown. @@ -226,9 +287,16 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); } + /// Determine whether this is the module we're building or not. + bool AutomaticImport = SuggestedModule && + (BuildingModule != StringRef(Filename.begin(), SlashPos)) && + !Filename.substr(SlashPos + 1).startswith(".."); + FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), - /*openFile=*/true)) { + /*openFile=*/!AutomaticImport)) { + if (AutomaticImport) + *SuggestedModule = StringRef(Filename.begin(), SlashPos); return FE; } @@ -240,7 +308,11 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( SearchPath->insert(SearchPath->begin()+OrigSize, Private, Private+strlen(Private)); - return FileMgr.getFile(FrameworkName.str(), /*openFile=*/true); + const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), + /*openFile=*/!AutomaticImport); + if (FE && AutomaticImport) + *SuggestedModule = StringRef(Filename.begin(), SlashPos); + return FE; } @@ -255,13 +327,18 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( /// non-null, indicates where the #including file is, in case a relative search /// is needed. const FileEntry *HeaderSearch::LookupFile( - llvm::StringRef Filename, + StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, const FileEntry *CurFileEnt, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + StringRef *SuggestedModule) +{ + if (SuggestedModule) + *SuggestedModule = StringRef(); + // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { CurDir = 0; @@ -279,7 +356,7 @@ const FileEntry *HeaderSearch::LookupFile( return FileMgr.getFile(Filename, /*openFile=*/true); } - // Step #0, unless disabled, check to see if the file is in the #includer's + // Unless disabled, check to see if the file is in the #includer's // directory. This has to be based on CurFileEnt, not CurDir, because // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h". @@ -301,7 +378,7 @@ const FileEntry *HeaderSearch::LookupFile( unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo; getFileInfo(FE).DirInfo = DirInfo; if (SearchPath != NULL) { - llvm::StringRef SearchPathRef(CurFileEnt->getDir()->getName()); + StringRef SearchPathRef(CurFileEnt->getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } @@ -346,19 +423,56 @@ const FileEntry *HeaderSearch::LookupFile( // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { const FileEntry *FE = - SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath); + SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath, + BuildingModule, SuggestedModule); if (!FE) continue; CurDir = &SearchDirs[i]; // This file is a system header or C++ unfriendly if the dir is. - getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic(); - + HeaderFileInfo &HFI = getFileInfo(FE); + HFI.DirInfo = CurDir->getDirCharacteristic(); + + // If this file is found in a header map and uses the framework style of + // includes, then this header is part of a framework we're building. + if (CurDir->isIndexHeaderMap()) { + size_t SlashPos = Filename.find('/'); + if (SlashPos != StringRef::npos) { + HFI.IndexHeaderMapHeader = 1; + HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), + SlashPos)); + } + } + // Remember this location for the next lookup we do. CacheLookup.second = i; return FE; } + // If we are including a file with a quoted include "foo.h" from inside + // a header in a framework that is currently being built, and we couldn't + // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where + // "Foo" is the name of the framework in which the including header was found. + if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) { + HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt); + if (IncludingHFI.IndexHeaderMapHeader) { + llvm::SmallString<128> ScratchFilename; + ScratchFilename += IncludingHFI.Framework; + ScratchFilename += '/'; + ScratchFilename += Filename; + + const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true, + FromDir, CurDir, CurFileEnt, + SearchPath, RelativePath, + SuggestedModule); + std::pair<unsigned, unsigned> &CacheLookup + = LookupFileCache.GetOrCreateValue(Filename).getValue(); + CacheLookup.second + = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second; + return Result; + } + } + // Otherwise, didn't find it. Remember we didn't find this. CacheLookup.second = SearchDirs.size(); return 0; @@ -370,15 +484,15 @@ const FileEntry *HeaderSearch::LookupFile( /// is a subframework within Carbon.framework. If so, return the FileEntry /// for the designated file, otherwise return null. const FileEntry *HeaderSearch:: -LookupSubframeworkHeader(llvm::StringRef Filename, +LookupSubframeworkHeader(StringRef Filename, const FileEntry *ContextFileEnt, - llvm::SmallVectorImpl<char> *SearchPath, - llvm::SmallVectorImpl<char> *RelativePath) { + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath) { assert(ContextFileEnt && "No context file?"); // Framework names must have a '/' in the filename. Find it. size_t SlashPos = Filename.find('/'); - if (SlashPos == llvm::StringRef::npos) return 0; + if (SlashPos == StringRef::npos) return 0; // Look up the base framework name of the ContextFileEnt. const char *ContextName = ContextFileEnt->getName(); @@ -466,7 +580,31 @@ LookupSubframeworkHeader(llvm::StringRef Filename, // File Info Management. //===----------------------------------------------------------------------===// +/// \brief Merge the header file info provided by \p OtherHFI into the current +/// header file info (\p HFI) +static void mergeHeaderFileInfo(HeaderFileInfo &HFI, + const HeaderFileInfo &OtherHFI) { + HFI.isImport |= OtherHFI.isImport; + HFI.isPragmaOnce |= OtherHFI.isPragmaOnce; + HFI.NumIncludes += OtherHFI.NumIncludes; + + if (!HFI.ControllingMacro && !HFI.ControllingMacroID) { + HFI.ControllingMacro = OtherHFI.ControllingMacro; + HFI.ControllingMacroID = OtherHFI.ControllingMacroID; + } + + if (OtherHFI.External) { + HFI.DirInfo = OtherHFI.DirInfo; + HFI.External = OtherHFI.External; + HFI.IndexHeaderMapHeader = OtherHFI.IndexHeaderMapHeader; + } + if (HFI.Framework.empty()) + HFI.Framework = OtherHFI.Framework; + + HFI.Resolved = true; +} + /// getFileInfo - Return the HeaderFileInfo structure for the specified /// FileEntry. HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { @@ -474,10 +612,8 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { FileInfo.resize(FE->getUID()+1); HeaderFileInfo &HFI = FileInfo[FE->getUID()]; - if (ExternalSource && !HFI.Resolved) { - HFI = ExternalSource->GetHeaderFileInfo(FE); - HFI.Resolved = true; - } + if (ExternalSource && !HFI.Resolved) + mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(FE)); return HFI; } @@ -488,10 +624,8 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) { // Resolve header file info from the external source, if needed. HeaderFileInfo &HFI = FileInfo[File->getUID()]; - if (ExternalSource && !HFI.Resolved) { - HFI = ExternalSource->GetHeaderFileInfo(File); - HFI.Resolved = true; - } + if (ExternalSource && !HFI.Resolved) + mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File)); return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID; } @@ -542,4 +676,14 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ return true; } +size_t HeaderSearch::getTotalMemory() const { + return SearchDirs.capacity() + + llvm::capacity_in_bytes(FileInfo) + + llvm::capacity_in_bytes(HeaderMaps) + + LookupFileCache.getAllocator().getTotalMemory() + + FrameworkMap.getAllocator().getTotalMemory(); +} +StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) { + return FrameworkNames.GetOrCreateValue(Framework).getKey(); +} |