 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
56.2% |
54 / 96 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
95.8% |
92 / 96 |
| |
|
Line Coverage: |
81.1% |
120 / 148 |
| |
 |
|
 |
1 : //===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===//
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 hooks for
11 : // code completion.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "CIndexer.h"
16 : #include "CIndexDiagnostic.h"
17 : #include "clang/Frontend/FrontendDiagnostic.h"
18 : #include "clang/Sema/CodeCompleteConsumer.h"
19 : #include "llvm/ADT/StringExtras.h"
20 : #include "llvm/Support/MemoryBuffer.h"
21 : #include "llvm/System/Program.h"
22 :
23 : using namespace clang;
24 :
25 : extern "C" {
26 :
27 : enum CXCompletionChunkKind
28 : clang_getCompletionChunkKind(CXCompletionString completion_string,
29 2263: unsigned chunk_number) {
30 2263: CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
2263: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
2263: branch 4 taken
0: branch 5 not taken
2263: branch 6 taken
31 2263: if (!CCStr || chunk_number >= CCStr->size())
32 0: return CXCompletionChunk_Text;
33 :
1728: branch 1 taken
42: branch 2 taken
1: branch 3 taken
136: branch 4 taken
20: branch 5 taken
90: branch 6 taken
3: branch 7 taken
57: branch 8 taken
57: branch 9 taken
0: branch 10 not taken
0: branch 11 not taken
23: branch 12 taken
23: branch 13 taken
0: branch 14 not taken
0: branch 15 not taken
4: branch 16 taken
0: branch 17 not taken
22: branch 18 taken
0: branch 19 not taken
42: branch 20 taken
15: branch 21 taken
0: branch 22 not taken
34 2263: switch ((*CCStr)[chunk_number].Kind) {
35 : case CodeCompletionString::CK_TypedText:
36 1728: return CXCompletionChunk_TypedText;
37 : case CodeCompletionString::CK_Text:
38 42: return CXCompletionChunk_Text;
39 : case CodeCompletionString::CK_Optional:
40 1: return CXCompletionChunk_Optional;
41 : case CodeCompletionString::CK_Placeholder:
42 136: return CXCompletionChunk_Placeholder;
43 : case CodeCompletionString::CK_Informative:
44 20: return CXCompletionChunk_Informative;
45 : case CodeCompletionString::CK_ResultType:
46 90: return CXCompletionChunk_ResultType;
47 : case CodeCompletionString::CK_CurrentParameter:
48 3: return CXCompletionChunk_CurrentParameter;
49 : case CodeCompletionString::CK_LeftParen:
50 57: return CXCompletionChunk_LeftParen;
51 : case CodeCompletionString::CK_RightParen:
52 57: return CXCompletionChunk_RightParen;
53 : case CodeCompletionString::CK_LeftBracket:
54 0: return CXCompletionChunk_LeftBracket;
55 : case CodeCompletionString::CK_RightBracket:
56 0: return CXCompletionChunk_RightBracket;
57 : case CodeCompletionString::CK_LeftBrace:
58 23: return CXCompletionChunk_LeftBrace;
59 : case CodeCompletionString::CK_RightBrace:
60 23: return CXCompletionChunk_RightBrace;
61 : case CodeCompletionString::CK_LeftAngle:
62 0: return CXCompletionChunk_LeftAngle;
63 : case CodeCompletionString::CK_RightAngle:
64 0: return CXCompletionChunk_RightAngle;
65 : case CodeCompletionString::CK_Comma:
66 4: return CXCompletionChunk_Comma;
67 : case CodeCompletionString::CK_Colon:
68 0: return CXCompletionChunk_Colon;
69 : case CodeCompletionString::CK_SemiColon:
70 22: return CXCompletionChunk_SemiColon;
71 : case CodeCompletionString::CK_Equal:
72 0: return CXCompletionChunk_Equal;
73 : case CodeCompletionString::CK_HorizontalSpace:
74 42: return CXCompletionChunk_HorizontalSpace;
75 : case CodeCompletionString::CK_VerticalSpace:
76 15: return CXCompletionChunk_VerticalSpace;
77 : }
78 :
79 : // Should be unreachable, but let's be careful.
80 0: return CXCompletionChunk_Text;
81 : }
82 :
83 : const char *clang_getCompletionChunkText(CXCompletionString completion_string,
84 2262: unsigned chunk_number) {
85 2262: CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
2262: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
2262: branch 4 taken
0: branch 5 not taken
2262: branch 6 taken
86 2262: if (!CCStr || chunk_number >= CCStr->size())
87 0: return 0;
88 :
2262: branch 1 taken
0: branch 2 not taken
0: branch 3 not taken
89 2262: switch ((*CCStr)[chunk_number].Kind) {
90 : case CodeCompletionString::CK_TypedText:
91 : case CodeCompletionString::CK_Text:
92 : case CodeCompletionString::CK_Placeholder:
93 : case CodeCompletionString::CK_CurrentParameter:
94 : case CodeCompletionString::CK_Informative:
95 : case CodeCompletionString::CK_LeftParen:
96 : case CodeCompletionString::CK_RightParen:
97 : case CodeCompletionString::CK_LeftBracket:
98 : case CodeCompletionString::CK_RightBracket:
99 : case CodeCompletionString::CK_LeftBrace:
100 : case CodeCompletionString::CK_RightBrace:
101 : case CodeCompletionString::CK_LeftAngle:
102 : case CodeCompletionString::CK_RightAngle:
103 : case CodeCompletionString::CK_Comma:
104 : case CodeCompletionString::CK_ResultType:
105 : case CodeCompletionString::CK_Colon:
106 : case CodeCompletionString::CK_SemiColon:
107 : case CodeCompletionString::CK_Equal:
108 : case CodeCompletionString::CK_HorizontalSpace:
109 : case CodeCompletionString::CK_VerticalSpace:
110 2262: return (*CCStr)[chunk_number].Text;
111 :
112 : case CodeCompletionString::CK_Optional:
113 : // Note: treated as an empty text block.
114 0: return "";
115 : }
116 :
117 : // Should be unreachable, but let's be careful.
118 0: return 0;
119 : }
120 :
121 : CXCompletionString
122 : clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
123 1: unsigned chunk_number) {
124 1: CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
1: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
1: branch 4 taken
0: branch 5 not taken
1: branch 6 taken
125 1: if (!CCStr || chunk_number >= CCStr->size())
126 0: return 0;
127 :
0: branch 1 not taken
1: branch 2 taken
0: branch 3 not taken
128 1: switch ((*CCStr)[chunk_number].Kind) {
129 : case CodeCompletionString::CK_TypedText:
130 : case CodeCompletionString::CK_Text:
131 : case CodeCompletionString::CK_Placeholder:
132 : case CodeCompletionString::CK_CurrentParameter:
133 : case CodeCompletionString::CK_Informative:
134 : case CodeCompletionString::CK_LeftParen:
135 : case CodeCompletionString::CK_RightParen:
136 : case CodeCompletionString::CK_LeftBracket:
137 : case CodeCompletionString::CK_RightBracket:
138 : case CodeCompletionString::CK_LeftBrace:
139 : case CodeCompletionString::CK_RightBrace:
140 : case CodeCompletionString::CK_LeftAngle:
141 : case CodeCompletionString::CK_RightAngle:
142 : case CodeCompletionString::CK_Comma:
143 : case CodeCompletionString::CK_ResultType:
144 : case CodeCompletionString::CK_Colon:
145 : case CodeCompletionString::CK_SemiColon:
146 : case CodeCompletionString::CK_Equal:
147 : case CodeCompletionString::CK_HorizontalSpace:
148 : case CodeCompletionString::CK_VerticalSpace:
149 0: return 0;
150 :
151 : case CodeCompletionString::CK_Optional:
152 : // Note: treated as an empty text block.
153 1: return (*CCStr)[chunk_number].Optional;
154 : }
155 :
156 : // Should be unreachable, but let's be careful.
157 0: return 0;
158 : }
159 :
160 1732: unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
161 1732: CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
1732: branch 0 taken
0: branch 1 not taken
162 1732: return CCStr? CCStr->size() : 0;
163 : }
164 :
165 : static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
166 1731: unsigned &Value) {
0: branch 0 not taken
1731: branch 1 taken
167 1731: if (Memory + sizeof(unsigned) > MemoryEnd)
168 0: return true;
169 :
170 1731: memmove(&Value, Memory, sizeof(unsigned));
171 1731: Memory += sizeof(unsigned);
172 1731: return false;
173 : }
174 :
175 : /// \brief The CXCodeCompleteResults structure we allocate internally;
176 : /// the client only sees the initial CXCodeCompleteResults structure.
177 102: struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
178 : /// \brief The memory buffer from which we parsed the results. We
179 : /// retain this buffer because the completion strings point into it.
180 : llvm::MemoryBuffer *Buffer;
181 :
182 : LangOptions LangOpts;
183 : };
184 :
185 : CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
186 : const char *source_filename,
187 : int num_command_line_args,
188 : const char **command_line_args,
189 : unsigned num_unsaved_files,
190 : struct CXUnsavedFile *unsaved_files,
191 : const char *complete_filename,
192 : unsigned complete_line,
193 : unsigned complete_column,
194 : CXDiagnosticCallback diag_callback,
195 51: CXClientData diag_client_data) {
196 : // The indexer, which is mainly used to determine where diagnostics go.
197 51: CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
198 :
199 : // Configure the diagnostics.
200 51: DiagnosticOptions DiagOpts;
201 51: llvm::OwningPtr<Diagnostic> Diags;
202 51: Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
203 51: CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
204 51: Diags->setClient(&DiagClient);
205 :
206 : // The set of temporary files that we've built.
207 51: std::vector<llvm::sys::Path> TemporaryFiles;
208 :
209 : // Build up the arguments for invoking 'clang'.
210 51: std::vector<const char *> argv;
211 :
212 : // First add the complete path to the 'clang' executable.
213 51: llvm::sys::Path ClangPath = CXXIdx->getClangPath();
214 51: argv.push_back(ClangPath.c_str());
215 :
216 : // Add the '-fsyntax-only' argument so that we only perform a basic
217 : // syntax check of the code.
218 51: argv.push_back("-fsyntax-only");
219 :
220 : // Add the appropriate '-code-completion-at=file:line:column' argument
221 : // to perform code completion, with an "-Xclang" preceding it.
222 51: std::string code_complete_at;
223 51: code_complete_at += complete_filename;
224 51: code_complete_at += ":";
225 51: code_complete_at += llvm::utostr(complete_line);
226 51: code_complete_at += ":";
227 51: code_complete_at += llvm::utostr(complete_column);
228 51: argv.push_back("-Xclang");
229 51: argv.push_back("-code-completion-at");
230 51: argv.push_back("-Xclang");
231 51: argv.push_back(code_complete_at.c_str());
232 51: argv.push_back("-Xclang");
233 51: argv.push_back("-no-code-completion-debug-printer");
234 51: argv.push_back("-Xclang");
235 51: argv.push_back("-code-completion-macros");
236 51: argv.push_back("-fdiagnostics-binary");
237 :
238 : // Remap any unsaved files to temporary files.
239 51: std::vector<std::string> RemapArgs;
0: branch 1 not taken
51: branch 2 taken
240 51: if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
241 0: return 0;
242 :
243 : // The pointers into the elements of RemapArgs are stable because we
244 : // won't be adding anything to RemapArgs after this point.
4: branch 1 taken
51: branch 2 taken
245 55: for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
246 4: argv.push_back(RemapArgs[i].c_str());
247 :
248 : // Add the source file name (FIXME: later, we'll want to build temporary
249 : // file from the buffer, or just feed the source text via standard input).
51: branch 0 taken
0: branch 1 not taken
250 51: if (source_filename)
251 51: argv.push_back(source_filename);
252 :
253 : // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
1: branch 0 taken
51: branch 1 taken
254 52: for (int i = 0; i < num_command_line_args; ++i)
1: branch 0 taken
0: branch 1 not taken
255 1: if (const char *arg = command_line_args[i]) {
0: branch 1 not taken
1: branch 2 taken
256 1: if (strcmp(arg, "-o") == 0) {
257 0: ++i; // Also skip the matching argument.
258 0: continue;
259 : }
1: branch 1 taken
0: branch 2 not taken
1: branch 4 taken
0: branch 5 not taken
0: branch 7 not taken
1: branch 8 taken
260 1: if (strcmp(arg, "-emit-ast") == 0 ||
261 : strcmp(arg, "-c") == 0 ||
262 : strcmp(arg, "-fsyntax-only") == 0) {
263 0: continue;
264 : }
265 :
266 : // Keep the argument.
267 1: argv.push_back(arg);
268 : }
269 :
270 : // Add the null terminator.
271 51: argv.push_back(NULL);
272 :
273 : // Generate a temporary name for the code-completion results file.
274 : char tmpFile[L_tmpnam];
275 51: char *tmpFileName = tmpnam(tmpFile);
276 51: llvm::sys::Path ResultsFile(tmpFileName);
277 51: TemporaryFiles.push_back(ResultsFile);
278 :
279 : // Generate a temporary name for the diagnostics file.
280 : char tmpFileResults[L_tmpnam];
281 51: char *tmpResultsFileName = tmpnam(tmpFileResults);
282 51: llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
283 51: TemporaryFiles.push_back(DiagnosticsFile);
284 :
285 : // Invoke 'clang'.
286 51: llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
287 : // on Unix or NUL (Windows).
288 51: std::string ErrMsg;
289 : const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
290 51: &DiagnosticsFile, 0 };
291 : llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
292 : /* redirects */ &Redirects[0],
293 : /* secondsToWait */ 0,
294 51: /* memoryLimits */ 0, &ErrMsg);
295 :
0: branch 1 not taken
51: branch 2 taken
296 51: if (!ErrMsg.empty()) {
297 0: std::string AllArgs;
0: branch 4 not taken
0: branch 5 not taken
298 0: for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
299 : I != E; ++I) {
300 0: AllArgs += ' ';
0: branch 1 not taken
0: branch 2 not taken
301 0: if (*I)
302 0: AllArgs += *I;
303 : }
304 :
305 0: Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
306 : }
307 :
308 : // Parse the resulting source file to find code-completion results.
309 : using llvm::MemoryBuffer;
310 : using llvm::StringRef;
311 51: AllocatedCXCodeCompleteResults *Results = 0;
51: branch 3 taken
0: branch 4 not taken
312 51: if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
313 51: llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
314 51: StringRef Buffer = F->getBuffer();
1731: branch 2 taken
51: branch 3 taken
315 1833: for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
316 : Str < StrEnd;) {
317 : unsigned KindValue;
0: branch 1 not taken
1731: branch 2 taken
318 1731: if (ReadUnsigned(Str, StrEnd, KindValue))
319 0: break;
320 :
321 : CodeCompletionString *CCStr
322 1731: = CodeCompletionString::Deserialize(Str, StrEnd);
0: branch 0 not taken
1731: branch 1 taken
323 1731: if (!CCStr)
324 0: continue;
325 :
1731: branch 1 taken
0: branch 2 not taken
326 1731: if (!CCStr->empty()) {
327 : // Vend the code-completion result to the caller.
328 : CXCompletionResult Result;
329 1731: Result.CursorKind = (CXCursorKind)KindValue;
330 1731: Result.CompletionString = CCStr;
331 1731: CompletionResults.push_back(Result);
332 : }
333 : };
334 :
335 : // Allocate the results.
336 51: Results = new AllocatedCXCodeCompleteResults;
337 51: Results->Results = new CXCompletionResult [CompletionResults.size()];
338 51: Results->NumResults = CompletionResults.size();
339 : memcpy(Results->Results, CompletionResults.data(),
340 51: CompletionResults.size() * sizeof(CXCompletionResult));
341 51: Results->Buffer = F;
342 : }
343 :
344 : // FIXME: The LangOptions we are passing here are not at all correct. However,
345 : // in the current design we must pass something in so the SourceLocations have
346 : // a LangOptions object to refer to.
347 : ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
348 : num_unsaved_files, unsaved_files,
349 51: Results->LangOpts);
350 :
103: branch 1 taken
51: branch 2 taken
351 154: for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
352 103: TemporaryFiles[i].eraseFromDisk();
353 :
354 51: return Results;
355 : }
356 :
357 51: void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
0: branch 0 not taken
51: branch 1 taken
358 51: if (!ResultsIn)
359 0: return;
360 :
361 : AllocatedCXCodeCompleteResults *Results
362 51: = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
363 :
1731: branch 0 taken
51: branch 1 taken
364 1782: for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
365 1731: delete (CXCompletionString *)Results->Results[I].CompletionString;
51: branch 0 taken
0: branch 1 not taken
366 51: delete [] Results->Results;
367 :
368 51: Results->Results = 0;
369 51: Results->NumResults = 0;
51: branch 0 taken
0: branch 1 not taken
370 51: delete Results->Buffer;
371 51: Results->Buffer = 0;
51: branch 0 taken
0: branch 1 not taken
372 51: delete Results;
373 : }
374 :
375 : } // end extern "C"
Generated: 2010-02-10 01:31 by zcov