diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2014-02-25 03:59:23 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2014-02-25 03:59:23 +0000 |
commit | 0b9682efa42cbd2c3d4ee5cfd56b22f590aeaa8a (patch) | |
tree | 77866ecdcefdb675fc2e5559fbe799209b8c3ac6 /clang/tools/libclang/BuildSystem.cpp | |
parent | 09a439d3135d276a1b8b35bc50ff9603cb0f2755 (diff) | |
download | bcm5719-llvm-0b9682efa42cbd2c3d4ee5cfd56b22f590aeaa8a.tar.gz bcm5719-llvm-0b9682efa42cbd2c3d4ee5cfd56b22f590aeaa8a.zip |
[libclang] Introduce libclang APIs for creating a buffer with a JSON virtual file overlay description.
The current API only supports adding 'virtual file path' -> 'real file path' mappings.
rdar://15986708
llvm-svn: 202105
Diffstat (limited to 'clang/tools/libclang/BuildSystem.cpp')
-rw-r--r-- | clang/tools/libclang/BuildSystem.cpp | 177 |
1 files changed, 175 insertions, 2 deletions
diff --git a/clang/tools/libclang/BuildSystem.cpp b/clang/tools/libclang/BuildSystem.cpp index caf8377174d..311319ab966 100644 --- a/clang/tools/libclang/BuildSystem.cpp +++ b/clang/tools/libclang/BuildSystem.cpp @@ -12,11 +12,184 @@ //===----------------------------------------------------------------------===// #include "clang-c/BuildSystem.h" +#include "CXString.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/TimeValue.h" -extern "C" { +using namespace clang; +using namespace llvm::sys; + unsigned long long clang_getBuildSessionTimestamp(void) { return llvm::sys::TimeValue::now().toEpochTime(); } -} // extern "C" +struct CXVirtualFileOverlayImpl { + std::vector<std::pair<std::string, std::string> > Mappings; +}; + +CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) { + return new CXVirtualFileOverlayImpl(); +} + +enum CXErrorCode +clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay VFO, + const char *virtualPath, + const char *realPath) { + if (!VFO || !virtualPath || !realPath) + return CXError_InvalidArguments; + if (!path::is_absolute(virtualPath)) + return CXError_InvalidArguments; + if (!path::is_absolute(realPath)) + return CXError_InvalidArguments; + + for (path::const_iterator + PI = path::begin(virtualPath), + PE = path::end(virtualPath); PI != PE; ++PI) { + StringRef Comp = *PI; + if (Comp == "." || Comp == "..") + return CXError_InvalidArguments; + } + + VFO->Mappings.push_back(std::make_pair(virtualPath, realPath)); + 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; + +public: + JSONVFSPrinter(llvm::raw_ostream &OS) : OS(OS) {} + + /// Entries must be sorted. + void print(ArrayRef<EntryTy> Entries) { + OS << "{\n" + " 'version': 0,\n" + " '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"; + OS.indent(Indent) << "'name': \""; + StringRef DirName = containedPart(ParentPath, + path::parent_path(Entry.VPath)); + OS.write_escaped(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': \""; + OS.write_escaped(VName) << "\",\n"; + OS.indent(Indent) << "'external-contents': \""; + OS.write_escaped(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, CXString *out_buffer) { + if (!VFO || !out_buffer) + 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); + Printer.print(Entries); + + *out_buffer = cxstring::createDup(OS.str()); + return CXError_Success; +} + +void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) { + delete VFO; +} |