#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
/// \see SeenDirEntries
llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries;
+ /// \brief The canonical names of directories.
+ llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames;
+
+ /// \brief Storage for canonical names that we have computed.
+ llvm::BumpPtrAllocator CanonicalNameStorage;
+
/// \brief Each FileEntry we create is assigned a unique ID #.
///
unsigned NextFileUID;
static void modifyFileEntry(FileEntry *File, off_t Size,
time_t ModificationTime);
+ /// \brief Retrieve the canonical name for a given directory.
+ ///
+ /// This is a very expensive operation, despite its results being cached,
+ /// and should only be used when the physical layout of the file system is
+ /// required, which is (almost) never.
+ StringRef getCanonicalName(const DirectoryEntry *Dir);
+
void PrintStats() const;
};
#define S_ISFIFO(x) (0)
#endif
#endif
+#if defined(LLVM_ON_UNIX)
+#if defined(__linux__)
+#include <linux/limits.h>
+#endif
+#endif
using namespace clang;
// FIXME: Enhance libsystem to support inode and other fields.
File->ModTime = ModificationTime;
}
+StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
+ // FIXME: use llvm::sys::fs::canonical() when it gets implemented
+#ifdef LLVM_ON_UNIX
+ llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
+ = CanonicalDirNames.find(Dir);
+ if (Known != CanonicalDirNames.end())
+ return Known->second;
+
+ StringRef CanonicalName(Dir->getName());
+ char CanonicalNameBuf[PATH_MAX];
+ if (realpath(Dir->getName(), CanonicalNameBuf)) {
+ unsigned Len = strlen(CanonicalNameBuf);
+ char *Mem = static_cast<char *>(CanonicalNameStorage.Allocate(Len, 1));
+ memcpy(Mem, CanonicalNameBuf, Len);
+ CanonicalName = StringRef(Mem, Len);
+ }
+
+ CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
+ return CanonicalName;
+#else
+ return StringRef(Dir->getName());
+#endif
+}
void FileManager::PrintStats() const {
llvm::errs() << "\n*** File Manager Stats:\n";
return Result;
}
+/// FIXME: HACK HACK HACK!
+static llvm::DenseMap<const DirectoryEntry *, const DirectoryEntry *>
+ TopFrameworkDirs;
+
/// \brief Given a framework directory, find the top-most framework directory.
///
/// \param FileMgr The file manager to use for directory lookups.
assert(llvm::sys::path::extension(DirName) == ".framework" &&
"Not a framework directory");
-#ifdef LLVM_ON_UNIX
// Note: as an egregious but useful hack we use the real path here, because
// frameworks moving between top-level frameworks to embedded frameworks tend
// to be symlinked, and we base the logical structure of modules on the
//
// Similar issues occur when a top-level framework has moved into an
// embedded framework.
- char RealDirName[PATH_MAX];
- if (realpath(DirName.str().c_str(), RealDirName))
- DirName = RealDirName;
-#endif
-
const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
+ DirName = FileMgr.getCanonicalName(TopFrameworkDir);
do {
// Get the parent directory name.
DirName = llvm::sys::path::parent_path(DirName);
const DirectoryEntry *Dir = File->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
-#ifdef LLVM_ON_UNIX
+
// Note: as an egregious but useful hack we use the real path here, because
// frameworks moving from top-level frameworks to embedded frameworks tend
// to be symlinked from the top-level location to the embedded location,
// and we need to resolve lookups as if we had found the embedded location.
- char RealDirName[PATH_MAX];
- StringRef DirName;
- if (realpath(Dir->getName(), RealDirName))
- DirName = RealDirName;
- else
- DirName = Dir->getName();
-#else
- StringRef DirName = Dir->getName();
-#endif
+ StringRef DirName = SourceMgr->getFileManager().getCanonicalName(Dir);
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
// a framework module, do so.
if (!Parent) {
// Determine whether we're allowed to infer a module map.
- StringRef FrameworkDirName = FrameworkDir->getName();
-#ifdef LLVM_ON_UNIX
+
// Note: as an egregious but useful hack we use the real path here, because
// we might be looking at an embedded framework that symlinks out to a
// top-level framework, and we need to infer as if we were naming the
// top-level framework.
- char RealFrameworkDirName[PATH_MAX];
- if (realpath(FrameworkDir->getName(), RealFrameworkDirName))
- FrameworkDirName = RealFrameworkDirName;
-#endif
+ StringRef FrameworkDirName
+ = SourceMgr->getFileManager().getCanonicalName(FrameworkDir);
bool canInfer = false;
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// check whether it is actually a subdirectory of the parent directory.
// This will not be the case if the 'subframework' is actually a symlink
// out to a top-level framework.
-#ifdef LLVM_ON_UNIX
- char RealSubframeworkDirName[PATH_MAX];
- if (realpath(Dir->path().c_str(), RealSubframeworkDirName)) {
- StringRef SubframeworkDirName = RealSubframeworkDirName;
-
- bool FoundParent = false;
- do {
- // Get the parent directory name.
- SubframeworkDirName
- = llvm::sys::path::parent_path(SubframeworkDirName);
- if (SubframeworkDirName.empty())
- break;
-
- if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
- FoundParent = true;
- break;
- }
- } while (true);
+ StringRef SubframeworkDirName = FileMgr.getCanonicalName(SubframeworkDir);
+ bool FoundParent = false;
+ do {
+ // Get the parent directory name.
+ SubframeworkDirName
+ = llvm::sys::path::parent_path(SubframeworkDirName);
+ if (SubframeworkDirName.empty())
+ break;
+
+ if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
+ FoundParent = true;
+ break;
+ }
+ } while (true);
- if (!FoundParent)
- continue;
- }
-#endif
+ if (!FoundParent)
+ continue;
// FIXME: Do we want to warn about subframeworks without umbrella headers?
SmallString<32> NameBuf;