r209241 - VirtualFileSystem: Add YAMLVFSWriter to generate VFS mapping files

Justin Bogner mail at justinbogner.com
Tue May 20 14:43:27 PDT 2014


Author: bogner
Date: Tue May 20 16:43:27 2014
New Revision: 209241

URL: http://llvm.org/viewvc/llvm-project?rev=209241&view=rev
Log:
VirtualFileSystem: Add YAMLVFSWriter to generate VFS mapping files

This moves the logic to write a JSON VFS mapping from the C api into
VirtualFileSystem, so that we can use it internally.

No functional change.

Modified:
    cfe/trunk/include/clang/Basic/VirtualFileSystem.h
    cfe/trunk/lib/Basic/VirtualFileSystem.cpp
    cfe/trunk/tools/libclang/BuildSystem.cpp

Modified: cfe/trunk/include/clang/Basic/VirtualFileSystem.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/VirtualFileSystem.h?rev=209241&r1=209240&r2=209241&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/VirtualFileSystem.h (original)
+++ cfe/trunk/include/clang/Basic/VirtualFileSystem.h Tue May 20 16:43:27 2014
@@ -15,8 +15,10 @@
 
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/SourceMgr.h"
 
 namespace llvm {
@@ -166,6 +168,34 @@ getVFSFromYAML(llvm::MemoryBuffer *Buffe
                void *DiagContext = nullptr,
                IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
 
+class YAMLVFSWriter {
+  struct MapEntry {
+    template <typename T1, typename T2> MapEntry(T1 &&VPath, T2 &&RPath)
+        : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
+    std::string VPath;
+    std::string RPath;
+  };
+  std::vector<MapEntry> Mappings;
+  Optional<bool> IsCaseSensitive;
+
+  llvm::ArrayRef<MapEntry> printDirNodes(llvm::raw_ostream &OS,
+                                         llvm::ArrayRef<MapEntry> Entries,
+                                         StringRef ParentPath, unsigned Indent);
+  llvm::ArrayRef<MapEntry> printContents(llvm::raw_ostream &OS,
+                                         llvm::ArrayRef<MapEntry> Entries,
+                                         unsigned Indent);
+  bool containedIn(StringRef Parent, StringRef Path);
+  StringRef containedPart(StringRef Parent, StringRef Path);
+
+public:
+  YAMLVFSWriter() {}
+  void addFileMapping(StringRef VirtualPath, StringRef RealPath);
+  void setCaseSensitivity(bool CaseSensitive) {
+    IsCaseSensitive = CaseSensitive;
+  }
+  void write(llvm::raw_ostream &OS);
+};
+
 } // end namespace vfs
 } // end namespace clang
 #endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H

Modified: cfe/trunk/lib/Basic/VirtualFileSystem.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/VirtualFileSystem.cpp?rev=209241&r1=209240&r2=209241&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/VirtualFileSystem.cpp (original)
+++ cfe/trunk/lib/Basic/VirtualFileSystem.cpp Tue May 20 16:43:27 2014
@@ -11,6 +11,7 @@
 
 #include "clang/Basic/VirtualFileSystem.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -843,3 +844,118 @@ UniqueID vfs::getNextVirtualUniqueID() {
   // dev_t value from the OS.
   return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
 }
