[cfe-commits] r124754 - /cfe/trunk/lib/Basic/FileManager.cpp

Chandler Carruth chandlerc at google.com
Wed Feb 2 16:38:50 PST 2011


On Wed, Feb 2, 2011 at 2:30 PM, Douglas Gregor <dgregor at apple.com> wrote:

> Author: dgregor
> Date: Wed Feb  2 16:30:17 2011
> New Revision: 124754
>
> URL: http://llvm.org/viewvc/llvm-project?rev=124754&view=rev
> Log:
> 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.
>
>
>
> Modified:
>    cfe/trunk/lib/Basic/FileManager.cpp
>
> Modified: cfe/trunk/lib/Basic/FileManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=124754&r1=124753&r2=124754&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Basic/FileManager.cpp (original)
> +++ cfe/trunk/lib/Basic/FileManager.cpp Wed Feb  2 16:30:17 2011
> @@ -271,10 +271,84 @@
>   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) {
>

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.


> +  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::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.
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110202/d139ae3a/attachment.html>


More information about the cfe-commits mailing list