Example #1
0
static bool swiftCodeCompleteImpl(SwiftLangSupport &Lang,
                                  llvm::MemoryBuffer *UnresolvedInputFile,
                                  unsigned Offset,
                                  SwiftCodeCompletionConsumer &SwiftConsumer,
                                  ArrayRef<const char *> Args,
                                  std::string &Error) {

  trace::TracedOperation TracedOp;
  if (trace::enabled()) {
    trace::SwiftInvocation SwiftArgs;
    trace::initTraceInfo(SwiftArgs,
                         UnresolvedInputFile->getBufferIdentifier(),
                         Args);
    SwiftArgs.addFile(UnresolvedInputFile->getBufferIdentifier(),
                      UnresolvedInputFile->getBuffer());

    TracedOp.start(trace::OperationKind::CodeCompletionInit, SwiftArgs,
                   { std::make_pair("Offset", std::to_string(Offset)),
                     std::make_pair("InputBufferSize",
                                    std::to_string(UnresolvedInputFile->getBufferSize()))});
  }
  
  // Resolve symlinks for the input file; we resolve them for the input files
  // in the arguments as well.
  // FIXME: We need the Swift equivalent of Clang's FileEntry.
  auto InputFile = llvm::MemoryBuffer::getMemBuffer(
      UnresolvedInputFile->getBuffer(),
      Lang.resolvePathSymlinks(UnresolvedInputFile->getBufferIdentifier()));

  CompilerInstance CI;
  // Display diagnostics to stderr.
  PrintingDiagnosticConsumer PrintDiags;
  CI.addDiagnosticConsumer(&PrintDiags);

  CompilerInvocation Invocation;
  bool Failed = Lang.getASTManager().initCompilerInvocation(
      Invocation, Args, CI.getDiags(), InputFile->getBufferIdentifier(), Error);
  if (Failed) {
    return false;
  }
  if (Invocation.getInputFilenames().empty()) {
    Error = "no input filenames specified";
    return false;
  }

  auto origBuffSize = InputFile->getBufferSize();
  unsigned CodeCompletionOffset = Offset;
  if (CodeCompletionOffset > origBuffSize) {
    CodeCompletionOffset = origBuffSize;
  }

  const char *Position = InputFile->getBufferStart() + CodeCompletionOffset;
  std::unique_ptr<llvm::MemoryBuffer> NewBuffer =
      llvm::MemoryBuffer::getNewUninitMemBuffer(InputFile->getBufferSize() + 1,
                                              InputFile->getBufferIdentifier());
  char *NewBuf = const_cast<char*>(NewBuffer->getBufferStart());
  char *NewPos = std::copy(InputFile->getBufferStart(), Position, NewBuf);
  *NewPos = '\0';
  std::copy(Position, InputFile->getBufferEnd(), NewPos+1);

  Invocation.setCodeCompletionPoint(NewBuffer.get(), CodeCompletionOffset);

  auto swiftCache = Lang.getCodeCompletionCache(); // Pin the cache.
  ide::CodeCompletionContext CompletionContext(swiftCache->getCache());

  // Create a factory for code completion callbacks that will feed the
  // Consumer.
  std::unique_ptr<CodeCompletionCallbacksFactory> CompletionCallbacksFactory(
      ide::makeCodeCompletionCallbacksFactory(CompletionContext,
                                              SwiftConsumer));

  Invocation.setCodeCompletionFactory(CompletionCallbacksFactory.get());

  // FIXME: We need to be passing the buffers from the open documents.
  // It is not a huge problem in practice because Xcode auto-saves constantly.

  if (CI.setup(Invocation)) {
    // FIXME: error?
    return true;
  }

  TracedOp.finish();

  if (trace::enabled()) {
    trace::SwiftInvocation SwiftArgs;
    trace::initTraceInfo(SwiftArgs, InputFile->getBufferIdentifier(), Args);
    trace::initTraceFiles(SwiftArgs, CI);

    // Replace primary file with original content
    std::for_each(SwiftArgs.Files.begin(), SwiftArgs.Files.end(),
                  [&] (trace::StringPairs::value_type &Pair) {
                    if (Pair.first == InputFile->getBufferIdentifier()) {
                      Pair.second = InputFile->getBuffer();
                    }
                  });

    TracedOp.start(trace::OperationKind::CodeCompletion, SwiftArgs,
                   {std::make_pair("OriginalOffset", std::to_string(Offset)),
                    std::make_pair("Offset",
                      std::to_string(CodeCompletionOffset))});
  }

  CloseClangModuleFiles scopedCloseFiles(
      *CI.getASTContext().getClangModuleLoader());
  SwiftConsumer.setContext(&CI.getASTContext(), &Invocation,
                           &CompletionContext);
  CI.performSema();
  SwiftConsumer.clearContext();
  return true;
}