summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-12-04 21:56:36 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-12-04 21:56:36 +0000
commit76f57b28554f0c281b1e5e3dc2749fe8c4893193 (patch)
tree34cb2b8a86628c3bf4a16e6cdc4f477cd1034c6a /tools
parentd80ab9d1a5be9068183b4433d417c61fdf02e179 (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.c4
-rw-r--r--tools/libclang/CIndex.cpp11
-rw-r--r--tools/libclang/CIndexer.cpp55
-rw-r--r--tools/libclang/CIndexer.h28
-rw-r--r--tools/libclang/libclang.exports1
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