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