CIndexer.cpp revision f59edb96b2d0bfe612b732f19519ab84bb995bd4
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 "clang/AST/Decl.h"
16#include "clang/AST/DeclVisitor.h"
17#include "clang/AST/StmtVisitor.h"
18#include "clang/Basic/FileManager.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Basic/Version.h"
21#include "clang/Sema/CodeCompleteConsumer.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Config/llvm-config.h"
24#include "llvm/Support/Compiler.h"
25#include "llvm/Support/MemoryBuffer.h"
26#include "llvm/Support/Program.h"
27#include "llvm/Support/raw_ostream.h"
28#include <cstdio>
29#include <sstream>
30#include <vector>
31
32#ifdef __CYGWIN__
33#include <cygwin/version.h>
34#include <sys/cygwin.h>
35#define LLVM_ON_WIN32 1
36#endif
37
38#ifdef LLVM_ON_WIN32
39#include <windows.h>
40#else
41#include <dlfcn.h>
42#endif
43
44using namespace clang;
45
46std::string CIndexer::getClangResourcesPath() {
47  // Did we already compute the path?
48  if (!ResourcesPath.empty())
49    return ResourcesPath.str();
50
51  // Find the location where this library lives (libclang.dylib).
52#ifdef LLVM_ON_WIN32
53  MEMORY_BASIC_INFORMATION mbi;
54  char path[MAX_PATH];
55  VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
56               sizeof(mbi));
57  GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
58
59#ifdef __CYGWIN__
60  char w32path[MAX_PATH];
61  strcpy(w32path, path);
62#if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181
63  cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH);
64#else
65  cygwin_conv_to_full_posix_path(w32path, path);
66#endif
67#endif
68
69  llvm::sys::Path LibClangPath(path);
70  LibClangPath.eraseComponent();
71#else
72  // This silly cast below avoids a C++ warning.
73  Dl_info info;
74  if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
75    llvm_unreachable("Call to dladdr() failed");
76
77  llvm::sys::Path LibClangPath(info.dli_fname);
78
79  // We now have the CIndex directory, locate clang relative to it.
80  LibClangPath.eraseComponent();
81#endif
82
83  LibClangPath.appendComponent("clang");
84  LibClangPath.appendComponent(CLANG_VERSION_STRING);
85
86  // Cache our result.
87  ResourcesPath = LibClangPath;
88  return LibClangPath.str();
89}
90
91static llvm::sys::Path GetTemporaryPath() {
92  // FIXME: This is lame; sys::Path should provide this function (in particular,
93  // it should know how to find the temporary files dir).
94  std::string Error;
95  const char *TmpDir = ::getenv("TMPDIR");
96  if (!TmpDir)
97    TmpDir = ::getenv("TEMP");
98  if (!TmpDir)
99    TmpDir = ::getenv("TMP");
100  if (!TmpDir)
101    TmpDir = "/tmp";
102  llvm::sys::Path P(TmpDir);
103  P.appendComponent("remap");
104  if (P.makeUnique(false, &Error))
105    return llvm::sys::Path("");
106
107  // FIXME: Grumble, makeUnique sometimes leaves the file around!?  PR3837.
108  P.eraseFromDisk(false, 0);
109
110  return P;
111}
112
113bool clang::RemapFiles(unsigned num_unsaved_files,
114                       struct CXUnsavedFile *unsaved_files,
115                       std::vector<std::string> &RemapArgs,
116                       std::vector<llvm::sys::Path> &TemporaryFiles) {
117  for (unsigned i = 0; i != num_unsaved_files; ++i) {
118    // Write the contents of this unsaved file into the temporary file.
119    llvm::sys::Path SavedFile(GetTemporaryPath());
120    if (SavedFile.empty())
121      return true;
122
123    std::string ErrorInfo;
124    llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo,
125                            llvm::raw_fd_ostream::F_Binary);
126    if (!ErrorInfo.empty())
127      return true;
128
129    OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
130    OS.close();
131    if (OS.has_error()) {
132      SavedFile.eraseFromDisk();
133      OS.clear_error();
134      return true;
135    }
136
137    // Remap the file.
138    std::string RemapArg = unsaved_files[i].Filename;
139    RemapArg += ';';
140    RemapArg += SavedFile.str();
141    RemapArgs.push_back("-Xclang");
142    RemapArgs.push_back("-remap-file");
143    RemapArgs.push_back("-Xclang");
144    RemapArgs.push_back(RemapArg);
145    TemporaryFiles.push_back(SavedFile);
146  }
147
148  return false;
149}
150
151