<div class="gmail_quote">On Wed, Feb 2, 2011 at 2:30 PM, Douglas Gregor <span dir="ltr"><<a href="mailto:dgregor@apple.com">dgregor@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Author: dgregor<br>
Date: Wed Feb  2 16:30:17 2011<br>
New Revision: 124754<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=124754&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=124754&view=rev</a><br>
Log:<br>
Canonicalize path names in the file manager before performing a lookup<br>
on that name. Canonicalization eliminates silliness such as "." and<br>
"foo/.." that breaks the uniquing of files in the presence of virtual<br>
files or files whose inode numbers have changed during<br>
parsing/re-parsing. c-index-test isn't able to create this crazy<br>
situation, so I've resorted to testing outside of the Clang<br>
tree. Fixes <rdar://problem/8928220>.<br>
<br>
Note that this hackery will go away once we have a real virtual file<br>
system on which we can layer FileManager; the virtual-files hack is<br>
showing cracks.<br>
<br>
<br>
<br>
Modified:<br>
    cfe/trunk/lib/Basic/FileManager.cpp<br>
<br>
Modified: cfe/trunk/lib/Basic/FileManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=124754&r1=124753&r2=124754&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=124754&r1=124753&r2=124754&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Basic/FileManager.cpp (original)<br>
+++ cfe/trunk/lib/Basic/FileManager.cpp Wed Feb  2 16:30:17 2011<br>
@@ -271,10 +271,84 @@<br>
   return &UDE;<br>
 }<br>
<br>
+/// \brief Canonicalize a file or path name by eliminating redundant<br>
+/// "foo/.." and "./" path components.<br>
+///<br>
+/// Uses the given scratch space to store the resulting string, if needed.<br>
+static llvm::StringRef CanonicalizeFileName(llvm::StringRef Filename,<br>
+                                            llvm::SmallVectorImpl<char> &Scratch) {<br></blockquote><div><br></div><div>Any reason not to place this logic in LLVM's PathV2 library? Also, this is a great candidate for a unit test. =] I suspect that even when we have proper VFS layering, we'll still want this core functionality, just not exposed at this layer.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
+  size_t Start = 0;<br>
+  bool Changed = false;<br>
+  do {<br>
+    size_t FirstSlash = Filename.find('/', Start);<br>
+    if (FirstSlash == llvm::StringRef::npos) {<br>
+      // No more components. Just copy the rest of the file name, if<br>
+      // we need to.<br>
+      if (Changed)<br>
+        Scratch.append(Filename.begin() + Start, Filename.end());<br>
+      break;<br>
+    }<br>
+<br>
+    if (Start + 1 == FirstSlash && Filename[Start] == '.') {<br>
+      // We have './'; remove it.<br>
+<br>
+      // If we haven't changed anything previously, copy the<br>
+      // starting bits here.<br>
+      if (!Changed) {<br>
+        Scratch.clear();<br>
+        Scratch.append(Filename.begin(), Filename.begin() + Start);<br>
+        Changed = true;<br>
+      }<br>
+<br>
+      // Skip over the './'.<br>
+      Start = FirstSlash + 1;<br>
+      continue;<br>
+    }<br>
+<br>
+    size_t SecondSlash = Filename.find('/', FirstSlash + 1);<br>
+    if (SecondSlash != llvm::StringRef::npos &&<br>
+        SecondSlash - FirstSlash == 3 &&<br>
+        Filename[FirstSlash + 1] == '.' &&<br>
+        Filename[FirstSlash + 2] == '.') {<br>
+      // We have 'foo/../'; remove it.<br>
+<br>
+      // If we haven't changed anything previously, copy the<br>
+      // starting bits here.<br>
+      if (!Changed) {<br>
+        Scratch.clear();<br>
+        Scratch.append(Filename.begin(), Filename.begin() + Start);<br>
+        Changed = true;<br>
+      }<br>
+<br>
+      // Skip over the 'foo/..'.<br>
+      Start = SecondSlash + 1;<br>
+      continue;<br>
+    }<br>
+<br>
+    if (Changed)<br>
+      Scratch.append(Filename.begin() + Start,<br>
+                     Filename.begin() + FirstSlash + 1);<br>
+    Start = FirstSlash + 1;<br>
+  } while (true);<br>
+<br>
+  if (Changed) {<br>
+#if 0<br>
+    llvm::errs() << "Canonicalized \"" << Filename << "\" to \""<br>
+                 << llvm::StringRef(Scratch.data(), Scratch.size()) << "\"\n";<br>
+#endif<br>
+    return llvm::StringRef(Scratch.data(), Scratch.size());<br>
+  }<br>
+<br>
+  return Filename;<br>
+}<br>
+<br>
 /// getFile - Lookup, cache, and verify the specified file.  This returns null<br>
 /// if the file doesn't exist.<br>
 ///<br>
 const FileEntry *FileManager::getFile(llvm::StringRef Filename) {<br>
+  llvm::SmallString<128> FilenameScratch;<br>
+  Filename = CanonicalizeFileName(Filename, FilenameScratch);<br>
+<br>
   ++NumFileLookups;<br>
<br>
   // See if there is already an entry in the map.<br>
@@ -343,6 +417,9 @@<br>
 const FileEntry *<br>
 FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,<br>
                             time_t ModificationTime) {<br>
+  llvm::SmallString<128> FilenameScratch;<br>
+  Filename = CanonicalizeFileName(Filename, FilenameScratch);<br>
+<br>
   ++NumFileLookups;<br>
<br>
   // See if there is already an entry in the map.<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>