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; }