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