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