*/
CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex);
+/**
+ * \brief Sets the invocation emission path option in a CXIndex.
+ *
+ * The invocation emission path specifies a path which will contain log
+ * files for certain libclang invocations. A null value (default) implies that
+ * libclang invocations are not logged..
+ */
+CINDEX_LINKAGE void
+clang_CXIndex_setInvocationEmissionPathOption(CXIndex, const char *Path);
+
/**
* \defgroup CINDEX_FILES File manipulation routines
*
--- /dev/null
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: not env CINDEXTEST_INVOCATION_EMISSION_PATH=%t c-index-test -test-load-source all %s
+// RUN: cat %t/libclang-* | FileCheck %s
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: env LIBCLANG_DISABLE_CRASH_RECOVERY=1 CINDEXTEST_INVOCATION_EMISSION_PATH=%t not --crash c-index-test -test-load-source all %s
+// RUN: cat %t/libclang-* | FileCheck %s
+
+// Verify that the file is removed for successful operation:
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: env CINDEXTEST_INVOCATION_EMISSION_PATH=%t c-index-test -test-load-source all %s -DAVOID_CRASH
+// RUN: ls %t | count 0
+
+#ifndef AVOID_CRASH
+# pragma clang __debug parser_crash
+#endif
+
+// CHECK: {"toolchain":"{{.*}}","libclang.operation":"parse","libclang.opts":1,"args":["clang","-fno-spell-checking","{{.*}}/record-parsing-invocation.c","-Xclang","-detailed-preprocessing-record","-fallow-editor-placeholders"]}
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--;
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();
// 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,
#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>
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);
+}
#include "clang-c/Index.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Mutex.h"
#include <utility>
namespace llvm {
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>())
/// \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".
clang_CXCursorSet_insert
clang_CXIndex_getGlobalOptions
clang_CXIndex_setGlobalOptions
+clang_CXIndex_setInvocationEmissionPathOption
clang_CXXConstructor_isConvertingConstructor
clang_CXXConstructor_isCopyConstructor
clang_CXXConstructor_isDefaultConstructor