1 //===--- CodeComplete.cpp ---------------------------------------*- C++-*-===//
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 // AST-based completions are provided using the completion hooks in Sema.
11 //
12 // Signature help works in a similar way as code completion, but it is simpler
13 // as there are typically fewer candidates.
14 //
15 //===---------------------------------------------------------------------===//
16 
17 #include "CodeComplete.h"
18 #include "Compiler.h"
19 #include "clang/Frontend/CompilerInstance.h"
20 #include "clang/Frontend/FrontendActions.h"
21 #include "clang/Sema/CodeCompleteConsumer.h"
22 #include "clang/Sema/Sema.h"
23 #include <queue>
24 
25 namespace clang {
26 namespace clangd {
27 namespace {
28 
29 CompletionItemKind getKindOfDecl(CXCursorKind CursorKind) {
30   switch (CursorKind) {
31   case CXCursor_MacroInstantiation:
32   case CXCursor_MacroDefinition:
33     return CompletionItemKind::Text;
34   case CXCursor_CXXMethod:
35     return CompletionItemKind::Method;
36   case CXCursor_FunctionDecl:
37   case CXCursor_FunctionTemplate:
38     return CompletionItemKind::Function;
39   case CXCursor_Constructor:
40   case CXCursor_Destructor:
41     return CompletionItemKind::Constructor;
42   case CXCursor_FieldDecl:
43     return CompletionItemKind::Field;
44   case CXCursor_VarDecl:
45   case CXCursor_ParmDecl:
46     return CompletionItemKind::Variable;
47   case CXCursor_ClassDecl:
48   case CXCursor_StructDecl:
49   case CXCursor_UnionDecl:
50   case CXCursor_ClassTemplate:
51   case CXCursor_ClassTemplatePartialSpecialization:
52     return CompletionItemKind::Class;
53   case CXCursor_Namespace:
54   case CXCursor_NamespaceAlias:
55   case CXCursor_NamespaceRef:
56     return CompletionItemKind::Module;
57   case CXCursor_EnumConstantDecl:
58     return CompletionItemKind::Value;
59   case CXCursor_EnumDecl:
60     return CompletionItemKind::Enum;
61   case CXCursor_TypeAliasDecl:
62   case CXCursor_TypeAliasTemplateDecl:
63   case CXCursor_TypedefDecl:
64   case CXCursor_MemberRef:
65   case CXCursor_TypeRef:
66     return CompletionItemKind::Reference;
67   default:
68     return CompletionItemKind::Missing;
69   }
70 }
71 
72 CompletionItemKind getKind(CodeCompletionResult::ResultKind ResKind,
73                            CXCursorKind CursorKind) {
74   switch (ResKind) {
75   case CodeCompletionResult::RK_Declaration:
76     return getKindOfDecl(CursorKind);
77   case CodeCompletionResult::RK_Keyword:
78     return CompletionItemKind::Keyword;
79   case CodeCompletionResult::RK_Macro:
80     return CompletionItemKind::Text; // unfortunately, there's no 'Macro'
81                                      // completion items in LSP.
82   case CodeCompletionResult::RK_Pattern:
83     return CompletionItemKind::Snippet;
84   }
85   llvm_unreachable("Unhandled CodeCompletionResult::ResultKind.");
86 }
87 
88 std::string escapeSnippet(const llvm::StringRef Text) {
89   std::string Result;
90   Result.reserve(Text.size()); // Assume '$', '}' and '\\' are rare.
91   for (const auto Character : Text) {
92     if (Character == '$' || Character == '}' || Character == '\\')
93       Result.push_back('\\');
94     Result.push_back(Character);
95   }
96   return Result;
97 }
98 
99 std::string getDocumentation(const CodeCompletionString &CCS) {
100   // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
101   // information in the documentation field.
102   std::string Result;
103   const unsigned AnnotationCount = CCS.getAnnotationCount();
104   if (AnnotationCount > 0) {
105     Result += "Annotation";
106     if (AnnotationCount == 1) {
107       Result += ": ";
108     } else /* AnnotationCount > 1 */ {
109       Result += "s: ";
110     }
111     for (unsigned I = 0; I < AnnotationCount; ++I) {
112       Result += CCS.getAnnotation(I);
113       Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
114     }
115   }
116   // Add brief documentation (if there is any).
117   if (CCS.getBriefComment() != nullptr) {
118     if (!Result.empty()) {
119       // This means we previously added annotations. Add an extra newline
120       // character to make the annotations stand out.
121       Result.push_back('\n');
122     }
123     Result += CCS.getBriefComment();
124   }
125   return Result;
126 }
127 
128 /// Get the optional chunk as a string. This function is possibly recursive.
129 ///
130 /// The parameter info for each parameter is appended to the Parameters.
131 std::string
132 getOptionalParameters(const CodeCompletionString &CCS,
133                       std::vector<ParameterInformation> &Parameters) {
134   std::string Result;
135   for (const auto &Chunk : CCS) {
136     switch (Chunk.Kind) {
137     case CodeCompletionString::CK_Optional:
138       assert(Chunk.Optional &&
139              "Expected the optional code completion string to be non-null.");
140       Result += getOptionalParameters(*Chunk.Optional, Parameters);
141       break;
142     case CodeCompletionString::CK_VerticalSpace:
143       break;
144     case CodeCompletionString::CK_Placeholder:
145       // A string that acts as a placeholder for, e.g., a function call
146       // argument.
147       // Intentional fallthrough here.
148     case CodeCompletionString::CK_CurrentParameter: {
149       // A piece of text that describes the parameter that corresponds to
150       // the code-completion location within a function call, message send,
151       // macro invocation, etc.
152       Result += Chunk.Text;
153       ParameterInformation Info;
154       Info.label = Chunk.Text;
155       Parameters.push_back(std::move(Info));
156       break;
157     }
158     default:
159       Result += Chunk.Text;
160       break;
161     }
162   }
163   return Result;
164 }
165 
166 /// A scored code completion result.
167 /// It may be promoted to a CompletionItem if it's among the top-ranked results.
168 struct CompletionCandidate {
169   CompletionCandidate(CodeCompletionResult &Result)
170       : Result(&Result), Score(score(Result)) {}
171 
172   CodeCompletionResult *Result;
173   float Score; // 0 to 1, higher is better.
174 
175   // Comparison reflects rank: better candidates are smaller.
176   bool operator<(const CompletionCandidate &C) const {
177     if (Score != C.Score)
178       return Score > C.Score;
179     return *Result < *C.Result;
180   }
181 
182   // Returns a string that sorts in the same order as operator<, for LSP.
183   // Conceptually, this is [-Score, Name]. We convert -Score to an integer, and
184   // hex-encode it for readability. Example: [0.5, "foo"] -> "41000000foo"
185   std::string sortText() const {
186     std::string S, NameStorage;
187     llvm::raw_string_ostream OS(S);
188     write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
189               /*Width=*/2 * sizeof(Score));
190     OS << Result->getOrderedName(NameStorage);
191     return OS.str();
192   }
193 
194 private:
195   static float score(const CodeCompletionResult &Result) {
196     // Priority 80 is a really bad score.
197     float Score = 1 - std::min<float>(80, Result.Priority) / 80;
198 
199     switch (static_cast<CXAvailabilityKind>(Result.Availability)) {
200     case CXAvailability_Available:
201       // No penalty.
202       break;
203     case CXAvailability_Deprecated:
204       Score *= 0.1f;
205       break;
206     case CXAvailability_NotAccessible:
207     case CXAvailability_NotAvailable:
208       Score = 0;
209       break;
210     }
211     return Score;
212   }
213 
214   // Produces an integer that sorts in the same order as F.
215   // That is: a < b <==> encodeFloat(a) < encodeFloat(b).
216   static uint32_t encodeFloat(float F) {
217     static_assert(std::numeric_limits<float>::is_iec559, "");
218     static_assert(sizeof(float) == sizeof(uint32_t), "");
219     constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
220 
221     // Get the bits of the float. Endianness is the same as for integers.
222     uint32_t U;
223     memcpy(&U, &F, sizeof(float));
224     // IEEE 754 floats compare like sign-magnitude integers.
225     if (U & TopBit)    // Negative float.
226       return 0 - U;    // Map onto the low half of integers, order reversed.
227     return U + TopBit; // Positive floats map onto the high half of integers.
228   }
229 };
230 
231 class CompletionItemsCollector : public CodeCompleteConsumer {
232 public:
233   CompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
234                            CompletionList &Items)
235       : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(),
236                              /*OutputIsBinary=*/false),
237         ClangdOpts(CodeCompleteOpts), Items(Items),
238         Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
239         CCTUInfo(Allocator) {}
240 
241   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
242                                   CodeCompletionResult *Results,
243                                   unsigned NumResults) override final {
244     StringRef Filter = S.getPreprocessor().getCodeCompletionFilter();
245     std::priority_queue<CompletionCandidate> Candidates;
246     for (unsigned I = 0; I < NumResults; ++I) {
247       auto &Result = Results[I];
248       if (!ClangdOpts.IncludeIneligibleResults &&
249           (Result.Availability == CXAvailability_NotAvailable ||
250            Result.Availability == CXAvailability_NotAccessible))
251         continue;
252       if (!Filter.empty() && !fuzzyMatch(S, Context, Filter, Result))
253         continue;
254       Candidates.emplace(Result);
255       if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) {
256         Candidates.pop();
257         Items.isIncomplete = true;
258       }
259     }
260     while (!Candidates.empty()) {
261       auto &Candidate = Candidates.top();
262       const auto *CCS = Candidate.Result->CreateCodeCompletionString(
263           S, Context, *Allocator, CCTUInfo,
264           CodeCompleteOpts.IncludeBriefComments);
265       assert(CCS && "Expected the CodeCompletionString to be non-null");
266       Items.items.push_back(ProcessCodeCompleteResult(Candidate, *CCS));
267       Candidates.pop();
268     }
269     std::reverse(Items.items.begin(), Items.items.end());
270   }
271 
272   GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
273 
274   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
275 
276 private:
277   bool fuzzyMatch(Sema &S, const CodeCompletionContext &CCCtx, StringRef Filter,
278                   CodeCompletionResult Result) {
279     switch (Result.Kind) {
280     case CodeCompletionResult::RK_Declaration:
281       if (auto *ID = Result.Declaration->getIdentifier())
282         return fuzzyMatch(Filter, ID->getName());
283       break;
284     case CodeCompletionResult::RK_Keyword:
285       return fuzzyMatch(Filter, Result.Keyword);
286     case CodeCompletionResult::RK_Macro:
287       return fuzzyMatch(Filter, Result.Macro->getName());
288     case CodeCompletionResult::RK_Pattern:
289       return fuzzyMatch(Filter, Result.Pattern->getTypedText());
290     }
291     auto *CCS = Result.CreateCodeCompletionString(
292         S, CCCtx, *Allocator, CCTUInfo, /*IncludeBriefComments=*/false);
293     return fuzzyMatch(Filter, CCS->getTypedText());
294   }
295 
296   // Checks whether Target matches the Filter.
297   // Currently just requires a case-insensitive subsequence match.
298   // FIXME: make stricter and word-based: 'unique_ptr' should not match 'que'.
299   // FIXME: return a score to be incorporated into ranking.
300   static bool fuzzyMatch(StringRef Filter, StringRef Target) {
301     size_t TPos = 0;
302     for (char C : Filter) {
303       TPos = Target.find_lower(C, TPos);
304       if (TPos == StringRef::npos)
305         return false;
306     }
307     return true;
308   }
309 
310   CompletionItem
311   ProcessCodeCompleteResult(const CompletionCandidate &Candidate,
312                             const CodeCompletionString &CCS) const {
313 
314     // Adjust this to InsertTextFormat::Snippet iff we encounter a
315     // CK_Placeholder chunk in SnippetCompletionItemsCollector.
316     CompletionItem Item;
317     Item.insertTextFormat = InsertTextFormat::PlainText;
318 
319     Item.documentation = getDocumentation(CCS);
320     Item.sortText = Candidate.sortText();
321 
322     // Fill in the label, detail, insertText and filterText fields of the
323     // CompletionItem.
324     ProcessChunks(CCS, Item);
325 
326     // Fill in the kind field of the CompletionItem.
327     Item.kind = getKind(Candidate.Result->Kind, Candidate.Result->CursorKind);
328 
329     return Item;
330   }
331 
332   virtual void ProcessChunks(const CodeCompletionString &CCS,
333                              CompletionItem &Item) const = 0;
334 
335   CodeCompleteOptions ClangdOpts;
336   CompletionList &Items;
337   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
338   CodeCompletionTUInfo CCTUInfo;
339 
340 }; // CompletionItemsCollector
341 
342 bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
343   return Chunk.Kind == CodeCompletionString::CK_Informative &&
344          StringRef(Chunk.Text).endswith("::");
345 }
346 
347 class PlainTextCompletionItemsCollector final
348     : public CompletionItemsCollector {
349 
350 public:
351   PlainTextCompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
352                                     CompletionList &Items)
353       : CompletionItemsCollector(CodeCompleteOpts, Items) {}
354 
355 private:
356   void ProcessChunks(const CodeCompletionString &CCS,
357                      CompletionItem &Item) const override {
358     for (const auto &Chunk : CCS) {
359       // Informative qualifier chunks only clutter completion results, skip
360       // them.
361       if (isInformativeQualifierChunk(Chunk))
362         continue;
363 
364       switch (Chunk.Kind) {
365       case CodeCompletionString::CK_TypedText:
366         // There's always exactly one CK_TypedText chunk.
367         Item.insertText = Item.filterText = Chunk.Text;
368         Item.label += Chunk.Text;
369         break;
370       case CodeCompletionString::CK_ResultType:
371         assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
372         Item.detail = Chunk.Text;
373         break;
374       case CodeCompletionString::CK_Optional:
375         break;
376       default:
377         Item.label += Chunk.Text;
378         break;
379       }
380     }
381   }
382 }; // PlainTextCompletionItemsCollector
383 
384 class SnippetCompletionItemsCollector final : public CompletionItemsCollector {
385 
386 public:
387   SnippetCompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
388                                   CompletionList &Items)
389       : CompletionItemsCollector(CodeCompleteOpts, Items) {}
390 
391 private:
392   void ProcessChunks(const CodeCompletionString &CCS,
393                      CompletionItem &Item) const override {
394     unsigned ArgCount = 0;
395     for (const auto &Chunk : CCS) {
396       // Informative qualifier chunks only clutter completion results, skip
397       // them.
398       if (isInformativeQualifierChunk(Chunk))
399         continue;
400 
401       switch (Chunk.Kind) {
402       case CodeCompletionString::CK_TypedText:
403         // The piece of text that the user is expected to type to match
404         // the code-completion string, typically a keyword or the name of
405         // a declarator or macro.
406         Item.filterText = Chunk.Text;
407         LLVM_FALLTHROUGH;
408       case CodeCompletionString::CK_Text:
409         // A piece of text that should be placed in the buffer,
410         // e.g., parentheses or a comma in a function call.
411         Item.label += Chunk.Text;
412         Item.insertText += Chunk.Text;
413         break;
414       case CodeCompletionString::CK_Optional:
415         // A code completion string that is entirely optional.
416         // For example, an optional code completion string that
417         // describes the default arguments in a function call.
418 
419         // FIXME: Maybe add an option to allow presenting the optional chunks?
420         break;
421       case CodeCompletionString::CK_Placeholder:
422         // A string that acts as a placeholder for, e.g., a function call
423         // argument.
424         ++ArgCount;
425         Item.insertText += "${" + std::to_string(ArgCount) + ':' +
426                            escapeSnippet(Chunk.Text) + '}';
427         Item.label += Chunk.Text;
428         Item.insertTextFormat = InsertTextFormat::Snippet;
429         break;
430       case CodeCompletionString::CK_Informative:
431         // A piece of text that describes something about the result
432         // but should not be inserted into the buffer.
433         // For example, the word "const" for a const method, or the name of
434         // the base class for methods that are part of the base class.
435         Item.label += Chunk.Text;
436         // Don't put the informative chunks in the insertText.
437         break;
438       case CodeCompletionString::CK_ResultType:
439         // A piece of text that describes the type of an entity or,
440         // for functions and methods, the return type.
441         assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
442         Item.detail = Chunk.Text;
443         break;
444       case CodeCompletionString::CK_CurrentParameter:
445         // A piece of text that describes the parameter that corresponds to
446         // the code-completion location within a function call, message send,
447         // macro invocation, etc.
448         //
449         // This should never be present while collecting completion items,
450         // only while collecting overload candidates.
451         llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
452                          "CompletionItems");
453         break;
454       case CodeCompletionString::CK_LeftParen:
455         // A left parenthesis ('(').
456       case CodeCompletionString::CK_RightParen:
457         // A right parenthesis (')').
458       case CodeCompletionString::CK_LeftBracket:
459         // A left bracket ('[').
460       case CodeCompletionString::CK_RightBracket:
461         // A right bracket (']').
462       case CodeCompletionString::CK_LeftBrace:
463         // A left brace ('{').
464       case CodeCompletionString::CK_RightBrace:
465         // A right brace ('}').
466       case CodeCompletionString::CK_LeftAngle:
467         // A left angle bracket ('<').
468       case CodeCompletionString::CK_RightAngle:
469         // A right angle bracket ('>').
470       case CodeCompletionString::CK_Comma:
471         // A comma separator (',').
472       case CodeCompletionString::CK_Colon:
473         // A colon (':').
474       case CodeCompletionString::CK_SemiColon:
475         // A semicolon (';').
476       case CodeCompletionString::CK_Equal:
477         // An '=' sign.
478       case CodeCompletionString::CK_HorizontalSpace:
479         // Horizontal whitespace (' ').
480         Item.insertText += Chunk.Text;
481         Item.label += Chunk.Text;
482         break;
483       case CodeCompletionString::CK_VerticalSpace:
484         // Vertical whitespace ('\n' or '\r\n', depending on the
485         // platform).
486         Item.insertText += Chunk.Text;
487         // Don't even add a space to the label.
488         break;
489       }
490     }
491   }
492 }; // SnippetCompletionItemsCollector
493 
494 class SignatureHelpCollector final : public CodeCompleteConsumer {
495 
496 public:
497   SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
498                          SignatureHelp &SigHelp)
499       : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
500         SigHelp(SigHelp),
501         Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
502         CCTUInfo(Allocator) {}
503 
504   void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
505                                  OverloadCandidate *Candidates,
506                                  unsigned NumCandidates) override {
507     SigHelp.signatures.reserve(NumCandidates);
508     // FIXME(rwols): How can we determine the "active overload candidate"?
509     // Right now the overloaded candidates seem to be provided in a "best fit"
510     // order, so I'm not too worried about this.
511     SigHelp.activeSignature = 0;
512     assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() &&
513            "too many arguments");
514     SigHelp.activeParameter = static_cast<int>(CurrentArg);
515     for (unsigned I = 0; I < NumCandidates; ++I) {
516       const auto &Candidate = Candidates[I];
517       const auto *CCS = Candidate.CreateSignatureString(
518           CurrentArg, S, *Allocator, CCTUInfo, true);
519       assert(CCS && "Expected the CodeCompletionString to be non-null");
520       SigHelp.signatures.push_back(ProcessOverloadCandidate(Candidate, *CCS));
521     }
522   }
523 
524   GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
525 
526   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
527 
528 private:
529   SignatureInformation
530   ProcessOverloadCandidate(const OverloadCandidate &Candidate,
531                            const CodeCompletionString &CCS) const {
532     SignatureInformation Result;
533     const char *ReturnType = nullptr;
534 
535     Result.documentation = getDocumentation(CCS);
536 
537     for (const auto &Chunk : CCS) {
538       switch (Chunk.Kind) {
539       case CodeCompletionString::CK_ResultType:
540         // A piece of text that describes the type of an entity or,
541         // for functions and methods, the return type.
542         assert(!ReturnType && "Unexpected CK_ResultType");
543         ReturnType = Chunk.Text;
544         break;
545       case CodeCompletionString::CK_Placeholder:
546         // A string that acts as a placeholder for, e.g., a function call
547         // argument.
548         // Intentional fallthrough here.
549       case CodeCompletionString::CK_CurrentParameter: {
550         // A piece of text that describes the parameter that corresponds to
551         // the code-completion location within a function call, message send,
552         // macro invocation, etc.
553         Result.label += Chunk.Text;
554         ParameterInformation Info;
555         Info.label = Chunk.Text;
556         Result.parameters.push_back(std::move(Info));
557         break;
558       }
559       case CodeCompletionString::CK_Optional: {
560         // The rest of the parameters are defaulted/optional.
561         assert(Chunk.Optional &&
562                "Expected the optional code completion string to be non-null.");
563         Result.label +=
564             getOptionalParameters(*Chunk.Optional, Result.parameters);
565         break;
566       }
567       case CodeCompletionString::CK_VerticalSpace:
568         break;
569       default:
570         Result.label += Chunk.Text;
571         break;
572       }
573     }
574     if (ReturnType) {
575       Result.label += " -> ";
576       Result.label += ReturnType;
577     }
578     return Result;
579   }
580 
581   SignatureHelp &SigHelp;
582   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
583   CodeCompletionTUInfo CCTUInfo;
584 
585 }; // SignatureHelpCollector
586 
587 bool invokeCodeComplete(const Context &Ctx,
588                         std::unique_ptr<CodeCompleteConsumer> Consumer,
589                         const clang::CodeCompleteOptions &Options,
590                         PathRef FileName,
591                         const tooling::CompileCommand &Command,
592                         PrecompiledPreamble const *Preamble, StringRef Contents,
593                         Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
594                         std::shared_ptr<PCHContainerOperations> PCHs) {
595   std::vector<const char *> ArgStrs;
596   for (const auto &S : Command.CommandLine)
597     ArgStrs.push_back(S.c_str());
598 
599   VFS->setCurrentWorkingDirectory(Command.Directory);
600 
601   IgnoreDiagnostics DummyDiagsConsumer;
602   auto CI = createInvocationFromCommandLine(
603       ArgStrs,
604       CompilerInstance::createDiagnostics(new DiagnosticOptions,
605                                           &DummyDiagsConsumer, false),
606       VFS);
607   assert(CI && "Couldn't create CompilerInvocation");
608 
609   std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
610       llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName);
611 
612   // Attempt to reuse the PCH from precompiled preamble, if it was built.
613   if (Preamble) {
614     auto Bounds =
615         ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
616     if (!Preamble->CanReuse(*CI, ContentsBuffer.get(), Bounds, VFS.get()))
617       Preamble = nullptr;
618   }
619 
620   auto Clang = prepareCompilerInstance(
621       std::move(CI), Preamble, std::move(ContentsBuffer), std::move(PCHs),
622       std::move(VFS), DummyDiagsConsumer);
623   auto &DiagOpts = Clang->getDiagnosticOpts();
624   DiagOpts.IgnoreWarnings = true;
625 
626   auto &FrontendOpts = Clang->getFrontendOpts();
627   FrontendOpts.SkipFunctionBodies = true;
628   FrontendOpts.CodeCompleteOpts = Options;
629   FrontendOpts.CodeCompletionAt.FileName = FileName;
630   FrontendOpts.CodeCompletionAt.Line = Pos.line + 1;
631   FrontendOpts.CodeCompletionAt.Column = Pos.character + 1;
632 
633   Clang->setCodeCompletionConsumer(Consumer.release());
634 
635   SyntaxOnlyAction Action;
636   if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
637     log(Ctx,
638         "BeginSourceFile() failed when running codeComplete for " + FileName);
639     return false;
640   }
641   if (!Action.Execute()) {
642     log(Ctx, "Execute() failed when running codeComplete for " + FileName);
643     return false;
644   }
645 
646   Action.EndSourceFile();
647 
648   return true;
649 }
650 
651 } // namespace
652 
653 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
654   clang::CodeCompleteOptions Result;
655   Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
656   Result.IncludeMacros = IncludeMacros;
657   Result.IncludeGlobals = IncludeGlobals;
658   Result.IncludeBriefComments = IncludeBriefComments;
659 
660   return Result;
661 }
662 
663 CompletionList codeComplete(const Context &Ctx, PathRef FileName,
664                             const tooling::CompileCommand &Command,
665                             PrecompiledPreamble const *Preamble,
666                             StringRef Contents, Position Pos,
667                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
668                             std::shared_ptr<PCHContainerOperations> PCHs,
669                             CodeCompleteOptions Opts) {
670   CompletionList Results;
671   std::unique_ptr<CodeCompleteConsumer> Consumer;
672   if (Opts.EnableSnippets) {
673     Consumer =
674         llvm::make_unique<SnippetCompletionItemsCollector>(Opts, Results);
675   } else {
676     Consumer =
677         llvm::make_unique<PlainTextCompletionItemsCollector>(Opts, Results);
678   }
679   invokeCodeComplete(Ctx, std::move(Consumer), Opts.getClangCompleteOpts(),
680                      FileName, Command, Preamble, Contents, Pos, std::move(VFS),
681                      std::move(PCHs));
682   return Results;
683 }
684 
685 SignatureHelp signatureHelp(const Context &Ctx, PathRef FileName,
686                             const tooling::CompileCommand &Command,
687                             PrecompiledPreamble const *Preamble,
688                             StringRef Contents, Position Pos,
689                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
690                             std::shared_ptr<PCHContainerOperations> PCHs) {
691   SignatureHelp Result;
692   clang::CodeCompleteOptions Options;
693   Options.IncludeGlobals = false;
694   Options.IncludeMacros = false;
695   Options.IncludeCodePatterns = false;
696   Options.IncludeBriefComments = true;
697   invokeCodeComplete(Ctx,
698                      llvm::make_unique<SignatureHelpCollector>(Options, Result),
699                      Options, FileName, Command, Preamble, Contents, Pos,
700                      std::move(VFS), std::move(PCHs));
701   return Result;
702 }
703 
704 } // namespace clangd
705 } // namespace clang
706