diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-12-04 21:56:36 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-12-04 21:56:36 +0000 |
commit | 76f57b28554f0c281b1e5e3dc2749fe8c4893193 (patch) | |
tree | 34cb2b8a86628c3bf4a16e6cdc4f477cd1034c6a /tools | |
parent | d80ab9d1a5be9068183b4433d417c61fdf02e179 (diff) |
[libclang] Record parsing invocation to a temporary file when requested
by client
This patch extends libclang by allowing it to record parsing operations to a
temporary JSON file. The file is deleted after parsing succeeds. When a crash
happens during parsing, the file is preserved and the client will be able to use
it to generate a reproducer for the crash.
These files are not emitted by default, and the client has to specify the
invocation emission path first.
rdar://35322543
Differential Revision: https://reviews.llvm.org/D40527
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@319702 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/c-index-test/c-index-test.c | 4 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 11 | ||||
-rw-r--r-- | tools/libclang/CIndexer.cpp | 55 | ||||
-rw-r--r-- | tools/libclang/CIndexer.h | 28 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 1 |
5 files changed, 99 insertions, 0 deletions
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index a11e03c846..6cb67e1030 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1747,11 +1747,15 @@ int perform_test_load_source(int argc, const char **argv, int result; unsigned Repeats = 0; unsigned I; + const char *InvocationPath; Idx = clang_createIndex(/* excludeDeclsFromPCH */ (!strcmp(filter, "local") || !strcmp(filter, "local-display"))? 1 : 0, /* displayDiagnostics=*/1); + InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH"); + if (InvocationPath) + clang_CXIndex_setInvocationEmissionPathOption(Idx, InvocationPath); if ((CommentSchemaFile = parse_comments_schema(argc, argv))) { argc--; diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 455151f0fc..b642014c43 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3255,6 +3255,12 @@ unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) { return 0; } +void clang_CXIndex_setInvocationEmissionPathOption(CXIndex CIdx, + const char *Path) { + if (CIdx) + static_cast<CIndexer *>(CIdx)->setInvocationEmissionPath(Path ? Path : ""); +} + void clang_toggleCrashRecovery(unsigned isEnabled) { if (isEnabled) llvm::CrashRecoveryContext::Enable(); @@ -3431,6 +3437,11 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, // faster, trading for a slower (first) reparse. unsigned PrecompilePreambleAfterNParses = !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; + + // FIXME: Record the hash of the unsaved files. + LibclangInvocationReporter InvocationReporter( + *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, + options, llvm::makeArrayRef(*Args)); std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), Diags, diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp index 694ed60630..13774bd8b7 100644 --- a/tools/libclang/CIndexer.cpp +++ b/tools/libclang/CIndexer.cpp @@ -14,8 +14,10 @@ #include "CIndexer.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Version.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/MutexGuard.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include <cstdio> @@ -76,3 +78,56 @@ const std::string &CIndexer::getClangResourcesPath() { ResourcesPath = LibClangPath.str(); return ResourcesPath; } + +StringRef CIndexer::getClangToolchainPath() { + if (!ToolchainPath.empty()) + return ToolchainPath; + StringRef ResourcePath = getClangResourcesPath(); + ToolchainPath = llvm::sys::path::parent_path( + llvm::sys::path::parent_path(llvm::sys::path::parent_path(ResourcePath))); + return ToolchainPath; +} + +LibclangInvocationReporter::LibclangInvocationReporter( + CIndexer &Idx, OperationKind Op, unsigned ParseOptions, + llvm::ArrayRef<const char *> Args) { + StringRef Path = Idx.getInvocationEmissionPath(); + if (Path.empty()) + return; + + // Create a temporary file for the invocation log. + SmallString<256> TempPath; + TempPath = Path; + llvm::sys::path::append(TempPath, "libclang-%%%%%%%%%%%%"); + int FD; + if (llvm::sys::fs::createUniqueFile(TempPath, FD, TempPath)) + return; + File = std::string(TempPath.begin(), TempPath.end()); + llvm::raw_fd_ostream OS(FD, /*ShouldClose=*/true); + + // Write out the information about the invocation to it. + auto WriteStringKey = [&OS](StringRef Key, StringRef Value) { + OS << R"(")" << Key << R"(":")"; + OS << Value << '"'; + }; + OS << '{'; + WriteStringKey("toolchain", Idx.getClangToolchainPath()); + OS << ','; + WriteStringKey("libclang.operation", + Op == OperationKind::ParseOperation ? "parse" : "complete"); + OS << ','; + OS << R"("libclang.opts":)" << ParseOptions; + OS << ','; + OS << R"("args":[)"; + for (const auto &I : llvm::enumerate(Args)) { + if (I.index()) + OS << ','; + OS << '"' << I.value() << '"'; + } + OS << "]}"; +} + +LibclangInvocationReporter::~LibclangInvocationReporter() { + if (!File.empty()) + llvm::sys::fs::remove(File); +} diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h index b227f943f7..b3346cd955 100644 --- a/tools/libclang/CIndexer.h +++ b/tools/libclang/CIndexer.h @@ -18,6 +18,7 @@ #include "clang-c/Index.h" #include "clang/Frontend/PCHContainerOperations.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Mutex.h" #include <utility> namespace llvm { @@ -40,6 +41,10 @@ class CIndexer { std::string ResourcesPath; std::shared_ptr<PCHContainerOperations> PCHContainerOps; + std::string ToolchainPath; + + std::string InvocationEmissionPath; + public: CIndexer(std::shared_ptr<PCHContainerOperations> PCHContainerOps = std::make_shared<PCHContainerOperations>()) @@ -71,6 +76,29 @@ public: /// \brief Get the path of the clang resource files. const std::string &getClangResourcesPath(); + + StringRef getClangToolchainPath(); + + void setInvocationEmissionPath(StringRef Str) { + InvocationEmissionPath = Str; + } + + StringRef getInvocationEmissionPath() const { return InvocationEmissionPath; } +}; + +/// Logs information about a particular libclang operation like parsing to +/// a new file in the invocation emission path. +class LibclangInvocationReporter { +public: + enum class OperationKind { ParseOperation, CompletionOperation }; + + LibclangInvocationReporter(CIndexer &Idx, OperationKind Op, + unsigned ParseOptions, + llvm::ArrayRef<const char *> Args); + ~LibclangInvocationReporter(); + +private: + std::string File; }; /// \brief Return the current size to request for "safety". diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index fb4547a867..bd262ee1a0 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -2,6 +2,7 @@ clang_CXCursorSet_contains clang_CXCursorSet_insert clang_CXIndex_getGlobalOptions clang_CXIndex_setGlobalOptions +clang_CXIndex_setInvocationEmissionPathOption clang_CXXConstructor_isConvertingConstructor clang_CXXConstructor_isCopyConstructor clang_CXXConstructor_isDefaultConstructor |