CIndexCodeCompletion.cpp revision 21c241ff68c18ad87e1f18a579c535385aec7af1
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/Basic/SourceManager.h"
18#include "clang/Basic/FileManager.h"
19#include "clang/Frontend/CompilerInstance.h"
20#include "clang/Frontend/FrontendDiagnostic.h"
21#include "clang/Sema/CodeCompleteConsumer.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/System/Program.h"
25
26#ifdef UDP_CODE_COMPLETION_LOGGER
27#include "clang/Basic/Version.h"
28#include "llvm/ADT/SmallString.h"
29#include "llvm/Support/Timer.h"
30#include "llvm/Support/raw_ostream.h"
31#include <arpa/inet.h>
32#include <sys/socket.h>
33#include <sys/types.h>
34#include <unistd.h>
35#endif
36
37using namespace clang;
38using namespace clang::cxstring;
39
40extern "C" {
41
42enum CXCompletionChunkKind
43clang_getCompletionChunkKind(CXCompletionString completion_string,
44                             unsigned chunk_number) {
45  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
46  if (!CCStr || chunk_number >= CCStr->size())
47    return CXCompletionChunk_Text;
48
49  switch ((*CCStr)[chunk_number].Kind) {
50  case CodeCompletionString::CK_TypedText:
51    return CXCompletionChunk_TypedText;
52  case CodeCompletionString::CK_Text:
53    return CXCompletionChunk_Text;
54  case CodeCompletionString::CK_Optional:
55    return CXCompletionChunk_Optional;
56  case CodeCompletionString::CK_Placeholder:
57    return CXCompletionChunk_Placeholder;
58  case CodeCompletionString::CK_Informative:
59    return CXCompletionChunk_Informative;
60  case CodeCompletionString::CK_ResultType:
61    return CXCompletionChunk_ResultType;
62  case CodeCompletionString::CK_CurrentParameter:
63    return CXCompletionChunk_CurrentParameter;
64  case CodeCompletionString::CK_LeftParen:
65    return CXCompletionChunk_LeftParen;
66  case CodeCompletionString::CK_RightParen:
67    return CXCompletionChunk_RightParen;
68  case CodeCompletionString::CK_LeftBracket:
69    return CXCompletionChunk_LeftBracket;
70  case CodeCompletionString::CK_RightBracket:
71    return CXCompletionChunk_RightBracket;
72  case CodeCompletionString::CK_LeftBrace:
73    return CXCompletionChunk_LeftBrace;
74  case CodeCompletionString::CK_RightBrace:
75    return CXCompletionChunk_RightBrace;
76  case CodeCompletionString::CK_LeftAngle:
77    return CXCompletionChunk_LeftAngle;
78  case CodeCompletionString::CK_RightAngle:
79    return CXCompletionChunk_RightAngle;
80  case CodeCompletionString::CK_Comma:
81    return CXCompletionChunk_Comma;
82  case CodeCompletionString::CK_Colon:
83    return CXCompletionChunk_Colon;
84  case CodeCompletionString::CK_SemiColon:
85    return CXCompletionChunk_SemiColon;
86  case CodeCompletionString::CK_Equal:
87    return CXCompletionChunk_Equal;
88  case CodeCompletionString::CK_HorizontalSpace:
89    return CXCompletionChunk_HorizontalSpace;
90  case CodeCompletionString::CK_VerticalSpace:
91    return CXCompletionChunk_VerticalSpace;
92  }
93
94  // Should be unreachable, but let's be careful.
95  return CXCompletionChunk_Text;
96}
97
98CXString clang_getCompletionChunkText(CXCompletionString completion_string,
99                                      unsigned chunk_number) {
100  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
101  if (!CCStr || chunk_number >= CCStr->size())
102    return createCXString(0);
103
104  switch ((*CCStr)[chunk_number].Kind) {
105  case CodeCompletionString::CK_TypedText:
106  case CodeCompletionString::CK_Text:
107  case CodeCompletionString::CK_Placeholder:
108  case CodeCompletionString::CK_CurrentParameter:
109  case CodeCompletionString::CK_Informative:
110  case CodeCompletionString::CK_LeftParen:
111  case CodeCompletionString::CK_RightParen:
112  case CodeCompletionString::CK_LeftBracket:
113  case CodeCompletionString::CK_RightBracket:
114  case CodeCompletionString::CK_LeftBrace:
115  case CodeCompletionString::CK_RightBrace:
116  case CodeCompletionString::CK_LeftAngle:
117  case CodeCompletionString::CK_RightAngle:
118  case CodeCompletionString::CK_Comma:
119  case CodeCompletionString::CK_ResultType:
120  case CodeCompletionString::CK_Colon:
121  case CodeCompletionString::CK_SemiColon:
122  case CodeCompletionString::CK_Equal:
123  case CodeCompletionString::CK_HorizontalSpace:
124    return createCXString((*CCStr)[chunk_number].Text, false);
125
126  case CodeCompletionString::CK_VerticalSpace:
127    // FIXME: Temporary hack until we figure out how to handle vertical space.
128    return createCXString(" ");
129
130  case CodeCompletionString::CK_Optional:
131    // Note: treated as an empty text block.
132    return createCXString("");
133  }
134
135  // Should be unreachable, but let's be careful.
136  return createCXString(0);
137}
138
139
140CXCompletionString
141clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
142                                         unsigned chunk_number) {
143  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
144  if (!CCStr || chunk_number >= CCStr->size())
145    return 0;
146
147  switch ((*CCStr)[chunk_number].Kind) {
148  case CodeCompletionString::CK_TypedText:
149  case CodeCompletionString::CK_Text:
150  case CodeCompletionString::CK_Placeholder:
151  case CodeCompletionString::CK_CurrentParameter:
152  case CodeCompletionString::CK_Informative:
153  case CodeCompletionString::CK_LeftParen:
154  case CodeCompletionString::CK_RightParen:
155  case CodeCompletionString::CK_LeftBracket:
156  case CodeCompletionString::CK_RightBracket:
157  case CodeCompletionString::CK_LeftBrace:
158  case CodeCompletionString::CK_RightBrace:
159  case CodeCompletionString::CK_LeftAngle:
160  case CodeCompletionString::CK_RightAngle:
161  case CodeCompletionString::CK_Comma:
162  case CodeCompletionString::CK_ResultType:
163  case CodeCompletionString::CK_Colon:
164  case CodeCompletionString::CK_SemiColon:
165  case CodeCompletionString::CK_Equal:
166  case CodeCompletionString::CK_HorizontalSpace:
167  case CodeCompletionString::CK_VerticalSpace:
168    return 0;
169
170  case CodeCompletionString::CK_Optional:
171    // Note: treated as an empty text block.
172    return (*CCStr)[chunk_number].Optional;
173  }
174
175  // Should be unreachable, but let's be careful.
176  return 0;
177}
178
179unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
180  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
181  return CCStr? CCStr->size() : 0;
182}
183
184static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
185                         unsigned &Value) {
186  if (Memory + sizeof(unsigned) > MemoryEnd)
187    return true;
188
189  memmove(&Value, Memory, sizeof(unsigned));
190  Memory += sizeof(unsigned);
191  return false;
192}
193
194/// \brief The CXCodeCompleteResults structure we allocate internally;
195/// the client only sees the initial CXCodeCompleteResults structure.
196struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
197  AllocatedCXCodeCompleteResults();
198  ~AllocatedCXCodeCompleteResults();
199
200  /// \brief The memory buffer from which we parsed the results. We
201  /// retain this buffer because the completion strings point into it.
202  llvm::MemoryBuffer *Buffer;
203
204  /// \brief Diagnostics produced while performing code completion.
205  llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
206
207  /// \brief Diag object
208  Diagnostic Diag;
209
210  /// \brief Language options used to adjust source locations.
211  LangOptions LangOpts;
212
213  /// \brief Source manager, used for diagnostics.
214  SourceManager SourceMgr;
215
216  /// \brief File manager, used for diagnostics.
217  FileManager FileMgr;
218
219  /// \brief Temporary files that should be removed once we have finished
220  /// with the code-completion results.
221  std::vector<llvm::sys::Path> TemporaryFiles;
222};
223
224AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
225  : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { }
226
227AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
228  for (unsigned I = 0, N = NumResults; I != N; ++I)
229    delete (CodeCompletionString *)Results[I].CompletionString;
230  delete [] Results;
231  delete Buffer;
232
233  for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
234    TemporaryFiles[I].eraseFromDisk();
235}
236
237CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
238                                          const char *source_filename,
239                                          int num_command_line_args,
240                                          const char **command_line_args,
241                                          unsigned num_unsaved_files,
242                                          struct CXUnsavedFile *unsaved_files,
243                                          const char *complete_filename,
244                                          unsigned complete_line,
245                                          unsigned complete_column) {
246#ifdef UDP_CODE_COMPLETION_LOGGER
247#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
248  const llvm::TimeRecord &StartTime =  llvm::TimeRecord::getCurrentTime();
249#endif
250#endif
251
252  // The indexer, which is mainly used to determine where diagnostics go.
253  CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
254
255  // Configure the diagnostics.
256  DiagnosticOptions DiagOpts;
257  llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
258  Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
259
260  // The set of temporary files that we've built.
261  std::vector<llvm::sys::Path> TemporaryFiles;
262
263  // Build up the arguments for invoking 'clang'.
264  std::vector<const char *> argv;
265
266  // First add the complete path to the 'clang' executable.
267  llvm::sys::Path ClangPath = CXXIdx->getClangPath();
268  argv.push_back(ClangPath.c_str());
269
270  // Add the '-fsyntax-only' argument so that we only perform a basic
271  // syntax check of the code.
272  argv.push_back("-fsyntax-only");
273
274  // Add the appropriate '-code-completion-at=file:line:column' argument
275  // to perform code completion, with an "-Xclang" preceding it.
276  std::string code_complete_at;
277  code_complete_at += complete_filename;
278  code_complete_at += ":";
279  code_complete_at += llvm::utostr(complete_line);
280  code_complete_at += ":";
281  code_complete_at += llvm::utostr(complete_column);
282  argv.push_back("-Xclang");
283  argv.push_back("-code-completion-at");
284  argv.push_back("-Xclang");
285  argv.push_back(code_complete_at.c_str());
286  argv.push_back("-Xclang");
287  argv.push_back("-no-code-completion-debug-printer");
288  argv.push_back("-Xclang");
289  argv.push_back("-code-completion-macros");
290  argv.push_back("-fdiagnostics-binary");
291
292  // Remap any unsaved files to temporary files.
293  std::vector<std::string> RemapArgs;
294  if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
295    return 0;
296
297  // The pointers into the elements of RemapArgs are stable because we
298  // won't be adding anything to RemapArgs after this point.
299  for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
300    argv.push_back(RemapArgs[i].c_str());
301
302  // Add the source file name (FIXME: later, we'll want to build temporary
303  // file from the buffer, or just feed the source text via standard input).
304  if (source_filename)
305    argv.push_back(source_filename);
306
307  // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
308  for (int i = 0; i < num_command_line_args; ++i)
309    if (const char *arg = command_line_args[i]) {
310      if (strcmp(arg, "-o") == 0) {
311        ++i; // Also skip the matching argument.
312        continue;
313      }
314      if (strcmp(arg, "-emit-ast") == 0 ||
315          strcmp(arg, "-c") == 0 ||
316          strcmp(arg, "-fsyntax-only") == 0) {
317        continue;
318      }
319
320      // Keep the argument.
321      argv.push_back(arg);
322    }
323
324  // Add the null terminator.
325  argv.push_back(NULL);
326
327  // Generate a temporary name for the code-completion results file.
328  char tmpFile[L_tmpnam];
329  char *tmpFileName = tmpnam(tmpFile);
330  llvm::sys::Path ResultsFile(tmpFileName);
331  TemporaryFiles.push_back(ResultsFile);
332
333  // Generate a temporary name for the diagnostics file.
334  char tmpFileResults[L_tmpnam];
335  char *tmpResultsFileName = tmpnam(tmpFileResults);
336  llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
337  TemporaryFiles.push_back(DiagnosticsFile);
338
339  // Invoke 'clang'.
340  llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
341                           // on Unix or NUL (Windows).
342  std::string ErrMsg;
343  const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
344                                         &DiagnosticsFile, 0 };
345  llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
346                                     /* redirects */ &Redirects[0],
347                                     /* secondsToWait */ 0,
348                                     /* memoryLimits */ 0, &ErrMsg);
349
350  if (!ErrMsg.empty()) {
351    std::string AllArgs;
352    for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
353         I != E; ++I) {
354      AllArgs += ' ';
355      if (*I)
356        AllArgs += *I;
357    }
358
359    Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
360  }
361
362  // Parse the resulting source file to find code-completion results.
363  using llvm::MemoryBuffer;
364  using llvm::StringRef;
365  AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
366  Results->Results = 0;
367  Results->NumResults = 0;
368  Results->Buffer = 0;
369  // FIXME: Set Results->LangOpts!
370  if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
371    llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
372    StringRef Buffer = F->getBuffer();
373    for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
374         Str < StrEnd;) {
375      unsigned KindValue;
376      if (ReadUnsigned(Str, StrEnd, KindValue))
377        break;
378
379      CodeCompletionString *CCStr
380        = CodeCompletionString::Deserialize(Str, StrEnd);
381      if (!CCStr)
382        continue;
383
384      if (!CCStr->empty()) {
385        // Vend the code-completion result to the caller.
386        CXCompletionResult Result;
387        Result.CursorKind = (CXCursorKind)KindValue;
388        Result.CompletionString = CCStr;
389        CompletionResults.push_back(Result);
390      }
391    };
392
393    // Allocate the results.
394    Results->Results = new CXCompletionResult [CompletionResults.size()];
395    Results->NumResults = CompletionResults.size();
396    memcpy(Results->Results, CompletionResults.data(),
397           CompletionResults.size() * sizeof(CXCompletionResult));
398    Results->Buffer = F;
399  }
400
401  LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
402                            Results->FileMgr, Results->SourceMgr,
403                            Results->Diagnostics);
404
405  // Make sure we delete temporary files when the code-completion results are
406  // destroyed.
407  Results->TemporaryFiles.swap(TemporaryFiles);
408
409#ifdef UDP_CODE_COMPLETION_LOGGER
410#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
411  const llvm::TimeRecord &EndTime =  llvm::TimeRecord::getCurrentTime();
412  llvm::SmallString<256> LogResult;
413  llvm::raw_svector_ostream os(LogResult);
414
415  // Figure out the language and whether or not it uses PCH.
416  const char *lang = 0;
417  bool usesPCH = false;
418
419  for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
420       I != E; ++I) {
421    if (*I == 0)
422      continue;
423    if (strcmp(*I, "-x") == 0) {
424      if (I + 1 != E) {
425        lang = *(++I);
426        continue;
427      }
428    }
429    else if (strcmp(*I, "-include") == 0) {
430      if (I+1 != E) {
431        const char *arg = *(++I);
432        llvm::SmallString<512> pchName;
433        {
434          llvm::raw_svector_ostream os(pchName);
435          os << arg << ".pth";
436        }
437        pchName.push_back('\0');
438        struct stat stat_results;
439        if (stat(pchName.data(), &stat_results) == 0)
440          usesPCH = true;
441        continue;
442      }
443    }
444  }
445
446  os << "{ ";
447  os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
448  os << ", \"numRes\": " << Results->NumResults;
449  os << ", \"diags\": " << Results->Diagnostics.size();
450  os << ", \"pch\": " << (usesPCH ? "true" : "false");
451  os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
452  const char *name = getlogin();
453  os << ", \"user\": \"" << (name ? name : "unknown") << '"';
454  os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
455  os << " }";
456
457  llvm::StringRef res = os.str();
458  if (res.size() > 0) {
459    do {
460      // Setup the UDP socket.
461      struct sockaddr_in servaddr;
462      bzero(&servaddr, sizeof(servaddr));
463      servaddr.sin_family = AF_INET;
464      servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
465      if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
466                    &servaddr.sin_addr) <= 0)
467        break;
468
469      int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
470      if (sockfd < 0)
471        break;
472
473      sendto(sockfd, res.data(), res.size(), 0,
474             (struct sockaddr *)&servaddr, sizeof(servaddr));
475      close(sockfd);
476    }
477    while (false);
478  }
479#endif
480#endif
481  return Results;
482}
483
484void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
485  if (!ResultsIn)
486    return;
487
488  AllocatedCXCodeCompleteResults *Results
489    = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
490  delete Results;
491}
492
493unsigned
494clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
495  AllocatedCXCodeCompleteResults *Results
496    = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
497  if (!Results)
498    return 0;
499
500  return Results->Diagnostics.size();
501}
502
503CXDiagnostic
504clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
505                                unsigned Index) {
506  AllocatedCXCodeCompleteResults *Results
507    = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
508  if (!Results || Index >= Results->Diagnostics.size())
509    return 0;
510
511  return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
512}
513
514
515} // end extern "C"
516