summaryrefslogtreecommitdiffstats
path: root/clang/tools/libclang/BuildSystem.cpp
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2014-02-25 03:59:23 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2014-02-25 03:59:23 +0000
commit0b9682efa42cbd2c3d4ee5cfd56b22f590aeaa8a (patch)
tree77866ecdcefdb675fc2e5559fbe799209b8c3ac6 /clang/tools/libclang/BuildSystem.cpp
parent09a439d3135d276a1b8b35bc50ff9603cb0f2755 (diff)
downloadbcm5719-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.cpp177
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;
+}
OpenPOWER on IntegriCloud