summaryrefslogtreecommitdiffstats
path: root/clang/lib/Basic/FileManager.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-02-02 22:30:17 +0000
committerDouglas Gregor <dgregor@apple.com>2011-02-02 22:30:17 +0000
commit3c0d263abb7469f63c03df6ab21bfb5785457401 (patch)
tree1c0ad8f0f34b71ae8f8bd7595ba52db24f68d54f /clang/lib/Basic/FileManager.cpp
parente3773c2f511e1c2deb2f1128a14e98b386ca47c4 (diff)
downloadbcm5719-llvm-3c0d263abb7469f63c03df6ab21bfb5785457401.tar.gz
bcm5719-llvm-3c0d263abb7469f63c03df6ab21bfb5785457401.zip
Canonicalize path names in the file manager before performing a lookup
on that name. Canonicalization eliminates silliness such as "." and "foo/.." that breaks the uniquing of files in the presence of virtual files or files whose inode numbers have changed during parsing/re-parsing. c-index-test isn't able to create this crazy situation, so I've resorted to testing outside of the Clang tree. Fixes <rdar://problem/8928220>. Note that this hackery will go away once we have a real virtual file system on which we can layer FileManager; the virtual-files hack is showing cracks. llvm-svn: 124754
Diffstat (limited to 'clang/lib/Basic/FileManager.cpp')
-rw-r--r--clang/lib/Basic/FileManager.cpp77
1 files changed, 77 insertions, 0 deletions
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp
index cbe90bfdc16..5bf1ae36892 100644
--- a/clang/lib/Basic/FileManager.cpp
+++ b/clang/lib/Basic/FileManager.cpp
@@ -271,10 +271,84 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) {
return &UDE;
}
+/// \brief Canonicalize a file or path name by eliminating redundant
+/// "foo/.." and "./" path components.
+///
+/// Uses the given scratch space to store the resulting string, if needed.
+static llvm::StringRef CanonicalizeFileName(llvm::StringRef Filename,
+ llvm::SmallVectorImpl<char> &Scratch) {
+ size_t Start = 0;
+ bool Changed = false;
+ do {
+ size_t FirstSlash = Filename.find('/', Start);
+ if (FirstSlash == llvm::StringRef::npos) {
+ // No more components. Just copy the rest of the file name, if
+ // we need to.
+ if (Changed)
+ Scratch.append(Filename.begin() + Start, Filename.end());
+ break;
+ }
+
+ if (Start + 1 == FirstSlash && Filename[Start] == '.') {
+ // We have './'; remove it.
+
+ // If we haven't changed anything previously, copy the
+ // starting bits here.
+ if (!Changed) {
+ Scratch.clear();
+ Scratch.append(Filename.begin(), Filename.begin() + Start);
+ Changed = true;
+ }
+
+ // Skip over the './'.
+ Start = FirstSlash + 1;
+ continue;
+ }
+
+ size_t SecondSlash = Filename.find('/', FirstSlash + 1);
+ if (SecondSlash != llvm::StringRef::npos &&
+ SecondSlash - FirstSlash == 3 &&
+ Filename[FirstSlash + 1] == '.' &&
+ Filename[FirstSlash + 2] == '.') {
+ // We have 'foo/../'; remove it.
+
+ // If we haven't changed anything previously, copy the
+ // starting bits here.
+ if (!Changed) {
+ Scratch.clear();
+ Scratch.append(Filename.begin(), Filename.begin() + Start);
+ Changed = true;
+ }
+
+ // Skip over the 'foo/..'.
+ Start = SecondSlash + 1;
+ continue;
+ }
+
+ if (Changed)
+ Scratch.append(Filename.begin() + Start,
+ Filename.begin() + FirstSlash + 1);
+ Start = FirstSlash + 1;
+ } while (true);
+
+ if (Changed) {
+#if 0
+ llvm::errs() << "Canonicalized \"" << Filename << "\" to \""
+ << llvm::StringRef(Scratch.data(), Scratch.size()) << "\"\n";
+#endif
+ return llvm::StringRef(Scratch.data(), Scratch.size());
+ }
+
+ return Filename;
+}
+
/// getFile - Lookup, cache, and verify the specified file. This returns null
/// if the file doesn't exist.
///
const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
+ llvm::SmallString<128> FilenameScratch;
+ Filename = CanonicalizeFileName(Filename, FilenameScratch);
+
++NumFileLookups;
// See if there is already an entry in the map.
@@ -343,6 +417,9 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
const FileEntry *
FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
time_t ModificationTime) {
+ llvm::SmallString<128> FilenameScratch;
+ Filename = CanonicalizeFileName(Filename, FilenameScratch);
+
++NumFileLookups;
// See if there is already an entry in the map.
OpenPOWER on IntegriCloud