forked from OSchip/llvm-project
Introduce a DirectoryEntryRef that stores both a reference and an
accessed name to the directory entry This commit introduces a parallel API that returns a DirectoryEntryRef to the FileManager, similar to the parallel FileEntryRef API. All uses will have to be update in follow-up patches. The immediate use of the new API in this patch fixes the issue where a file manager was reused in clang-scan-deps, but reported an different file path whenever a framework lookup was done through a symlink. Differential Revision: https://reviews.llvm.org/D67026 llvm-svn: 370562
This commit is contained in:
parent
09490012af
commit
0377ca641c
|
@ -45,12 +45,31 @@ class FileSystemStatCache;
|
|||
class DirectoryEntry {
|
||||
friend class FileManager;
|
||||
|
||||
// FIXME: We should not be storing a directory entry name here.
|
||||
StringRef Name; // Name of the directory.
|
||||
|
||||
public:
|
||||
StringRef getName() const { return Name; }
|
||||
};
|
||||
|
||||
/// A reference to a \c DirectoryEntry that includes the name of the directory
|
||||
/// as it was accessed by the FileManager's client.
|
||||
class DirectoryEntryRef {
|
||||
public:
|
||||
const DirectoryEntry &getDirEntry() const { return *Entry->getValue(); }
|
||||
|
||||
StringRef getName() const { return Entry->getKey(); }
|
||||
|
||||
private:
|
||||
friend class FileManager;
|
||||
|
||||
DirectoryEntryRef(
|
||||
llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry)
|
||||
: Entry(Entry) {}
|
||||
|
||||
const llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry;
|
||||
};
|
||||
|
||||
/// Cached information about one file (either on disk
|
||||
/// or in the virtual file system).
|
||||
///
|
||||
|
@ -259,6 +278,29 @@ public:
|
|||
/// virtual).
|
||||
///
|
||||
/// This returns a \c std::error_code if there was an error reading the
|
||||
/// directory. On success, returns the reference to the directory entry
|
||||
/// together with the exact path that was used to access a file by a
|
||||
/// particular call to getDirectoryRef.
|
||||
///
|
||||
/// \param CacheFailure If true and the file does not exist, we'll cache
|
||||
/// the failure to find this file.
|
||||
llvm::Expected<DirectoryEntryRef> getDirectoryRef(StringRef DirName,
|
||||
bool CacheFailure = true);
|
||||
|
||||
/// Get a \c DirectoryEntryRef if it exists, without doing anything on error.
|
||||
llvm::Optional<DirectoryEntryRef>
|
||||
getOptionalDirectoryRef(StringRef DirName, bool CacheFailure = true) {
|
||||
return llvm::expectedToOptional(getDirectoryRef(DirName, CacheFailure));
|
||||
}
|
||||
|
||||
/// Lookup, cache, and verify the specified directory (real or
|
||||
/// virtual).
|
||||
///
|
||||
/// This function is deprecated and will be removed at some point in the
|
||||
/// future, new clients should use
|
||||
/// \c getDirectoryRef.
|
||||
///
|
||||
/// This returns a \c std::error_code if there was an error reading the
|
||||
/// directory. If there is no error, the DirectoryEntry is guaranteed to be
|
||||
/// non-NULL.
|
||||
///
|
||||
|
|
|
@ -36,14 +36,17 @@ public:
|
|||
LT_HeaderMap
|
||||
};
|
||||
private:
|
||||
union { // This union is discriminated by isHeaderMap.
|
||||
union DLU { // This union is discriminated by isHeaderMap.
|
||||
/// Dir - This is the actual directory that we're referring to for a normal
|
||||
/// directory or a framework.
|
||||
const DirectoryEntry *Dir;
|
||||
DirectoryEntryRef Dir;
|
||||
|
||||
/// Map - This is the HeaderMap if this is a headermap lookup.
|
||||
///
|
||||
const HeaderMap *Map;
|
||||
|
||||
DLU(DirectoryEntryRef Dir) : Dir(Dir) {}
|
||||
DLU(const HeaderMap *Map) : Map(Map) {}
|
||||
} u;
|
||||
|
||||
/// DirCharacteristic - The type of directory this is: this is an instance of
|
||||
|
@ -62,24 +65,18 @@ private:
|
|||
unsigned SearchedAllModuleMaps : 1;
|
||||
|
||||
public:
|
||||
/// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
|
||||
/// 'dir'.
|
||||
DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT,
|
||||
/// This ctor *does not take ownership* of 'Dir'.
|
||||
DirectoryLookup(DirectoryEntryRef Dir, SrcMgr::CharacteristicKind DT,
|
||||
bool isFramework)
|
||||
: DirCharacteristic(DT),
|
||||
LookupType(isFramework ? LT_Framework : LT_NormalDir),
|
||||
IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {
|
||||
u.Dir = dir;
|
||||
}
|
||||
: u(Dir), DirCharacteristic(DT),
|
||||
LookupType(isFramework ? LT_Framework : LT_NormalDir),
|
||||
IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {}
|
||||
|
||||
/// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
|
||||
/// 'map'.
|
||||
DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT,
|
||||
/// This ctor *does not take ownership* of 'Map'.
|
||||
DirectoryLookup(const HeaderMap *Map, SrcMgr::CharacteristicKind DT,
|
||||
bool isIndexHeaderMap)
|
||||
: DirCharacteristic(DT), LookupType(LT_HeaderMap),
|
||||
IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {
|
||||
u.Map = map;
|
||||
}
|
||||
: u(Map), DirCharacteristic(DT), LookupType(LT_HeaderMap),
|
||||
IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {}
|
||||
|
||||
/// getLookupType - Return the kind of directory lookup that this is: either a
|
||||
/// normal directory, a framework path, or a HeaderMap.
|
||||
|
@ -92,13 +89,17 @@ public:
|
|||
/// getDir - Return the directory that this entry refers to.
|
||||
///
|
||||
const DirectoryEntry *getDir() const {
|
||||
return isNormalDir() ? u.Dir : nullptr;
|
||||
return isNormalDir() ? &u.Dir.getDirEntry() : nullptr;
|
||||
}
|
||||
|
||||
/// getFrameworkDir - Return the directory that this framework refers to.
|
||||
///
|
||||
const DirectoryEntry *getFrameworkDir() const {
|
||||
return isFramework() ? u.Dir : nullptr;
|
||||
return isFramework() ? &u.Dir.getDirEntry() : nullptr;
|
||||
}
|
||||
|
||||
Optional<DirectoryEntryRef> getFrameworkDirRef() const {
|
||||
return isFramework() ? Optional<DirectoryEntryRef>(u.Dir) : None;
|
||||
}
|
||||
|
||||
/// getHeaderMap - Return the directory that this entry refers to.
|
||||
|
|
|
@ -107,16 +107,8 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
|
|||
addAncestorsAsVirtualDirs(DirName);
|
||||
}
|
||||
|
||||
/// Converts a llvm::ErrorOr<T &> to an llvm::ErrorOr<T *> by promoting
|
||||
/// the address of the inner reference to a pointer or by propagating the error.
|
||||
template <typename T>
|
||||
static llvm::ErrorOr<T *> promoteInnerReference(llvm::ErrorOr<T &> value) {
|
||||
if (value) return &*value;
|
||||
return value.getError();
|
||||
}
|
||||
|
||||
llvm::ErrorOr<const DirectoryEntry *>
|
||||
FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
|
||||
llvm::Expected<DirectoryEntryRef>
|
||||
FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
|
||||
// stat doesn't like trailing separators except for root directory.
|
||||
// At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
|
||||
// (though it can strip '\\')
|
||||
|
@ -141,8 +133,11 @@ FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
|
|||
// contains both virtual and real directories.
|
||||
auto SeenDirInsertResult =
|
||||
SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory});
|
||||
if (!SeenDirInsertResult.second)
|
||||
return promoteInnerReference(SeenDirInsertResult.first->second);
|
||||
if (!SeenDirInsertResult.second) {
|
||||
if (SeenDirInsertResult.first->second)
|
||||
return DirectoryEntryRef(&*SeenDirInsertResult.first);
|
||||
return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError());
|
||||
}
|
||||
|
||||
// We've not seen this before. Fill it in.
|
||||
++NumDirCacheMisses;
|
||||
|
@ -163,7 +158,7 @@ FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
|
|||
NamedDirEnt.second = statError;
|
||||
else
|
||||
SeenDirEntries.erase(DirName);
|
||||
return statError;
|
||||
return llvm::errorCodeToError(statError);
|
||||
}
|
||||
|
||||
// It exists. See if we have already opened a directory with the
|
||||
|
@ -179,7 +174,15 @@ FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
|
|||
UDE.Name = InterndDirName;
|
||||
}
|
||||
|
||||
return &UDE;
|
||||
return DirectoryEntryRef(&NamedDirEnt);
|
||||
}
|
||||
|
||||
llvm::ErrorOr<const DirectoryEntry *>
|
||||
FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
|
||||
auto Result = getDirectoryRef(DirName, CacheFailure);
|
||||
if (Result)
|
||||
return &Result->getDirEntry();
|
||||
return llvm::errorToErrorCode(Result.takeError());
|
||||
}
|
||||
|
||||
llvm::ErrorOr<const FileEntry *>
|
||||
|
|
|
@ -148,7 +148,7 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
|
|||
}
|
||||
|
||||
// If the directory exists, add it.
|
||||
if (auto DE = FM.getDirectory(MappedPathStr)) {
|
||||
if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) {
|
||||
IncludePath.push_back(
|
||||
std::make_pair(Group, DirectoryLookup(*DE, Type, isFramework)));
|
||||
return true;
|
||||
|
|
|
@ -296,6 +296,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
|
|||
/// getName - Return the directory or filename corresponding to this lookup
|
||||
/// object.
|
||||
StringRef DirectoryLookup::getName() const {
|
||||
// FIXME: Use the name from \c DirectoryEntryRef.
|
||||
if (isNormalDir())
|
||||
return getDir()->getName();
|
||||
if (isFramework())
|
||||
|
@ -496,7 +497,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
|
|||
|
||||
// FrameworkName = "/System/Library/Frameworks/"
|
||||
SmallString<1024> FrameworkName;
|
||||
FrameworkName += getFrameworkDir()->getName();
|
||||
FrameworkName += getFrameworkDirRef()->getName();
|
||||
if (FrameworkName.empty() || FrameworkName.back() != '/')
|
||||
FrameworkName.push_back('/');
|
||||
|
||||
|
|
|
@ -1695,7 +1695,7 @@ Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
|
|||
// Give the clients a chance to recover.
|
||||
SmallString<128> RecoveryPath;
|
||||
if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
|
||||
if (auto DE = FileMgr.getDirectory(RecoveryPath)) {
|
||||
if (auto DE = FileMgr.getOptionalDirectoryRef(RecoveryPath)) {
|
||||
// Add the recovery path to the list of search paths.
|
||||
DirectoryLookup DL(*DE, SrcMgr::C_User, false);
|
||||
HeaderInfo.AddSearchPath(DL, isAngled);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
{
|
||||
"directory": "DIR",
|
||||
"command": "clang -E DIR/subframework_header_dir_symlink2.m -FInputs/frameworks_symlink -iframework Inputs/frameworks",
|
||||
"command": "clang -E DIR/subframework_header_dir_symlink2.m -FInputs/frameworks -iframework Inputs/frameworks_symlink",
|
||||
"file": "DIR/subframework_header_dir_symlink2.m"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/subframework_header_dir_symlink_cdb.json > %t.cdb
|
||||
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=0 | \
|
||||
// RUN: FileCheck %s
|
||||
// FIXME: Make this work when the filemanager is reused:
|
||||
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=1 | \
|
||||
// RUN: not FileCheck %s
|
||||
// RUN: FileCheck %s
|
||||
|
||||
#ifndef EMPTY
|
||||
#include "Framework/Framework.h"
|
||||
|
|
|
@ -39,7 +39,7 @@ protected:
|
|||
void addSearchDir(llvm::StringRef Dir) {
|
||||
VFS->addFile(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/None,
|
||||
/*Group=*/None, llvm::sys::fs::file_type::directory_file);
|
||||
auto DE = FileMgr.getDirectory(Dir);
|
||||
auto DE = FileMgr.getOptionalDirectoryRef(Dir);
|
||||
assert(DE);
|
||||
auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);
|
||||
Search.AddSearchPath(DL, /*isAngled=*/false);
|
||||
|
|
|
@ -145,7 +145,7 @@ protected:
|
|||
|
||||
// Add header's parent path to search path.
|
||||
StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
|
||||
auto DE = FileMgr.getDirectory(SearchPath);
|
||||
auto DE = FileMgr.getOptionalDirectoryRef(SearchPath);
|
||||
DirectoryLookup DL(*DE, SrcMgr::C_User, false);
|
||||
HeaderInfo.AddSearchPath(DL, IsSystemHeader);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue