blob: 87f73b20505449090c0d39217c00c8fa3f805563 [file] [log] [blame]
Sam McCall98775c52017-12-04 13:49:59 +00001//===--- 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"
Eric Liu63696e12017-12-20 17:24:31 +000018#include "CodeCompletionStrings.h"
Sam McCall98775c52017-12-04 13:49:59 +000019#include "Compiler.h"
Eric Liu6f648df2017-12-19 16:50:37 +000020#include "Logger.h"
21#include "index/Index.h"
Sam McCall98775c52017-12-04 13:49:59 +000022#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
28namespace clang {
29namespace clangd {
30namespace {
31
Eric Liu6f648df2017-12-19 16:50:37 +000032CompletionItemKind toCompletionItemKind(CXCursorKind CursorKind) {
Sam McCall98775c52017-12-04 13:49:59 +000033 switch (CursorKind) {
34 case CXCursor_MacroInstantiation:
35 case CXCursor_MacroDefinition:
36 return CompletionItemKind::Text;
37 case CXCursor_CXXMethod:
Eric Liu6f648df2017-12-19 16:50:37 +000038 case CXCursor_Destructor:
Sam McCall98775c52017-12-04 13:49:59 +000039 return CompletionItemKind::Method;
40 case CXCursor_FunctionDecl:
41 case CXCursor_FunctionTemplate:
42 return CompletionItemKind::Function;
43 case CXCursor_Constructor:
Sam McCall98775c52017-12-04 13:49:59 +000044 return CompletionItemKind::Constructor;
45 case CXCursor_FieldDecl:
46 return CompletionItemKind::Field;
47 case CXCursor_VarDecl:
48 case CXCursor_ParmDecl:
49 return CompletionItemKind::Variable;
Eric Liu6f648df2017-12-19 16:50:37 +000050 // FIXME(ioeric): use LSP struct instead of class when it is suppoted in the
51 // protocol.
Sam McCall98775c52017-12-04 13:49:59 +000052 case CXCursor_StructDecl:
Eric Liu6f648df2017-12-19 16:50:37 +000053 case CXCursor_ClassDecl:
Sam McCall98775c52017-12-04 13:49:59 +000054 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;
Eric Liu6f648df2017-12-19 16:50:37 +000066 // FIXME(ioeric): figure out whether reference is the right type for aliases.
Sam McCall98775c52017-12-04 13:49:59 +000067 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
Eric Liu6f648df2017-12-19 16:50:37 +000078CompletionItemKind
79toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
80 CXCursorKind CursorKind) {
Sam McCall98775c52017-12-04 13:49:59 +000081 switch (ResKind) {
82 case CodeCompletionResult::RK_Declaration:
Eric Liu6f648df2017-12-19 16:50:37 +000083 return toCompletionItemKind(CursorKind);
Sam McCall98775c52017-12-04 13:49:59 +000084 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
Eric Liu6f648df2017-12-19 16:50:37 +000095CompletionItemKind 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
Sam McCall98775c52017-12-04 13:49:59 +0000148/// 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.
151std::string
152getOptionalParameters(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
Sam McCall98775c52017-12-04 13:49:59 +0000186/// A scored code completion result.
187/// It may be promoted to a CompletionItem if it's among the top-ranked results.
188struct 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
214private:
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
Eric Liu6f648df2017-12-19 16:50:37 +0000251/// \brief Information about the scope specifier in the qualified-id code
252/// completion (e.g. "ns::ab?").
253struct 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".
266struct 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
274SpecifiedScope extraCompletionScope(Sema &S, const CXXScopeSpec &SS);
275
Sam McCall98775c52017-12-04 13:49:59 +0000276class CompletionItemsCollector : public CodeCompleteConsumer {
277public:
278 CompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
Eric Liu6f648df2017-12-19 16:50:37 +0000279 CompletionList &Items, NameToComplete &CompletedName)
Sam McCall98775c52017-12-04 13:49:59 +0000280 : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(),
281 /*OutputIsBinary=*/false),
282 ClangdOpts(CodeCompleteOpts), Items(Items),
283 Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
Eric Liu63696e12017-12-20 17:24:31 +0000284 CCTUInfo(Allocator), CompletedName(CompletedName),
285 EnableSnippets(CodeCompleteOpts.EnableSnippets) {}
Sam McCall98775c52017-12-04 13:49:59 +0000286
287 void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
288 CodeCompletionResult *Results,
289 unsigned NumResults) override final {
Eric Liu6f648df2017-12-19 16:50:37 +0000290 if (auto SS = Context.getCXXScopeSpecifier())
291 CompletedName.SSInfo = extraCompletionScope(S, **SS);
292
293 CompletedName.Filter = S.getPreprocessor().getCodeCompletionFilter();
Sam McCall98775c52017-12-04 13:49:59 +0000294 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;
Eric Liu6f648df2017-12-19 16:50:37 +0000301 if (!CompletedName.Filter.empty() &&
302 !fuzzyMatch(S, Context, CompletedName.Filter, Result))
Sam McCall98775c52017-12-04 13:49:59 +0000303 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
326private:
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;
Sam McCall98775c52017-12-04 13:49:59 +0000367
368 Item.documentation = getDocumentation(CCS);
369 Item.sortText = Candidate.sortText();
370
Eric Liu63696e12017-12-20 17:24:31 +0000371 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;
Sam McCall98775c52017-12-04 13:49:59 +0000377
378 // Fill in the kind field of the CompletionItem.
Eric Liu6f648df2017-12-19 16:50:37 +0000379 Item.kind = toCompletionItemKind(Candidate.Result->Kind,
380 Candidate.Result->CursorKind);
Sam McCall98775c52017-12-04 13:49:59 +0000381
382 return Item;
383 }
384
Sam McCall98775c52017-12-04 13:49:59 +0000385 CodeCompleteOptions ClangdOpts;
386 CompletionList &Items;
387 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
388 CodeCompletionTUInfo CCTUInfo;
Eric Liu6f648df2017-12-19 16:50:37 +0000389 NameToComplete &CompletedName;
Eric Liu63696e12017-12-20 17:24:31 +0000390 bool EnableSnippets;
Sam McCall98775c52017-12-04 13:49:59 +0000391}; // CompletionItemsCollector
392
Sam McCall98775c52017-12-04 13:49:59 +0000393class SignatureHelpCollector final : public CodeCompleteConsumer {
394
395public:
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
427private:
Eric Liu63696e12017-12-20 17:24:31 +0000428 // FIXME(ioeric): consider moving CodeCompletionString logic here to
429 // CompletionString.h.
Sam McCall98775c52017-12-04 13:49:59 +0000430 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
Ilya Biryukov940901e2017-12-13 12:51:22 +0000488bool invokeCodeComplete(const Context &Ctx,
489 std::unique_ptr<CodeCompleteConsumer> Consumer,
Sam McCall98775c52017-12-04 13:49:59 +0000490 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,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000495 std::shared_ptr<PCHContainerOperations> PCHs) {
Sam McCall98775c52017-12-04 13:49:59 +0000496 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])) {
Ilya Biryukov940901e2017-12-13 12:51:22 +0000538 log(Ctx,
539 "BeginSourceFile() failed when running codeComplete for " + FileName);
Sam McCall98775c52017-12-04 13:49:59 +0000540 return false;
541 }
542 if (!Action.Execute()) {
Ilya Biryukov940901e2017-12-13 12:51:22 +0000543 log(Ctx, "Execute() failed when running codeComplete for " + FileName);
Sam McCall98775c52017-12-04 13:49:59 +0000544 return false;
545 }
546
547 Action.EndSourceFile();
548
549 return true;
550}
551
Eric Liu6f648df2017-12-19 16:50:37 +0000552CompletionItem 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 = Filter;
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
572void 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
587SpecifiedScope 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();
Sam McCalle3e15702017-12-19 17:05:00 +0000597 } else if (llvm::dyn_cast<TranslationUnitDecl>(DC) != nullptr) {
Eric Liu6f648df2017-12-19 16:50:37 +0000598 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
Sam McCall98775c52017-12-04 13:49:59 +0000607} // namespace
608
609clang::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
Eric Liu6f648df2017-12-19 16:50:37 +0000616 // Enable index-based code completion when Index is provided.
617 Result.IncludeNamespaceLevelDecls = !Index;
618
Sam McCall98775c52017-12-04 13:49:59 +0000619 return Result;
620}
621
Ilya Biryukov940901e2017-12-13 12:51:22 +0000622CompletionList codeComplete(const Context &Ctx, PathRef FileName,
Sam McCall98775c52017-12-04 13:49:59 +0000623 const tooling::CompileCommand &Command,
624 PrecompiledPreamble const *Preamble,
625 StringRef Contents, Position Pos,
626 IntrusiveRefCntPtr<vfs::FileSystem> VFS,
627 std::shared_ptr<PCHContainerOperations> PCHs,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000628 CodeCompleteOptions Opts) {
Sam McCall98775c52017-12-04 13:49:59 +0000629 CompletionList Results;
Eric Liu6f648df2017-12-19 16:50:37 +0000630 NameToComplete CompletedName;
Eric Liu63696e12017-12-20 17:24:31 +0000631 auto Consumer =
632 llvm::make_unique<CompletionItemsCollector>(Opts, Results, CompletedName);
Ilya Biryukov940901e2017-12-13 12:51:22 +0000633 invokeCodeComplete(Ctx, std::move(Consumer), Opts.getClangCompleteOpts(),
634 FileName, Command, Preamble, Contents, Pos, std::move(VFS),
635 std::move(PCHs));
Eric Liu6f648df2017-12-19 16:50:37 +0000636 if (Opts.Index && CompletedName.SSInfo) {
Eric Liudc641eb2017-12-19 18:10:32 +0000637 if (!Results.items.empty())
638 log(Ctx, "WARNING: Got completion results from sema for completion on "
639 "qualified ID while symbol index is provided.");
Eric Liu6f648df2017-12-19 16:50:37 +0000640 Results.items.clear();
641 completeWithIndex(Ctx, *Opts.Index, Contents, *CompletedName.SSInfo,
642 CompletedName.Filter, &Results);
643 }
Sam McCall98775c52017-12-04 13:49:59 +0000644 return Results;
645}
646
Ilya Biryukov940901e2017-12-13 12:51:22 +0000647SignatureHelp 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) {
Sam McCall98775c52017-12-04 13:49:59 +0000653 SignatureHelp Result;
654 clang::CodeCompleteOptions Options;
655 Options.IncludeGlobals = false;
656 Options.IncludeMacros = false;
657 Options.IncludeCodePatterns = false;
658 Options.IncludeBriefComments = true;
Ilya Biryukov940901e2017-12-13 12:51:22 +0000659 invokeCodeComplete(Ctx,
660 llvm::make_unique<SignatureHelpCollector>(Options, Result),
Sam McCall98775c52017-12-04 13:49:59 +0000661 Options, FileName, Command, Preamble, Contents, Pos,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000662 std::move(VFS), std::move(PCHs));
Sam McCall98775c52017-12-04 13:49:59 +0000663 return Result;
664}
665
666} // namespace clangd
667} // namespace clang