+
+#ifndef NDEBUG
+static bool pathHasTraversal(StringRef Path) {
+  using namespace llvm::sys;
+  for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
+    if (Comp == "." || Comp == "..")
+      return true;
+  return false;
+}
+#endif
+
+void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
+  assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
+  assert(sys::path::is_absolute(RealPath) && "real path not absolute");
+  assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
+  Mappings.emplace_back(VirtualPath, RealPath);
+}
+
+ArrayRef<YAMLVFSWriter::MapEntry>
+YAMLVFSWriter::printDirNodes(llvm::raw_ostream &OS, ArrayRef<MapEntry> Entries,
+                             StringRef ParentPath, unsigned Indent) {
+  while (!Entries.empty()) {
+    const MapEntry &Entry = Entries.front();
+    OS.indent(Indent) << "{\n";
+    Indent += 2;
+    OS.indent(Indent) << "'type': 'directory',\n";
+    StringRef DirName =
+        containedPart(ParentPath, sys::path::parent_path(Entry.VPath));
+    OS.indent(Indent)
+        << "'name': \"" << llvm::yaml::escape(DirName) << "\",\n";
+    OS.indent(Indent) << "'contents': [\n";
+    Entries = printContents(OS, Entries, Indent + 2);
+    OS.indent(Indent) << "]\n";
+    Indent -= 2;
+    OS.indent(Indent) << '}';
+    if (Entries.empty()) {
+      OS << '\n';
+      break;
+    }
+    StringRef NextVPath = Entries.front().VPath;
+    if (!containedIn(ParentPath, NextVPath)) {
+      OS << '\n';
+      break;
+    }
+    OS << ",\n";
+  }
+  return Entries;
+}
+
+ArrayRef<YAMLVFSWriter::MapEntry>
+YAMLVFSWriter::printContents(llvm::raw_ostream &OS, ArrayRef<MapEntry> Entries,
+                             unsigned Indent) {
+  using namespace llvm::sys;
+  while (!Entries.empty()) {
+    const MapEntry &Entry = Entries.front();
+    Entries = Entries.slice(1);
+    StringRef ParentPath = path::parent_path(Entry.VPath);
+    StringRef VName = path::filename(Entry.VPath);
+    OS.indent(Indent) << "{\n";
+    Indent += 2;
+    OS.indent(Indent) << "'type': 'file',\n";
+    OS.indent(Indent) << "'name': \"" << llvm::yaml::escape(VName) << "\",\n";
+    OS.indent(Indent) << "'external-contents': \""
+                      << llvm::yaml::escape(Entry.RPath) << "\"\n";
+    Indent -= 2;
+    OS.indent(Indent) << '}';
+    if (Entries.empty()) {
+      OS << '\n';
+      break;
+    }
+    StringRef NextVPath = Entries.front().VPath;
+    if (!containedIn(ParentPath, NextVPath)) {
+      OS << '\n';
+      break;
+    }
+    OS << ",\n";
+    if (path::parent_path(NextVPath) != ParentPath) {
+      Entries = printDirNodes(OS, Entries, ParentPath, Indent);
+    }
+  }
+  return Entries;
+}
+
+bool YAMLVFSWriter::containedIn(StringRef Parent, StringRef Path) {
+  return Path.startswith(Parent);
+}
+
+StringRef YAMLVFSWriter::containedPart(StringRef Parent, StringRef Path) {
+  assert(containedIn(Parent, Path));
+  if (Parent.empty())
+    return Path;
+  return Path.slice(Parent.size() + 1, StringRef::npos);
+}
+
+void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
+  std::sort(Mappings.begin(), Mappings.end(),
+            [](const MapEntry &LHS, const MapEntry &RHS) {
+    return LHS.VPath < RHS.VPath;
+  });
+
+  OS << "{\n"
+        "  'version': 0,\n";
+  if (IsCaseSensitive.hasValue()) {
+    OS << "  'case-sensitive': '";
+    if (IsCaseSensitive.getValue())
+      OS << "true";
+    else
+      OS << "false";
+    OS << "',\n";
+  }
+  OS << "  'roots': [\n";
+  printDirNodes(OS, Mappings, "", 4);
+  OS << "  ]\n"
+     << "}\n";
+}

Modified: cfe/trunk/tools/libclang/BuildSystem.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/BuildSystem.cpp?rev=209241&r1=209240&r2=209241&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/BuildSystem.cpp (original)
+++ cfe/trunk/tools/libclang/BuildSystem.cpp Tue May 20 16:43:27 2014
@@ -13,13 +13,12 @@
 
 #include "clang-c/BuildSystem.h"
 #include "CXString.h"
-#include "llvm/ADT/ArrayRef.h"
+#include "clang/Basic/VirtualFileSystem.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Optional.h"
+#include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/TimeValue.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/YAMLParser.h"
 
 using namespace clang;
 using namespace llvm::sys;
@@ -28,13 +27,11 @@ unsigned long long clang_getBuildSession
   return llvm::sys::TimeValue::now().toEpochTime();
 }
 
-struct CXVirtualFileOverlayImpl {
-  std::vector<std::pair<std::string, std::string> > Mappings;
-  Optional<bool> IsCaseSensitive;
-};
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(clang::vfs::YAMLVFSWriter,
+                                   CXVirtualFileOverlay)
 
 CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) {
-  return new CXVirtualFileOverlayImpl();
+  return wrap(new clang::vfs::YAMLVFSWriter());
 }
 
 enum CXErrorCode
@@ -56,7 +53,7 @@ clang_VirtualFileOverlay_addFileMapping(
       return CXError_InvalidArguments;
   }
 
-  VFO->Mappings.push_back(std::make_pair(virtualPath, realPath));
+  unwrap(VFO)->addFileMapping(virtualPath, realPath);
   return CXError_Success;
 }
 
@@ -65,124 +62,10 @@ clang_VirtualFileOverlay_setCaseSensitiv
                                             int caseSensitive) {
   if (!VFO)
     return CXError_InvalidArguments;
-
-  VFO->IsCaseSensitive = caseSensitive;
+  unwrap(VFO)->setCaseSensitivity(caseSensitive);
   return CXError_Success;
 }
 
