1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Clang-C Source Indexing library.
//
//===----------------------------------------------------------------------===//
#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>
#ifdef __CYGWIN__
#include <cygwin/version.h>
#include <sys/cygwin.h>
#define LLVM_ON_WIN32 1
#endif
#ifdef LLVM_ON_WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
using namespace clang;
const std::string &CIndexer::getClangResourcesPath() {
// Did we already compute the path?
if (!ResourcesPath.empty())
return ResourcesPath;
SmallString<128> LibClangPath;
// Find the location where this library lives (libclang.dylib).
#ifdef LLVM_ON_WIN32
MEMORY_BASIC_INFORMATION mbi;
char path[MAX_PATH];
VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
sizeof(mbi));
GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
#ifdef __CYGWIN__
char w32path[MAX_PATH];
strcpy(w32path, path);
#if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181
cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH);
#else
cygwin_conv_to_full_posix_path(w32path, path);
#endif
#endif
LibClangPath += llvm::sys::path::parent_path(path);
#else
// This silly cast below avoids a C++ warning.
Dl_info info;
if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
llvm_unreachable("Call to dladdr() failed");
// We now have the CIndex directory, locate clang relative to it.
LibClangPath += llvm::sys::path::parent_path(info.dli_fname);
#endif
llvm::sys::path::append(LibClangPath, "clang", CLANG_VERSION_STRING);
// Cache our result.
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);
}
|