]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/libclang/CIndexer.cpp
Vendor import of clang trunk r338150:
[FreeBSD/FreeBSD.git] / tools / libclang / CIndexer.cpp
1 //===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Clang-C Source Indexing library.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "CIndexer.h"
15 #include "CXString.h"
16 #include "clang/Basic/LLVM.h"
17 #include "clang/Basic/Version.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/Support/MD5.h"
21 #include "llvm/Support/MutexGuard.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/Program.h"
24 #include "llvm/Support/YAMLParser.h"
25 #include <cstdio>
26
27 #ifdef __CYGWIN__
28 #include <cygwin/version.h>
29 #include <sys/cygwin.h>
30 #define _WIN32 1
31 #endif
32
33 #ifdef _WIN32
34 #include <windows.h>
35 #else
36 #include <dlfcn.h>
37 #endif
38
39 using namespace clang;
40
41 const std::string &CIndexer::getClangResourcesPath() {
42   // Did we already compute the path?
43   if (!ResourcesPath.empty())
44     return ResourcesPath;
45
46   SmallString<128> LibClangPath;
47
48   // Find the location where this library lives (libclang.dylib).
49 #ifdef _WIN32
50   MEMORY_BASIC_INFORMATION mbi;
51   char path[MAX_PATH];
52   VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
53                sizeof(mbi));
54   GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
55
56 #ifdef __CYGWIN__
57   char w32path[MAX_PATH];
58   strcpy(w32path, path);
59 #if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181
60   cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH);
61 #else
62   cygwin_conv_to_full_posix_path(w32path, path);
63 #endif
64 #endif
65
66   LibClangPath += llvm::sys::path::parent_path(path);
67 #else
68   // This silly cast below avoids a C++ warning.
69   Dl_info info;
70   if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
71     llvm_unreachable("Call to dladdr() failed");
72
73   // We now have the CIndex directory, locate clang relative to it.
74   LibClangPath += llvm::sys::path::parent_path(info.dli_fname);
75 #endif
76
77   llvm::sys::path::append(LibClangPath, "clang", CLANG_VERSION_STRING);
78
79   // Cache our result.
80   ResourcesPath = LibClangPath.str();
81   return ResourcesPath;
82 }
83
84 StringRef CIndexer::getClangToolchainPath() {
85   if (!ToolchainPath.empty())
86     return ToolchainPath;
87   StringRef ResourcePath = getClangResourcesPath();
88   ToolchainPath = llvm::sys::path::parent_path(
89       llvm::sys::path::parent_path(llvm::sys::path::parent_path(ResourcePath)));
90   return ToolchainPath;
91 }
92
93 LibclangInvocationReporter::LibclangInvocationReporter(
94     CIndexer &Idx, OperationKind Op, unsigned ParseOptions,
95     llvm::ArrayRef<const char *> Args,
96     llvm::ArrayRef<std::string> InvocationArgs,
97     llvm::ArrayRef<CXUnsavedFile> UnsavedFiles) {
98   StringRef Path = Idx.getInvocationEmissionPath();
99   if (Path.empty())
100     return;
101
102   // Create a temporary file for the invocation log.
103   SmallString<256> TempPath;
104   TempPath = Path;
105   llvm::sys::path::append(TempPath, "libclang-%%%%%%%%%%%%");
106   int FD;
107   if (llvm::sys::fs::createUniqueFile(TempPath, FD, TempPath))
108     return;
109   File = std::string(TempPath.begin(), TempPath.end());
110   llvm::raw_fd_ostream OS(FD, /*ShouldClose=*/true);
111
112   // Write out the information about the invocation to it.
113   auto WriteStringKey = [&OS](StringRef Key, StringRef Value) {
114     OS << R"(")" << Key << R"(":")";
115     OS << llvm::yaml::escape(Value) << '"';
116   };
117   OS << '{';
118   WriteStringKey("toolchain", Idx.getClangToolchainPath());
119   OS << ',';
120   WriteStringKey("libclang.operation",
121                  Op == OperationKind::ParseOperation ? "parse" : "complete");
122   OS << ',';
123   OS << R"("libclang.opts":)" << ParseOptions;
124   OS << ',';
125   OS << R"("args":[)";
126   for (const auto &I : llvm::enumerate(Args)) {
127     if (I.index())
128       OS << ',';
129     OS << '"' << llvm::yaml::escape(I.value()) << '"';
130   }
131   if (!InvocationArgs.empty()) {
132     OS << R"(],"invocation-args":[)";
133     for (const auto &I : llvm::enumerate(InvocationArgs)) {
134       if (I.index())
135         OS << ',';
136       OS << '"' << llvm::yaml::escape(I.value()) << '"';
137     }
138   }
139   if (!UnsavedFiles.empty()) {
140     OS << R"(],"unsaved_file_hashes":[)";
141     for (const auto &UF : llvm::enumerate(UnsavedFiles)) {
142       if (UF.index())
143         OS << ',';
144       OS << '{';
145       WriteStringKey("name", UF.value().Filename);
146       OS << ',';
147       llvm::MD5 Hash;
148       Hash.update(getContents(UF.value()));
149       llvm::MD5::MD5Result Result;
150       Hash.final(Result);
151       SmallString<32> Digest = Result.digest();
152       WriteStringKey("md5", Digest);
153       OS << '}';
154     }
155   }
156   OS << "]}";
157 }
158
159 LibclangInvocationReporter::~LibclangInvocationReporter() {
160   if (!File.empty())
161     llvm::sys::fs::remove(File);
162 }