-namespace {
-struct EntryTy {
-  std::string VPath;
-  std::string RPath;
-
-  friend bool operator < (const EntryTy &LHS, const EntryTy &RHS) {
-    return LHS.VPath < RHS.VPath;
-  }
-};
-
-class JSONVFSPrinter {
-  llvm::raw_ostream &OS;
-  CXVirtualFileOverlay VFO;
-
-public:
-  JSONVFSPrinter(llvm::raw_ostream &OS, CXVirtualFileOverlay VFO)
-    : OS(OS), VFO(VFO) {}
-
-  /// Entries must be sorted.
-  void print(ArrayRef<EntryTy> Entries) {
-    OS << "{\n"
-          "  'version': 0,\n";
-    if (VFO->IsCaseSensitive.hasValue()) {
-      OS << "  'case-sensitive': '";
-      if (VFO->IsCaseSensitive.getValue())
-        OS << "true";
-      else
-        OS << "false";
-      OS << "',\n";
-    }
-    OS << "  'roots': [\n";
-    printDirNodes(Entries, "", 4);
-    OS << "  ]\n"
-          "}\n";
-  }
-
-private:
-  ArrayRef<EntryTy> printDirNodes(ArrayRef<EntryTy> Entries,
-                                  StringRef ParentPath,
-                                  unsigned Indent) {
-    while (!Entries.empty()) {
-      const EntryTy &Entry = Entries.front();
-      OS.indent(Indent) << "{\n";
-      Indent += 2;
-      OS.indent(Indent) << "'type': 'directory',\n";
-      StringRef DirName = containedPart(ParentPath,
-                                        path::parent_path(Entry.VPath));
-      OS.indent(Indent)
-          << "'name': \"" << llvm::yaml::escape(DirName) << "\",\n";
-      OS.indent(Indent) << "'contents': [\n";
-      Entries = printContents(Entries, Indent + 2);
-      OS.indent(Indent) << "]\n";
-      Indent -= 2;
-      OS.indent(Indent) << '}';
-      if (Entries.empty()) {
-        OS << '\n';
-        break;
-      }
-      StringRef NextVPath = Entries.front().VPath;
-      if (!containedIn(ParentPath, NextVPath)) {
-        OS << '\n';
-        break;
-      }
-      OS << ",\n";
-    }
-    return Entries;
-  }
-
-  ArrayRef<EntryTy> printContents(ArrayRef<EntryTy> Entries,
-                                  unsigned Indent) {
-    while (!Entries.empty()) {
-      const EntryTy &Entry = Entries.front();
-      Entries = Entries.slice(1);
-      StringRef ParentPath = path::parent_path(Entry.VPath);
-      StringRef VName = path::filename(Entry.VPath);
-      OS.indent(Indent) << "{\n";
-      Indent += 2;
-      OS.indent(Indent) << "'type': 'file',\n";
-      OS.indent(Indent) << "'name': \"" << llvm::yaml::escape(VName) << "\",\n";
-      OS.indent(Indent) << "'external-contents': \""
-                        << llvm::yaml::escape(Entry.RPath) << "\"\n";
-      Indent -= 2;
-      OS.indent(Indent) << '}';
-      if (Entries.empty()) {
-        OS << '\n';
-        break;
-      }
-      StringRef NextVPath = Entries.front().VPath;
-      if (!containedIn(ParentPath, NextVPath)) {
-        OS << '\n';
-        break;
-      }
-      OS << ",\n";
-      if (path::parent_path(NextVPath) != ParentPath) {
-        Entries = printDirNodes(Entries, ParentPath, Indent);
-      }
-    }
-    return Entries;
-  }
-
-  bool containedIn(StringRef Parent, StringRef Path) {
-    return Path.startswith(Parent);
-  }
-
-  StringRef containedPart(StringRef Parent, StringRef Path) {
-    assert(containedIn(Parent, Path));
-    if (Parent.empty())
-      return Path;
-    return Path.slice(Parent.size()+1, StringRef::npos);
-  }
-};
-}
-
 enum CXErrorCode
 clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned,
                                        char **out_buffer_ptr,
@@ -190,24 +73,9 @@ clang_VirtualFileOverlay_writeToBuffer(C
   if (!VFO || !out_buffer_ptr || !out_buffer_size)
     return CXError_InvalidArguments;
 
-  llvm::SmallVector<EntryTy, 16> Entries;
-  for (unsigned i = 0, e = VFO->Mappings.size(); i != e; ++i) {
-    EntryTy Entry;
-    Entry.VPath = VFO->Mappings[i].first;
-    Entry.RPath = VFO->Mappings[i].second;
-    Entries.push_back(Entry);
-  }
-
-  // FIXME: We should add options to determine if the paths are case sensitive
-  // or not. The following assumes that if paths are case-insensitive the caller
-  // did not mix cases in the virtual paths it provided.
-
-  std::sort(Entries.begin(), Entries.end());
-
   llvm::SmallString<256> Buf;
   llvm::raw_svector_ostream OS(Buf);
-  JSONVFSPrinter Printer(OS, VFO);
-  Printer.print(Entries);
+  unwrap(VFO)->write(OS);
 
   StringRef Data = OS.str();
   *out_buffer_ptr = (char*)malloc(Data.size());
@@ -217,7 +85,7 @@ clang_VirtualFileOverlay_writeToBuffer(C
 }
 
 void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) {
-  delete VFO;
+  delete unwrap(VFO);
 }
 
 





More information about the cfe-commits mailing list