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 "CodeCompletionStrings.h"
19 #include "Compiler.h"
20 #include "Logger.h"
21 #include "index/Index.h"
22 #include "clang/Frontend/CompilerInstance.h"
23 #include "clang/Frontend/FrontendActions.h"
24 #include "clang/Sema/CodeCompleteConsumer.h"
25 #include "clang/Sema/Sema.h"
26 #include <queue>
27 
28 namespace clang {
29 namespace clangd {
30 namespace {
31 
32 CompletionItemKind toCompletionItemKind(CXCursorKind CursorKind) {
33   switch (CursorKind) {
34   case CXCursor_MacroInstantiation:
35   case CXCursor_MacroDefinition:
36     return CompletionItemKind::Text;
37   case CXCursor_CXXMethod:
38   case CXCursor_Destructor:
39     return CompletionItemKind::Method;
40   case CXCursor_FunctionDecl:
41   case CXCursor_FunctionTemplate:
42     return CompletionItemKind::Function;
43   case CXCursor_Constructor:
44     return CompletionItemKind::Constructor;
45   case CXCursor_FieldDecl:
46     return CompletionItemKind::Field;
47   case CXCursor_VarDecl:
48   case CXCursor_ParmDecl:
49     return CompletionItemKind::Variable;
50   // FIXME(ioeric): use LSP struct instead of class when it is suppoted in the
51   // protocol.
52   case CXCursor_StructDecl:
53   case CXCursor_ClassDecl:
54   case CXCursor_UnionDecl:
55   case CXCursor_ClassTemplate:
56   case CXCursor_ClassTemplatePartialSpecialization:
57     return CompletionItemKind::Class;
58   case CXCursor_Namespace:
59   case CXCursor_NamespaceAlias:
60   case CXCursor_NamespaceRef:
61     return CompletionItemKind::Module;
62   case CXCursor_EnumConstantDecl:
63     return CompletionItemKind::Value;
64   case CXCursor_EnumDecl:
65     return CompletionItemKind::Enum;
66   // FIXME(ioeric): figure out whether reference is the right type for aliases.
67   case CXCursor_TypeAliasDecl:
68   case CXCursor_TypeAliasTemplateDecl:
69   case CXCursor_TypedefDecl:
70   case CXCursor_MemberRef:
71   case CXCursor_TypeRef:
72     return CompletionItemKind::Reference;
73   default:
74     return CompletionItemKind::Missing;
75   }
76 }
77 
78 CompletionItemKind
79 toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
80                      CXCursorKind CursorKind) {
81   switch (ResKind) {
82   case CodeCompletionResult::RK_Declaration:
83     return toCompletionItemKind(CursorKind);
84   case CodeCompletionResult::RK_Keyword:
85     return CompletionItemKind::Keyword;
86   case CodeCompletionResult::RK_Macro:
87     return CompletionItemKind::Text; // unfortunately, there's no 'Macro'
88                                      // completion items in LSP.
89   case CodeCompletionResult::RK_Pattern:
90     return CompletionItemKind::Snippet;
91   }
92   llvm_unreachable("Unhandled CodeCompletionResult::ResultKind.");
93 }
94 
95 CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
96   using SK = index::SymbolKind;
97   switch (Kind) {
98   case SK::Unknown:
99     return CompletionItemKind::Missing;
100   case SK::Module:
101   case SK::Namespace:
102   case SK::NamespaceAlias:
103     return CompletionItemKind::Module;
104   case SK::Macro:
105     return CompletionItemKind::Text;
106   case SK::Enum:
107     return CompletionItemKind::Enum;
108   // FIXME(ioeric): use LSP struct instead of class when it is suppoted in the
109   // protocol.
110   case SK::Struct:
111   case SK::Class:
112   case SK::Protocol:
113   case SK::Extension:
114   case SK::Union:
115     return CompletionItemKind::Class;
116   // FIXME(ioeric): figure out whether reference is the right type for aliases.
117   case SK::TypeAlias:
118   case SK::Using:
119     return CompletionItemKind::Reference;
120   case SK::Function:
121   // FIXME(ioeric): this should probably be an operator. This should be fixed
122   // when `Operator` is support type in the protocol.
123   case SK::ConversionFunction:
124     return CompletionItemKind::Function;
125   case SK::Variable:
126   case SK::Parameter:
127     return CompletionItemKind::Variable;
128   case SK::Field:
129     return CompletionItemKind::Field;
130   // FIXME(ioeric): use LSP enum constant when it is supported in the protocol.
131   case SK::EnumConstant:
132     return CompletionItemKind::Value;
133   case SK::InstanceMethod:
134   case SK::ClassMethod:
135   case SK::StaticMethod:
136   case SK::Destructor:
137     return CompletionItemKind::Method;
138   case SK::InstanceProperty:
139   case SK::ClassProperty:
140   case SK::StaticProperty:
141     return CompletionItemKind::Property;
142   case SK::Constructor:
143     return CompletionItemKind::Constructor;
144   }
145   llvm_unreachable("Unhandled clang::index::SymbolKind.");
146 }
147 
148 /// Get the optional chunk as a string. This function is possibly recursive.
149 ///
150 /// The parameter info for each parameter is appended to the Parameters.
151 std::string
152 getOptionalParameters(const CodeCompletionString &CCS,
153                       std::vector<ParameterInformation> &Parameters) {
154   std::string Result;
155   for (const auto &Chunk : CCS) {
156     switch (Chunk.Kind) {
157     case CodeCompletionString::CK_Optional:
158       assert(Chunk.Optional &&
159              "Expected the optional code completion string to be non-null.");
160       Result += getOptionalParameters(*Chunk.Optional, Parameters);
161       break;
162     case CodeCompletionString::CK_VerticalSpace:
163       break;
164     case CodeCompletionString::CK_Placeholder:
165       // A string that acts as a placeholder for, e.g., a function call
166       // argument.
167       // Intentional fallthrough here.
168     case CodeCompletionString::CK_CurrentParameter: {
169       // A piece of text that describes the parameter that corresponds to
170       // the code-completion location within a function call, message send,
171       // macro invocation, etc.
172       Result += Chunk.Text;
173       ParameterInformation Info;
174       Info.label = Chunk.Text;
175       Parameters.push_back(std::move(Info));
176       break;
177     }
178     default:
179       Result += Chunk.Text;
180       break;
181     }
182   }
183   return Result;
184 }
185 
186 /// A scored code completion result.
187 /// It may be promoted to a CompletionItem if it's among the top-ranked results.
188 struct CompletionCandidate {
189   CompletionCandidate(CodeCompletionResult &Result)
190       : Result(&Result), Score(score(Result)) {}
191 
192   CodeCompletionResult *Result;
193   float Score; // 0 to 1, higher is better.
194 
195   // Comparison reflects rank: better candidates are smaller.
196   bool operator<(const CompletionCandidate &C) const {
197     if (Score != C.Score)
198       return Score > C.Score;
199     return *Result < *C.Result;
200   }
201 
202   // Returns a string that sorts in the same order as operator<, for LSP.
203   // Conceptually, this is [-Score, Name]. We convert -Score to an integer, and
204   // hex-encode it for readability. Example: [0.5, "foo"] -> "41000000foo"
205   std::string sortText() const {
206     std::string S, NameStorage;
207     llvm::raw_string_ostream OS(S);
208     write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
209               /*Width=*/2 * sizeof(Score));
210     OS << Result->getOrderedName(NameStorage);
211     return OS.str();
212   }
213 
214 private:
215   static float score(const CodeCompletionResult &Result) {
216     // Priority 80 is a really bad score.
217     float Score = 1 - std::min<float>(80, Result.Priority) / 80;
218 
219     switch (static_cast<CXAvailabilityKind>(Result.Availability)) {
220     case CXAvailability_Available:
221       // No penalty.
222       break;
223     case CXAvailability_Deprecated:
224       Score *= 0.1f;
225       break;
226     case CXAvailability_NotAccessible:
227     case CXAvailability_NotAvailable:
228       Score = 0;
229       break;
230     }
231     return Score;
232   }
233 
234   // Produces an integer that sorts in the same order as F.
235   // That is: a < b <==> encodeFloat(a) < encodeFloat(b).
236   static uint32_t encodeFloat(float F) {
237     static_assert(std::numeric_limits<float>::is_iec559, "");
238     static_assert(sizeof(float) == sizeof(uint32_t), "");
239     constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
240 
241     // Get the bits of the float. Endianness is the same as for integers.
242     uint32_t U;
243     memcpy(&U, &F, sizeof(float));
244     // IEEE 754 floats compare like sign-magnitude integers.
245     if (U & TopBit)    // Negative float.
246       return 0 - U;    // Map onto the low half of integers, order reversed.
247     return U + TopBit; // Positive floats map onto the high half of integers.
248   }
249 };
250 
251 /// \brief Information about the scope specifier in the qualified-id code
252 /// completion (e.g. "ns::ab?").
253 struct SpecifiedScope {
254   /// The scope specifier as written. For example, for completion "ns::ab?", the
255   /// written scope specifier is "ns".
256   std::string Written;
257   // If this scope specifier is recognized in Sema (e.g. as a namespace
258   // context), this will be set to the fully qualfied name of the corresponding
259   // context.
260   std::string Resolved;
261 };
262 
263 /// \brief Information from sema about (parital) symbol names to be completed.
264 /// For example, for completion "ns::ab^", this stores the scope specifier
265 /// "ns::" and the completion filter text "ab".
266 struct NameToComplete {
267   // The partial identifier being completed, without qualifier.
268   std::string Filter;
269 
270   /// This is set if the completion is for qualified IDs, e.g. "abc::x^".
271   llvm::Optional<SpecifiedScope> SSInfo;
272 };
273 
274 SpecifiedScope extraCompletionScope(Sema &S, const CXXScopeSpec &SS);
275 
276 class CompletionItemsCollector : public CodeCompleteConsumer {
277 public:
278   CompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
279                            CompletionList &Items, NameToComplete &CompletedName)
280       : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(),
281                              /*OutputIsBinary=*/false),
282         ClangdOpts(CodeCompleteOpts), Items(Items),
283         Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
284         CCTUInfo(Allocator), CompletedName(CompletedName),
285         EnableSnippets(CodeCompleteOpts.EnableSnippets) {}
286 
287   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
288                                   CodeCompletionResult *Results,
289                                   unsigned NumResults) override final {
290     if (auto SS = Context.getCXXScopeSpecifier())
291       CompletedName.SSInfo = extraCompletionScope(S, **SS);
292 
293     CompletedName.Filter = S.getPreprocessor().getCodeCompletionFilter();
294     std::priority_queue<CompletionCandidate> Candidates;
295     for (unsigned I = 0; I < NumResults; ++I) {
296       auto &Result = Results[I];
297       if (!ClangdOpts.IncludeIneligibleResults &&
298           (Result.Availability == CXAvailability_NotAvailable ||
299            Result.Availability == CXAvailability_NotAccessible))
300         continue;
301       if (!CompletedName.Filter.empty() &&
302           !fuzzyMatch(S, Context, CompletedName.Filter, Result))
303         continue;
304       Candidates.emplace(Result);
305       if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) {
306         Candidates.pop();
307         Items.isIncomplete = true;
308       }
309     }
310     while (!Candidates.empty()) {
311       auto &Candidate = Candidates.top();
312       const auto *CCS = Candidate.Result->CreateCodeCompletionString(
313           S, Context, *Allocator, CCTUInfo,
314           CodeCompleteOpts.IncludeBriefComments);
315       assert(CCS && "Expected the CodeCompletionString to be non-null");
316       Items.items.push_back(ProcessCodeCompleteResult(Candidate, *CCS));
317       Candidates.pop();
318     }
319     std::reverse(Items.items.begin(), Items.items.end());
320   }
321 
322   GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
323 
324   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
325 
326 private:
327   bool fuzzyMatch(Sema &S, const CodeCompletionContext &CCCtx, StringRef Filter,
328                   CodeCompletionResult Result) {
329     switch (Result.Kind) {
330     case CodeCompletionResult::RK_Declaration:
331       if (auto *ID = Result.Declaration->getIdentifier())
332         return fuzzyMatch(Filter, ID->getName());
333       break;
334     case CodeCompletionResult::RK_Keyword:
335       return fuzzyMatch(Filter, Result.Keyword);
336     case CodeCompletionResult::RK_Macro:
337       return fuzzyMatch(Filter, Result.Macro->getName());
338     case CodeCompletionResult::RK_Pattern:
339       return fuzzyMatch(Filter, Result.Pattern->getTypedText());
340     }
341     auto *CCS = Result.CreateCodeCompletionString(
342         S, CCCtx, *Allocator, CCTUInfo, /*IncludeBriefComments=*/false);
343     return fuzzyMatch(Filter, CCS->getTypedText());
344   }
345 
346   // Checks whether Target matches the Filter.
347   // Currently just requires a case-insensitive subsequence match.
348   // FIXME: make stricter and word-based: 'unique_ptr' should not match 'que'.
349   // FIXME: return a score to be incorporated into ranking.
350   static bool fuzzyMatch(StringRef Filter, StringRef Target) {
351     size_t TPos = 0;
352     for (char C : Filter) {
353       TPos = Target.find_lower(C, TPos);
354       if (TPos == StringRef::npos)
355         return false;
356     }
357     return true;
358   }
359 
360   CompletionItem
361   ProcessCodeCompleteResult(const CompletionCandidate &Candidate,
362                             const CodeCompletionString &CCS) const {
363 
364     // Adjust this to InsertTextFormat::Snippet iff we encounter a
365     // CK_Placeholder chunk in SnippetCompletionItemsCollector.
366     CompletionItem Item;
367 
368     Item.documentation = getDocumentation(CCS);
369     Item.sortText = Candidate.sortText();
370 
371     Item.detail = getDetail(CCS);
372     Item.filterText = getFilterText(CCS);
373     getLabelAndInsertText(CCS, &Item.label, &Item.insertText, EnableSnippets);
374 
375     Item.insertTextFormat = EnableSnippets ? InsertTextFormat::Snippet
376                                            : InsertTextFormat::PlainText;
377 
378     // Fill in the kind field of the CompletionItem.
379     Item.kind = toCompletionItemKind(Candidate.Result->Kind,
380                                      Candidate.Result->CursorKind);
381 
382     return Item;
383   }
384 
385   CodeCompleteOptions ClangdOpts;
386   CompletionList &Items;
387   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
388   CodeCompletionTUInfo CCTUInfo;
389   NameToComplete &CompletedName;
390   bool EnableSnippets;
391 }; // CompletionItemsCollector
392 
393 class SignatureHelpCollector final : public CodeCompleteConsumer {
394 
395 public:
396   SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
397                          SignatureHelp &SigHelp)
398       : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
399         SigHelp(SigHelp),
400         Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
401         CCTUInfo(Allocator) {}
402 
403   void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
404                                  OverloadCandidate *Candidates,
405                                  unsigned NumCandidates) override {
406     SigHelp.signatures.reserve(NumCandidates);
407     // FIXME(rwols): How can we determine the "active overload candidate"?
408     // Right now the overloaded candidates seem to be provided in a "best fit"
409     // order, so I'm not too worried about this.
410     SigHelp.activeSignature = 0;
411     assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() &&
412            "too many arguments");
413     SigHelp.activeParameter = static_cast<int>(CurrentArg);
414     for (unsigned I = 0; I < NumCandidates; ++I) {
415       const auto &Candidate = Candidates[I];
416       const auto *CCS = Candidate.CreateSignatureString(
417           CurrentArg, S, *Allocator, CCTUInfo, true);
418       assert(CCS && "Expected the CodeCompletionString to be non-null");
419       SigHelp.signatures.push_back(ProcessOverloadCandidate(Candidate, *CCS));
420     }
421   }
422 
423   GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
424 
425   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
426 
427 private:
428   // FIXME(ioeric): consider moving CodeCompletionString logic here to
429   // CompletionString.h.
430   SignatureInformation
431   ProcessOverloadCandidate(const OverloadCandidate &Candidate,
432                            const CodeCompletionString &CCS) const {
433     SignatureInformation Result;
434     const char *ReturnType = nullptr;
435 
436     Result.documentation = getDocumentation(CCS);
437 
438     for (const auto &Chunk : CCS) {
439       switch (Chunk.Kind) {
440       case CodeCompletionString::CK_ResultType:
441         // A piece of text that describes the type of an entity or,
442         // for functions and methods, the return type.
443         assert(!ReturnType && "Unexpected CK_ResultType");
444         ReturnType = Chunk.Text;
445         break;
446       case CodeCompletionString::CK_Placeholder:
447         // A string that acts as a placeholder for, e.g., a function call
448         // argument.
449         // Intentional fallthrough here.
450       case CodeCompletionString::CK_CurrentParameter: {
451         // A piece of text that describes the parameter that corresponds to
452         // the code-completion location within a function call, message send,
453         // macro invocation, etc.
454         Result.label += Chunk.Text;
455         ParameterInformation Info;
456         Info.label = Chunk.Text;
457         Result.parameters.push_back(std::move(Info));
458         break;
459       }
460       case CodeCompletionString::CK_Optional: {
461         // The rest of the parameters are defaulted/optional.
462         assert(Chunk.Optional &&
463                "Expected the optional code completion string to be non-null.");
464         Result.label +=
465             getOptionalParameters(*Chunk.Optional, Result.parameters);
466         break;
467       }
468       case CodeCompletionString::CK_VerticalSpace:
469         break;
470       default:
471         Result.label += Chunk.Text;
472         break;
473       }
474     }
475     if (ReturnType) {
476       Result.label += " -> ";
477       Result.label += ReturnType;
478     }
479     return Result;
480   }
481 
482   SignatureHelp &SigHelp;
483   std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
484   CodeCompletionTUInfo CCTUInfo;
485 
486 }; // SignatureHelpCollector
487 
488 bool invokeCodeComplete(const Context &Ctx,
489                         std::unique_ptr<CodeCompleteConsumer> Consumer,
490                         const clang::CodeCompleteOptions &Options,
491                         PathRef FileName,
492                         const tooling::CompileCommand &Command,
493                         PrecompiledPreamble const *Preamble, StringRef Contents,
494                         Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
495                         std::shared_ptr<PCHContainerOperations> PCHs) {
496   std::vector<const char *> ArgStrs;
497   for (const auto &S : Command.CommandLine)
498     ArgStrs.push_back(S.c_str());
499 
500   VFS->setCurrentWorkingDirectory(Command.Directory);
501 
502   IgnoreDiagnostics DummyDiagsConsumer;
503   auto CI = createInvocationFromCommandLine(
504       ArgStrs,
505       CompilerInstance::createDiagnostics(new DiagnosticOptions,
506                                           &DummyDiagsConsumer, false),
507       VFS);
508   assert(CI && "Couldn't create CompilerInvocation");
509 
510   std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
511       llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName);
512 
513   // Attempt to reuse the PCH from precompiled preamble, if it was built.
514   if (Preamble) {
515     auto Bounds =
516         ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
517     if (!Preamble->CanReuse(*CI, ContentsBuffer.get(), Bounds, VFS.get()))
518       Preamble = nullptr;
519   }
520 
521   auto Clang = prepareCompilerInstance(
522       std::move(CI), Preamble, std::move(ContentsBuffer), std::move(PCHs),
523       std::move(VFS), DummyDiagsConsumer);
524   auto &DiagOpts = Clang->getDiagnosticOpts();
525   DiagOpts.IgnoreWarnings = true;
526 
527   auto &FrontendOpts = Clang->getFrontendOpts();
528   FrontendOpts.SkipFunctionBodies = true;
529   FrontendOpts.CodeCompleteOpts = Options;
530   FrontendOpts.CodeCompletionAt.FileName = FileName;
531   FrontendOpts.CodeCompletionAt.Line = Pos.line + 1;
532   FrontendOpts.CodeCompletionAt.Column = Pos.character + 1;
533 
534   Clang->setCodeCompletionConsumer(Consumer.release());
535 
536   SyntaxOnlyAction Action;
537   if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
538     log(Ctx,
539         "BeginSourceFile() failed when running codeComplete for " + FileName);
540     return false;
541   }
542   if (!Action.Execute()) {
543     log(Ctx, "Execute() failed when running codeComplete for " + FileName);
544     return false;
545   }
546 
547   Action.EndSourceFile();
548 
549   return true;
550 }
551 
552 CompletionItem indexCompletionItem(const Symbol &Sym, llvm::StringRef Filter,
553                                    const SpecifiedScope &SSInfo) {
554   CompletionItem Item;
555   Item.kind = toCompletionItemKind(Sym.SymInfo.Kind);
556   Item.label = Sym.Name;
557   // FIXME(ioeric): support inserting/replacing scope qualifiers.
558   Item.insertText = Sym.Name;
559   // FIXME(ioeric): support snippets.
560   Item.insertTextFormat = InsertTextFormat::PlainText;
561   Item.filterText = Sym.Name;
562 
563   // FIXME(ioeric): sort symbols appropriately.
564   Item.sortText = "";
565 
566   // FIXME(ioeric): use more symbol information (e.g. documentation, label) to
567   // populate the completion item.
568 
569   return Item;
570 }
571 
572 void completeWithIndex(const Context &Ctx, const SymbolIndex &Index,
573                        llvm::StringRef Code, const SpecifiedScope &SSInfo,
574                        llvm::StringRef Filter, CompletionList *Items) {
575   FuzzyFindRequest Req;
576   Req.Query = Filter;
577   // FIXME(ioeric): add more possible scopes based on using namespaces and
578   // containing namespaces.
579   StringRef Scope = SSInfo.Resolved.empty() ? SSInfo.Written : SSInfo.Resolved;
580   Req.Scopes = {Scope.trim(':').str()};
581 
582   Items->isIncomplete = !Index.fuzzyFind(Ctx, Req, [&](const Symbol &Sym) {
583     Items->items.push_back(indexCompletionItem(Sym, Filter, SSInfo));
584   });
585 }
586 
587 SpecifiedScope extraCompletionScope(Sema &S, const CXXScopeSpec &SS) {
588   SpecifiedScope Info;
589   auto &SM = S.getSourceManager();
590   auto SpecifierRange = SS.getRange();
591   Info.Written = Lexer::getSourceText(
592       CharSourceRange::getCharRange(SpecifierRange), SM, clang::LangOptions());
593   if (SS.isValid()) {
594     DeclContext *DC = S.computeDeclContext(SS);
595     if (auto *NS = llvm::dyn_cast<NamespaceDecl>(DC)) {
596       Info.Resolved = NS->getQualifiedNameAsString();
597     } else if (llvm::dyn_cast<TranslationUnitDecl>(DC) != nullptr) {
598       Info.Resolved = "::";
599       // Sema does not include the suffix "::" in the range of SS, so we add
600       // it back here.
601       Info.Written = "::";
602     }
603   }
604   return Info;
605 }
606 
607 } // namespace
608 
609 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
610   clang::CodeCompleteOptions Result;
611   Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
612   Result.IncludeMacros = IncludeMacros;
613   Result.IncludeGlobals = IncludeGlobals;
614   Result.IncludeBriefComments = IncludeBriefComments;
615 
616   // Enable index-based code completion when Index is provided.
617   Result.IncludeNamespaceLevelDecls = !Index;
618 
619   return Result;
620 }
621 
622 CompletionList codeComplete(const Context &Ctx, PathRef FileName,
623                             const tooling::CompileCommand &Command,
624                             PrecompiledPreamble const *Preamble,
625                             StringRef Contents, Position Pos,
626                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
627                             std::shared_ptr<PCHContainerOperations> PCHs,
628                             CodeCompleteOptions Opts) {
629   CompletionList Results;
630   NameToComplete CompletedName;
631   auto Consumer =
632       llvm::make_unique<CompletionItemsCollector>(Opts, Results, CompletedName);
633   invokeCodeComplete(Ctx, std::move(Consumer), Opts.getClangCompleteOpts(),
634                      FileName, Command, Preamble, Contents, Pos, std::move(VFS),
635                      std::move(PCHs));
636   if (Opts.Index && CompletedName.SSInfo) {
637     if (!Results.items.empty())
638       log(Ctx, "WARNING: Got completion results from sema for completion on "
639                "qualified ID while symbol index is provided.");
640     Results.items.clear();
641     completeWithIndex(Ctx, *Opts.Index, Contents, *CompletedName.SSInfo,
642                       CompletedName.Filter, &Results);
643   }
644   return Results;
645 }
646 
647 SignatureHelp signatureHelp(const Context &Ctx, PathRef FileName,
648                             const tooling::CompileCommand &Command,
649                             PrecompiledPreamble const *Preamble,
650                             StringRef Contents, Position Pos,
651                             IntrusiveRefCntPtr<vfs::FileSystem> VFS,
652                             std::shared_ptr<PCHContainerOperations> PCHs) {
653   SignatureHelp Result;
654   clang::CodeCompleteOptions Options;
655   Options.IncludeGlobals = false;
656   Options.IncludeMacros = false;
657   Options.IncludeCodePatterns = false;
658   Options.IncludeBriefComments = true;
659   invokeCodeComplete(Ctx,
660                      llvm::make_unique<SignatureHelpCollector>(Options, Result),
661                      Options, FileName, Command, Preamble, Contents, Pos,
662                      std::move(VFS), std::move(PCHs));
663   return Result;
664 }
665 
666 } // namespace clangd
667 } // namespace clang
668