blob: d5131ff6d86964c490dd911ab120388ffb6cdd5b [file] [log] [blame]
Ted Kremenekab188932010-01-05 19:32:54 +00001//===- 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/System/Program.h"
29
30#include <cstdio>
31#include <vector>
32#include <sstream>
33
34#ifdef LLVM_ON_WIN32
35#include <windows.h>
36#else
37#include <dlfcn.h>
38#endif
39
40using namespace clang;
Ted Kremenekab188932010-01-05 19:32:54 +000041
42const llvm::sys::Path& CIndexer::getClangPath() {
43 // Did we already compute the path?
44 if (!ClangPath.empty())
45 return ClangPath;
46
47 // Find the location where this library lives (libCIndex.dylib).
48#ifdef LLVM_ON_WIN32
49 MEMORY_BASIC_INFORMATION mbi;
50 char path[MAX_PATH];
51 VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
52 sizeof(mbi));
53 GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
54
55 llvm::sys::Path CIndexPath(path);
56
57 CIndexPath.eraseComponent();
58 CIndexPath.appendComponent("clang");
59 CIndexPath.appendSuffix("exe");
60 CIndexPath.makeAbsolute();
61#else
62 // This silly cast below avoids a C++ warning.
63 Dl_info info;
64 if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
65 assert(0 && "Call to dladdr() failed");
66
67 llvm::sys::Path CIndexPath(info.dli_fname);
68
69 // We now have the CIndex directory, locate clang relative to it.
70 CIndexPath.eraseComponent();
Chandler Carruthf1f70b42010-01-27 07:37:16 +000071 CIndexPath.appendComponent("..");
Ted Kremenekab188932010-01-05 19:32:54 +000072 CIndexPath.appendComponent("bin");
73 CIndexPath.appendComponent("clang");
74#endif
75
76 // Cache our result.
77 ClangPath = CIndexPath;
78 return ClangPath;
79}
80
81std::string CIndexer::getClangResourcesPath() {
82 llvm::sys::Path P = getClangPath();
83
84 if (!P.empty()) {
85 P.eraseComponent(); // Remove /clang from foo/bin/clang
86 P.eraseComponent(); // Remove /bin from foo/bin
87
88 // Get foo/lib/clang/<version>/include
89 P.appendComponent("lib");
90 P.appendComponent("clang");
91 P.appendComponent(CLANG_VERSION_STRING);
92 }
93
94 return P.str();
95}
Douglas Gregor4db64a42010-01-23 00:14:00 +000096
Benjamin Kramerc2a98162010-03-13 21:22:49 +000097static llvm::sys::Path GetTemporaryPath() {
Daniel Dunbar74198af2010-02-02 05:19:57 +000098 // FIXME: This is lame; sys::Path should provide this function (in particular,
99 // it should know how to find the temporary files dir).
100 std::string Error;
101 const char *TmpDir = ::getenv("TMPDIR");
102 if (!TmpDir)
103 TmpDir = ::getenv("TEMP");
104 if (!TmpDir)
105 TmpDir = ::getenv("TMP");
106 if (!TmpDir)
107 TmpDir = "/tmp";
108 llvm::sys::Path P(TmpDir);
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000109 P.appendComponent("remap");
Daniel Dunbar74198af2010-02-02 05:19:57 +0000110 if (P.makeUnique(false, &Error))
111 return llvm::sys::Path("");
112
113 // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837.
114 P.eraseFromDisk(false, 0);
115
116 return P;
117}
118
Douglas Gregor4db64a42010-01-23 00:14:00 +0000119bool clang::RemapFiles(unsigned num_unsaved_files,
120 struct CXUnsavedFile *unsaved_files,
121 std::vector<std::string> &RemapArgs,
122 std::vector<llvm::sys::Path> &TemporaryFiles) {
123 for (unsigned i = 0; i != num_unsaved_files; ++i) {
Douglas Gregor4db64a42010-01-23 00:14:00 +0000124 // Write the contents of this unsaved file into the temporary file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000125 llvm::sys::Path SavedFile(GetTemporaryPath());
Daniel Dunbar74198af2010-02-02 05:19:57 +0000126 if (SavedFile.empty())
127 return true;
128
Douglas Gregor4db64a42010-01-23 00:14:00 +0000129 std::string ErrorInfo;
130 llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
131 if (!ErrorInfo.empty())
132 return true;
133
134 OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
135 OS.close();
136 if (OS.has_error()) {
137 SavedFile.eraseFromDisk();
138 return true;
139 }
140
141 // Remap the file.
142 std::string RemapArg = unsaved_files[i].Filename;
143 RemapArg += ';';
Daniel Dunbar74198af2010-02-02 05:19:57 +0000144 RemapArg += SavedFile.str();
Douglas Gregor4db64a42010-01-23 00:14:00 +0000145 RemapArgs.push_back("-Xclang");
146 RemapArgs.push_back("-remap-file");
147 RemapArgs.push_back("-Xclang");
148 RemapArgs.push_back(RemapArg);
149 TemporaryFiles.push_back(SavedFile);
150 }
151
152 return false;
153}
154