Merge remote-tracking branch 'origin/swift-4.1-branch' into stable
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 3b5ea9f..4802914 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -334,6 +334,16 @@
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
*
* @{
diff --git a/lib/DirectoryWatcher/CMakeLists.txt b/lib/DirectoryWatcher/CMakeLists.txt
index 425a40f..b70e925 100644
--- a/lib/DirectoryWatcher/CMakeLists.txt
+++ b/lib/DirectoryWatcher/CMakeLists.txt
@@ -1,3 +1,5 @@
+include(CheckIncludeFiles)
+
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangDirectoryWatcher
@@ -6,3 +8,14 @@
LINK_LIBS
clangBasic
)
+
+if(BUILD_SHARED_LIBS)
+ if(APPLE)
+ check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES_H)
+ if(HAVE_CORESERVICES_H)
+ set(DIRECTORY_WATCHER_FLAGS "${DIRECTORY_WATCHER_FLAGS} -framework CoreServices")
+ endif()
+ set_property(TARGET clangDirectoryWatcher APPEND_STRING PROPERTY
+ LINK_FLAGS ${DIRECTORY_WATCHER_FLAGS})
+ endif()
+endif()
diff --git a/lib/Tooling/Refactor/CMakeLists.txt b/lib/Tooling/Refactor/CMakeLists.txt
index 9828c1a..bd93afa 100644
--- a/lib/Tooling/Refactor/CMakeLists.txt
+++ b/lib/Tooling/Refactor/CMakeLists.txt
@@ -37,6 +37,7 @@
clangASTMatchers
clangBasic
clangEdit
+ clangFrontend
clangIndex
clangLex
clangToolingCore
diff --git a/test/Index/Inputs/record-parsing-invocation-remap.c b/test/Index/Inputs/record-parsing-invocation-remap.c
new file mode 100644
index 0000000..4a32ca6
--- /dev/null
+++ b/test/Index/Inputs/record-parsing-invocation-remap.c
@@ -0,0 +1,2 @@
+
+#pragma clang __debug parser_crash
diff --git a/test/Index/record-completion-invocation.c b/test/Index/record-completion-invocation.c
new file mode 100644
index 0000000..c249565
--- /dev/null
+++ b/test/Index/record-completion-invocation.c
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: env CINDEXTEST_INVOCATION_EMISSION_PATH=%t not c-index-test -code-completion-at=%s:10:1 "-remap-file=%s,%S/Inputs/record-parsing-invocation-remap.c" %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 -code-completion-at=%s:10:1 "-remap-file=%s,%S/Inputs/record-parsing-invocation-remap.c" %s
+// RUN: cat %t/libclang-* | FileCheck %s
+
+// CHECK: {"toolchain":"{{.*}}","libclang.operation":"complete","libclang.opts":1,"args":["clang","-fno-spell-checking","{{.*}}record-completion-invocation.c","-Xclang","-detailed-preprocessing-record","-fallow-editor-placeholders"],"invocation-args":["-code-completion-at={{.*}}record-completion-invocation.c:10:1"],"unsaved_file_hashes":[{"name":"{{.*}}record-completion-invocation.c","md5":"aee23773de90e665992b48209351d70e"}]}
diff --git a/test/Index/record-parsing-invocation.c b/test/Index/record-parsing-invocation.c
new file mode 100644
index 0000000..3254e58
--- /dev/null
+++ b/test/Index/record-parsing-invocation.c
@@ -0,0 +1,28 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: env CINDEXTEST_INVOCATION_EMISSION_PATH=%t not 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
+
+// Make sure we record the unsaved file hash.
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: env CINDEXTEST_INVOCATION_EMISSION_PATH=%t not c-index-test -test-load-source all "-remap-file=%s,%S/Inputs/record-parsing-invocation-remap.c" %s
+// RUN: cat %t/libclang-* | FileCheck --check-prefix=CHECK-UNSAVED %s
+
+#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"]}
+// CHECK-UNSAVED: {"toolchain":"{{.*}}","libclang.operation":"parse","libclang.opts":1,"args":["clang","-fno-spell-checking","{{.*}}record-parsing-invocation.c","-Xclang","-detailed-preprocessing-record","-fallow-editor-placeholders"],"unsaved_file_hashes":[{"name":"{{.*}}record-parsing-invocation.c","md5":"aee23773de90e665992b48209351d70e"}]}
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 36b7703..baa0317 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1742,11 +1742,15 @@
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--;
@@ -2307,7 +2311,8 @@
CXTranslationUnit TU;
unsigned I, Repeats = 1;
unsigned completionOptions = clang_defaultCodeCompleteOptions();
-
+ const char *InvocationPath;
+
if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
completionOptions |= CXCodeComplete_IncludeCodePatterns;
if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
@@ -2326,7 +2331,10 @@
return -1;
CIdx = clang_createIndex(0, 0);
-
+ InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
+ if (InvocationPath)
+ clang_CXIndex_setInvocationEmissionPathOption(CIdx, InvocationPath);
+
if (getenv("CINDEXTEST_EDITING"))
Repeats = 5;
diff --git a/tools/clang-rename/CMakeLists.txt b/tools/clang-rename/CMakeLists.txt
index 771e3bd..24e5d98 100644
--- a/tools/clang-rename/CMakeLists.txt
+++ b/tools/clang-rename/CMakeLists.txt
@@ -12,6 +12,7 @@
clangTooling
clangToolingCore
clangToolingRefactor
+ clangToolingRefactoring
)
install(TARGETS clang-rename RUNTIME DESTINATION bin)
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index d527535..7fa5f19 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -81,6 +81,8 @@
D->Diagnostics = nullptr;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
D->CommentToXML = nullptr;
+ D->ParsingOptions = 0;
+ D->Arguments = {};
return D;
}
@@ -3227,6 +3229,12 @@
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();
@@ -3403,6 +3411,11 @@
// faster, trading for a slower (first) reparse.
unsigned PrecompilePreambleAfterNParses =
!PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
+
+ LibclangInvocationReporter InvocationReporter(
+ *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation,
+ options, llvm::makeArrayRef(*Args), /*InvocationArgs=*/None,
+ unsaved_files);
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine(
Args->data(), Args->data() + Args->size(),
CXXIdx->getPCHContainerOperations(), Diags,
@@ -3429,7 +3442,14 @@
return CXError_ASTReadError;
*out_TU = MakeCXTranslationUnit(CXXIdx, std::move(Unit));
- return *out_TU ? CXError_Success : CXError_Failure;
+ if (CXTranslationUnitImpl *TU = *out_TU) {
+ TU->ParsingOptions = options;
+ TU->Arguments.reserve(Args->size());
+ for (const char *Arg : *Args)
+ TU->Arguments.push_back(Arg);
+ return CXError_Success;
+ }
+ return CXError_Failure;
}
CXTranslationUnit
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index c2b4c0b..1bd3d6b 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -32,6 +32,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Timer.h"
@@ -691,6 +692,16 @@
CaptureCompletionResults Capture(Opts, *Results, &TU);
// Perform completion.
+ std::vector<const char *> CArgs;
+ for (const auto &Arg : TU->Arguments)
+ CArgs.push_back(Arg.c_str());
+ std::string CompletionInvocation =
+ llvm::formatv("-code-completion-at={0}:{1}:{2}", complete_filename,
+ complete_line, complete_column)
+ .str();
+ LibclangInvocationReporter InvocationReporter(
+ *CXXIdx, LibclangInvocationReporter::OperationKind::CompletionOperation,
+ TU->ParsingOptions, CArgs, CompletionInvocation, unsaved_files);
AST->CodeComplete(complete_filename, complete_line, complete_column,
RemappedFiles, (options & CXCodeComplete_IncludeMacros),
(options & CXCodeComplete_IncludeCodePatterns),
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 694ed60..62ea881 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -12,10 +12,14 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
+#include "CXString.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/MD5.h"
+#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include <cstdio>
@@ -76,3 +80,83 @@
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,
+ llvm::ArrayRef<std::string> InvocationArgs,
+ llvm::ArrayRef<CXUnsavedFile> UnsavedFiles) {
+ 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() << '"';
+ }
+ if (!InvocationArgs.empty()) {
+ OS << R"(],"invocation-args":[)";
+ for (const auto &I : llvm::enumerate(InvocationArgs)) {
+ if (I.index())
+ OS << ',';
+ OS << '"' << I.value() << '"';
+ }
+ }
+ if (!UnsavedFiles.empty()) {
+ OS << R"(],"unsaved_file_hashes":[)";
+ for (const auto &UF : llvm::enumerate(UnsavedFiles)) {
+ if (UF.index())
+ OS << ',';
+ OS << '{';
+ WriteStringKey("name", UF.value().Filename);
+ OS << ',';
+ llvm::MD5 Hash;
+ Hash.update(getContents(UF.value()));
+ llvm::MD5::MD5Result Result;
+ Hash.final(Result);
+ SmallString<32> Digest = Result.digest();
+ WriteStringKey("md5", Digest);
+ OS << '}';
+ }
+ }
+ OS << "]}";
+}
+
+LibclangInvocationReporter::~LibclangInvocationReporter() {
+ if (!File.empty())
+ llvm::sys::fs::remove(File);
+}
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index b227f94..6c46eed 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 @@
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,31 @@
/// \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,
+ llvm::ArrayRef<std::string> InvocationArgs,
+ llvm::ArrayRef<CXUnsavedFile> UnsavedFiles);
+ ~LibclangInvocationReporter();
+
+private:
+ std::string File;
};
/// \brief Return the current size to request for "safety".
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index dbad06a..2210598 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -43,6 +43,7 @@
clangLex
clangSema
clangTooling
+ clangToolingRefactor
)
if (CLANG_ENABLE_ARCMT)
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index ce8469b..590142f 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -33,6 +33,8 @@
void *Diagnostics;
void *OverridenCursorsPool;
clang::index::CommentToXMLConverter *CommentToXML;
+ unsigned ParsingOptions;
+ std::vector<std::string> Arguments;
};
struct CXTargetInfoImpl {
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index e9a9b58..e13f769 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -2,6 +2,7 @@
clang_CXCursorSet_insert
clang_CXIndex_getGlobalOptions
clang_CXIndex_setGlobalOptions
+clang_CXIndex_setInvocationEmissionPathOption
clang_CXXConstructor_isConvertingConstructor
clang_CXXConstructor_isCopyConstructor
clang_CXXConstructor_isDefaultConstructor
diff --git a/unittests/Rename/CMakeLists.txt b/unittests/Rename/CMakeLists.txt
index aa76092..80a9efd 100644
--- a/unittests/Rename/CMakeLists.txt
+++ b/unittests/Rename/CMakeLists.txt
@@ -19,4 +19,5 @@
clangTooling
clangToolingCore
clangToolingRefactor
+ clangToolingRefactoring
)
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index 1359c7c..0dc75ef 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -41,4 +41,5 @@
clangTooling
clangToolingCore
clangToolingRefactor
+ clangToolingRefactoring
)