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