1 | //===- CodeCompleteConsumer.cpp - Code Completion Interface ---------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the CodeCompleteConsumer class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/Sema/CodeCompleteConsumer.h" |
14 | #include "clang-c/Index.h" |
15 | #include "clang/AST/Decl.h" |
16 | #include "clang/AST/DeclBase.h" |
17 | #include "clang/AST/DeclObjC.h" |
18 | #include "clang/AST/DeclTemplate.h" |
19 | #include "clang/AST/DeclarationName.h" |
20 | #include "clang/AST/Type.h" |
21 | #include "clang/Basic/IdentifierTable.h" |
22 | #include "clang/Lex/Preprocessor.h" |
23 | #include "clang/Sema/Sema.h" |
24 | #include "llvm/ADT/SmallString.h" |
25 | #include "llvm/ADT/SmallVector.h" |
26 | #include "llvm/ADT/StringExtras.h" |
27 | #include "llvm/ADT/StringRef.h" |
28 | #include "llvm/ADT/Twine.h" |
29 | #include "llvm/Support/Casting.h" |
30 | #include "llvm/Support/Compiler.h" |
31 | #include "llvm/Support/ErrorHandling.h" |
32 | #include "llvm/Support/FormatVariadic.h" |
33 | #include "llvm/Support/raw_ostream.h" |
34 | #include <algorithm> |
35 | #include <cassert> |
36 | #include <cstdint> |
37 | #include <string> |
38 | |
39 | using namespace clang; |
40 | |
41 | //===----------------------------------------------------------------------===// |
42 | // Code completion context implementation |
43 | //===----------------------------------------------------------------------===// |
44 | |
45 | bool CodeCompletionContext::wantConstructorResults() const { |
46 | switch (CCKind) { |
47 | case CCC_Recovery: |
48 | case CCC_Statement: |
49 | case CCC_Expression: |
50 | case CCC_ObjCMessageReceiver: |
51 | case CCC_ParenthesizedExpression: |
52 | case CCC_Symbol: |
53 | case CCC_SymbolOrNewName: |
54 | case CCC_TopLevelOrExpression: |
55 | return true; |
56 | |
57 | case CCC_TopLevel: |
58 | case CCC_ObjCInterface: |
59 | case CCC_ObjCImplementation: |
60 | case CCC_ObjCIvarList: |
61 | case CCC_ClassStructUnion: |
62 | case CCC_DotMemberAccess: |
63 | case CCC_ArrowMemberAccess: |
64 | case CCC_ObjCPropertyAccess: |
65 | case CCC_EnumTag: |
66 | case CCC_UnionTag: |
67 | case CCC_ClassOrStructTag: |
68 | case CCC_ObjCProtocolName: |
69 | case CCC_Namespace: |
70 | case CCC_Type: |
71 | case CCC_NewName: |
72 | case CCC_MacroName: |
73 | case CCC_MacroNameUse: |
74 | case CCC_PreprocessorExpression: |
75 | case CCC_PreprocessorDirective: |
76 | case CCC_NaturalLanguage: |
77 | case CCC_SelectorName: |
78 | case CCC_TypeQualifiers: |
79 | case CCC_Other: |
80 | case CCC_OtherWithMacros: |
81 | case CCC_ObjCInstanceMessage: |
82 | case CCC_ObjCClassMessage: |
83 | case CCC_ObjCInterfaceName: |
84 | case CCC_ObjCCategoryName: |
85 | case CCC_IncludedFile: |
86 | case CCC_Attribute: |
87 | case CCC_ObjCClassForwardDecl: |
88 | return false; |
89 | } |
90 | |
91 | llvm_unreachable("Invalid CodeCompletionContext::Kind!" ); |
92 | } |
93 | |
94 | StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) { |
95 | using CCKind = CodeCompletionContext::Kind; |
96 | switch (Kind) { |
97 | case CCKind::CCC_Other: |
98 | return "Other" ; |
99 | case CCKind::CCC_OtherWithMacros: |
100 | return "OtherWithMacros" ; |
101 | case CCKind::CCC_TopLevel: |
102 | return "TopLevel" ; |
103 | case CCKind::CCC_ObjCInterface: |
104 | return "ObjCInterface" ; |
105 | case CCKind::CCC_ObjCImplementation: |
106 | return "ObjCImplementation" ; |
107 | case CCKind::CCC_ObjCIvarList: |
108 | return "ObjCIvarList" ; |
109 | case CCKind::CCC_ClassStructUnion: |
110 | return "ClassStructUnion" ; |
111 | case CCKind::CCC_Statement: |
112 | return "Statement" ; |
113 | case CCKind::CCC_Expression: |
114 | return "Expression" ; |
115 | case CCKind::CCC_ObjCMessageReceiver: |
116 | return "ObjCMessageReceiver" ; |
117 | case CCKind::CCC_DotMemberAccess: |
118 | return "DotMemberAccess" ; |
119 | case CCKind::CCC_ArrowMemberAccess: |
120 | return "ArrowMemberAccess" ; |
121 | case CCKind::CCC_ObjCPropertyAccess: |
122 | return "ObjCPropertyAccess" ; |
123 | case CCKind::CCC_EnumTag: |
124 | return "EnumTag" ; |
125 | case CCKind::CCC_UnionTag: |
126 | return "UnionTag" ; |
127 | case CCKind::CCC_ClassOrStructTag: |
128 | return "ClassOrStructTag" ; |
129 | case CCKind::CCC_ObjCProtocolName: |
130 | return "ObjCProtocolName" ; |
131 | case CCKind::CCC_Namespace: |
132 | return "Namespace" ; |
133 | case CCKind::CCC_Type: |
134 | return "Type" ; |
135 | case CCKind::CCC_NewName: |
136 | return "NewName" ; |
137 | case CCKind::CCC_Symbol: |
138 | return "Symbol" ; |
139 | case CCKind::CCC_SymbolOrNewName: |
140 | return "SymbolOrNewName" ; |
141 | case CCKind::CCC_MacroName: |
142 | return "MacroName" ; |
143 | case CCKind::CCC_MacroNameUse: |
144 | return "MacroNameUse" ; |
145 | case CCKind::CCC_PreprocessorExpression: |
146 | return "PreprocessorExpression" ; |
147 | case CCKind::CCC_PreprocessorDirective: |
148 | return "PreprocessorDirective" ; |
149 | case CCKind::CCC_NaturalLanguage: |
150 | return "NaturalLanguage" ; |
151 | case CCKind::CCC_SelectorName: |
152 | return "SelectorName" ; |
153 | case CCKind::CCC_TypeQualifiers: |
154 | return "TypeQualifiers" ; |
155 | case CCKind::CCC_ParenthesizedExpression: |
156 | return "ParenthesizedExpression" ; |
157 | case CCKind::CCC_ObjCInstanceMessage: |
158 | return "ObjCInstanceMessage" ; |
159 | case CCKind::CCC_ObjCClassMessage: |
160 | return "ObjCClassMessage" ; |
161 | case CCKind::CCC_ObjCInterfaceName: |
162 | return "ObjCInterfaceName" ; |
163 | case CCKind::CCC_ObjCCategoryName: |
164 | return "ObjCCategoryName" ; |
165 | case CCKind::CCC_IncludedFile: |
166 | return "IncludedFile" ; |
167 | case CCKind::CCC_Attribute: |
168 | return "Attribute" ; |
169 | case CCKind::CCC_Recovery: |
170 | return "Recovery" ; |
171 | case CCKind::CCC_ObjCClassForwardDecl: |
172 | return "ObjCClassForwardDecl" ; |
173 | case CCKind::CCC_TopLevelOrExpression: |
174 | return "ReplTopLevel" ; |
175 | } |
176 | llvm_unreachable("Invalid CodeCompletionContext::Kind!" ); |
177 | } |
178 | |
179 | //===----------------------------------------------------------------------===// |
180 | // Code completion string implementation |
181 | //===----------------------------------------------------------------------===// |
182 | |
183 | CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) |
184 | : Kind(Kind), Text("" ) { |
185 | switch (Kind) { |
186 | case CK_TypedText: |
187 | case CK_Text: |
188 | case CK_Placeholder: |
189 | case CK_Informative: |
190 | case CK_ResultType: |
191 | case CK_CurrentParameter: |
192 | this->Text = Text; |
193 | break; |
194 | |
195 | case CK_Optional: |
196 | llvm_unreachable("Optional strings cannot be created from text" ); |
197 | |
198 | case CK_LeftParen: |
199 | this->Text = "(" ; |
200 | break; |
201 | |
202 | case CK_RightParen: |
203 | this->Text = ")" ; |
204 | break; |
205 | |
206 | case CK_LeftBracket: |
207 | this->Text = "[" ; |
208 | break; |
209 | |
210 | case CK_RightBracket: |
211 | this->Text = "]" ; |
212 | break; |
213 | |
214 | case CK_LeftBrace: |
215 | this->Text = "{" ; |
216 | break; |
217 | |
218 | case CK_RightBrace: |
219 | this->Text = "}" ; |
220 | break; |
221 | |
222 | case CK_LeftAngle: |
223 | this->Text = "<" ; |
224 | break; |
225 | |
226 | case CK_RightAngle: |
227 | this->Text = ">" ; |
228 | break; |
229 | |
230 | case CK_Comma: |
231 | this->Text = ", " ; |
232 | break; |
233 | |
234 | case CK_Colon: |
235 | this->Text = ":" ; |
236 | break; |
237 | |
238 | case CK_SemiColon: |
239 | this->Text = ";" ; |
240 | break; |
241 | |
242 | case CK_Equal: |
243 | this->Text = " = " ; |
244 | break; |
245 | |
246 | case CK_HorizontalSpace: |
247 | this->Text = " " ; |
248 | break; |
249 | |
250 | case CK_VerticalSpace: |
251 | this->Text = "\n" ; |
252 | break; |
253 | } |
254 | } |
255 | |
256 | CodeCompletionString::Chunk |
257 | CodeCompletionString::Chunk::CreateText(const char *Text) { |
258 | return Chunk(CK_Text, Text); |
259 | } |
260 | |
261 | CodeCompletionString::Chunk |
262 | CodeCompletionString::Chunk::CreateOptional(CodeCompletionString *Optional) { |
263 | Chunk Result; |
264 | Result.Kind = CK_Optional; |
265 | Result.Optional = Optional; |
266 | return Result; |
267 | } |
268 | |
269 | CodeCompletionString::Chunk |
270 | CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { |
271 | return Chunk(CK_Placeholder, Placeholder); |
272 | } |
273 | |
274 | CodeCompletionString::Chunk |
275 | CodeCompletionString::Chunk::CreateInformative(const char *Informative) { |
276 | return Chunk(CK_Informative, Informative); |
277 | } |
278 | |
279 | CodeCompletionString::Chunk |
280 | CodeCompletionString::Chunk::CreateResultType(const char *ResultType) { |
281 | return Chunk(CK_ResultType, ResultType); |
282 | } |
283 | |
284 | CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter( |
285 | const char *CurrentParameter) { |
286 | return Chunk(CK_CurrentParameter, CurrentParameter); |
287 | } |
288 | |
289 | CodeCompletionString::CodeCompletionString( |
290 | const Chunk *Chunks, unsigned NumChunks, unsigned Priority, |
291 | CXAvailabilityKind Availability, const char **Annotations, |
292 | unsigned NumAnnotations, StringRef ParentName, const char *) |
293 | : NumChunks(NumChunks), NumAnnotations(NumAnnotations), Priority(Priority), |
294 | Availability(Availability), ParentName(ParentName), |
295 | BriefComment(BriefComment) { |
296 | assert(NumChunks <= 0xffff); |
297 | assert(NumAnnotations <= 0xffff); |
298 | |
299 | Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1); |
300 | for (unsigned I = 0; I != NumChunks; ++I) |
301 | StoredChunks[I] = Chunks[I]; |
302 | |
303 | const char **StoredAnnotations = |
304 | reinterpret_cast<const char **>(StoredChunks + NumChunks); |
305 | for (unsigned I = 0; I != NumAnnotations; ++I) |
306 | StoredAnnotations[I] = Annotations[I]; |
307 | } |
308 | |
309 | unsigned CodeCompletionString::getAnnotationCount() const { |
310 | return NumAnnotations; |
311 | } |
312 | |
313 | const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const { |
314 | if (AnnotationNr < NumAnnotations) |
315 | return reinterpret_cast<const char *const *>(end())[AnnotationNr]; |
316 | else |
317 | return nullptr; |
318 | } |
319 | |
320 | std::string CodeCompletionString::getAsString() const { |
321 | std::string Result; |
322 | llvm::raw_string_ostream OS(Result); |
323 | |
324 | for (const Chunk &C : *this) { |
325 | switch (C.Kind) { |
326 | case CK_Optional: |
327 | OS << "{#" << C.Optional->getAsString() << "#}" ; |
328 | break; |
329 | case CK_Placeholder: |
330 | OS << "<#" << C.Text << "#>" ; |
331 | break; |
332 | case CK_Informative: |
333 | case CK_ResultType: |
334 | OS << "[#" << C.Text << "#]" ; |
335 | break; |
336 | case CK_CurrentParameter: |
337 | OS << "<#" << C.Text << "#>" ; |
338 | break; |
339 | default: |
340 | OS << C.Text; |
341 | break; |
342 | } |
343 | } |
344 | return Result; |
345 | } |
346 | |
347 | const char *CodeCompletionString::getTypedText() const { |
348 | for (const Chunk &C : *this) |
349 | if (C.Kind == CK_TypedText) |
350 | return C.Text; |
351 | |
352 | return nullptr; |
353 | } |
354 | |
355 | std::string CodeCompletionString::getAllTypedText() const { |
356 | std::string Res; |
357 | for (const Chunk &C : *this) |
358 | if (C.Kind == CK_TypedText) |
359 | Res += C.Text; |
360 | |
361 | return Res; |
362 | } |
363 | |
364 | const char *CodeCompletionAllocator::CopyString(const Twine &String) { |
365 | SmallString<128> Data; |
366 | StringRef Ref = String.toStringRef(Out&: Data); |
367 | // FIXME: It would be more efficient to teach Twine to tell us its size and |
368 | // then add a routine there to fill in an allocated char* with the contents |
369 | // of the string. |
370 | char *Mem = (char *)Allocate(Size: Ref.size() + 1, Alignment: 1); |
371 | std::copy(Ref.begin(), Ref.end(), Mem); |
372 | Mem[Ref.size()] = 0; |
373 | return Mem; |
374 | } |
375 | |
376 | StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { |
377 | if (!isa<NamedDecl>(Val: DC)) |
378 | return {}; |
379 | |
380 | // Check whether we've already cached the parent name. |
381 | StringRef &CachedParentName = ParentNames[DC]; |
382 | if (!CachedParentName.empty()) |
383 | return CachedParentName; |
384 | |
385 | // If we already processed this DeclContext and assigned empty to it, the |
386 | // data pointer will be non-null. |
387 | if (CachedParentName.data() != nullptr) |
388 | return {}; |
389 | |
390 | // Find the interesting names. |
391 | SmallVector<const DeclContext *, 2> Contexts; |
392 | while (DC && !DC->isFunctionOrMethod()) { |
393 | if (const auto *ND = dyn_cast<NamedDecl>(Val: DC)) { |
394 | if (ND->getIdentifier()) |
395 | Contexts.push_back(Elt: DC); |
396 | } |
397 | |
398 | DC = DC->getParent(); |
399 | } |
400 | |
401 | { |
402 | SmallString<128> S; |
403 | llvm::raw_svector_ostream OS(S); |
404 | bool First = true; |
405 | for (const DeclContext *CurDC : llvm::reverse(C&: Contexts)) { |
406 | if (First) |
407 | First = false; |
408 | else { |
409 | OS << "::" ; |
410 | } |
411 | |
412 | if (const auto *CatImpl = dyn_cast<ObjCCategoryImplDecl>(Val: CurDC)) |
413 | CurDC = CatImpl->getCategoryDecl(); |
414 | |
415 | if (const auto *Cat = dyn_cast<ObjCCategoryDecl>(Val: CurDC)) { |
416 | const ObjCInterfaceDecl *Interface = Cat->getClassInterface(); |
417 | if (!Interface) { |
418 | // Assign an empty StringRef but with non-null data to distinguish |
419 | // between empty because we didn't process the DeclContext yet. |
420 | CachedParentName = StringRef((const char *)(uintptr_t)~0U, 0); |
421 | return {}; |
422 | } |
423 | |
424 | OS << Interface->getName() << '(' << Cat->getName() << ')'; |
425 | } else { |
426 | OS << cast<NamedDecl>(Val: CurDC)->getName(); |
427 | } |
428 | } |
429 | |
430 | CachedParentName = AllocatorRef->CopyString(String: OS.str()); |
431 | } |
432 | |
433 | return CachedParentName; |
434 | } |
435 | |
436 | CodeCompletionString *CodeCompletionBuilder::TakeString() { |
437 | void *Mem = getAllocator().Allocate( |
438 | Size: sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() + |
439 | sizeof(const char *) * Annotations.size(), |
440 | Alignment: alignof(CodeCompletionString)); |
441 | CodeCompletionString *Result = new (Mem) CodeCompletionString( |
442 | Chunks.data(), Chunks.size(), Priority, Availability, Annotations.data(), |
443 | Annotations.size(), ParentName, BriefComment); |
444 | Chunks.clear(); |
445 | return Result; |
446 | } |
447 | |
448 | void CodeCompletionBuilder::AddTypedTextChunk(const char *Text) { |
449 | Chunks.push_back(Elt: Chunk(CodeCompletionString::CK_TypedText, Text)); |
450 | } |
451 | |
452 | void CodeCompletionBuilder::AddTextChunk(const char *Text) { |
453 | Chunks.push_back(Elt: Chunk::CreateText(Text)); |
454 | } |
455 | |
456 | void CodeCompletionBuilder::AddOptionalChunk(CodeCompletionString *Optional) { |
457 | Chunks.push_back(Elt: Chunk::CreateOptional(Optional)); |
458 | } |
459 | |
460 | void CodeCompletionBuilder::AddPlaceholderChunk(const char *Placeholder) { |
461 | Chunks.push_back(Elt: Chunk::CreatePlaceholder(Placeholder)); |
462 | } |
463 | |
464 | void CodeCompletionBuilder::AddInformativeChunk(const char *Text) { |
465 | Chunks.push_back(Elt: Chunk::CreateInformative(Informative: Text)); |
466 | } |
467 | |
468 | void CodeCompletionBuilder::AddResultTypeChunk(const char *ResultType) { |
469 | Chunks.push_back(Elt: Chunk::CreateResultType(ResultType)); |
470 | } |
471 | |
472 | void CodeCompletionBuilder::AddCurrentParameterChunk( |
473 | const char *CurrentParameter) { |
474 | Chunks.push_back(Elt: Chunk::CreateCurrentParameter(CurrentParameter)); |
475 | } |
476 | |
477 | void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK, |
478 | const char *Text) { |
479 | Chunks.push_back(Elt: Chunk(CK, Text)); |
480 | } |
481 | |
482 | void CodeCompletionBuilder::addParentContext(const DeclContext *DC) { |
483 | if (DC->isTranslationUnit()) |
484 | return; |
485 | |
486 | if (DC->isFunctionOrMethod()) |
487 | return; |
488 | |
489 | if (!isa<NamedDecl>(Val: DC)) |
490 | return; |
491 | |
492 | ParentName = getCodeCompletionTUInfo().getParentName(DC); |
493 | } |
494 | |
495 | void CodeCompletionBuilder::(StringRef ) { |
496 | BriefComment = Allocator.CopyString(String: Comment); |
497 | } |
498 | |
499 | //===----------------------------------------------------------------------===// |
500 | // Code completion overload candidate implementation |
501 | //===----------------------------------------------------------------------===// |
502 | FunctionDecl *CodeCompleteConsumer::OverloadCandidate::getFunction() const { |
503 | if (getKind() == CK_Function) |
504 | return Function; |
505 | else if (getKind() == CK_FunctionTemplate) |
506 | return FunctionTemplate->getTemplatedDecl(); |
507 | else |
508 | return nullptr; |
509 | } |
510 | |
511 | const FunctionType * |
512 | CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { |
513 | switch (Kind) { |
514 | case CK_Function: |
515 | return Function->getType()->getAs<FunctionType>(); |
516 | |
517 | case CK_FunctionTemplate: |
518 | return FunctionTemplate->getTemplatedDecl() |
519 | ->getType() |
520 | ->getAs<FunctionType>(); |
521 | |
522 | case CK_FunctionType: |
523 | return Type; |
524 | case CK_FunctionProtoTypeLoc: |
525 | return ProtoTypeLoc.getTypePtr(); |
526 | case CK_Template: |
527 | case CK_Aggregate: |
528 | return nullptr; |
529 | } |
530 | |
531 | llvm_unreachable("Invalid CandidateKind!" ); |
532 | } |
533 | |
534 | const FunctionProtoTypeLoc |
535 | CodeCompleteConsumer::OverloadCandidate::getFunctionProtoTypeLoc() const { |
536 | if (Kind == CK_FunctionProtoTypeLoc) |
537 | return ProtoTypeLoc; |
538 | return FunctionProtoTypeLoc(); |
539 | } |
540 | |
541 | unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const { |
542 | if (Kind == CK_Template) |
543 | return Template->getTemplateParameters()->size(); |
544 | |
545 | if (Kind == CK_Aggregate) { |
546 | unsigned Count = |
547 | std::distance(first: AggregateType->field_begin(), last: AggregateType->field_end()); |
548 | if (const auto *CRD = dyn_cast<CXXRecordDecl>(Val: AggregateType)) |
549 | Count += CRD->getNumBases(); |
550 | return Count; |
551 | } |
552 | |
553 | if (const auto *FT = getFunctionType()) |
554 | if (const auto *FPT = dyn_cast<FunctionProtoType>(Val: FT)) |
555 | return FPT->getNumParams(); |
556 | |
557 | return 0; |
558 | } |
559 | |
560 | QualType |
561 | CodeCompleteConsumer::OverloadCandidate::getParamType(unsigned N) const { |
562 | if (Kind == CK_Aggregate) { |
563 | if (const auto *CRD = dyn_cast<CXXRecordDecl>(Val: AggregateType)) { |
564 | if (N < CRD->getNumBases()) |
565 | return std::next(x: CRD->bases_begin(), n: N)->getType(); |
566 | N -= CRD->getNumBases(); |
567 | } |
568 | for (const auto *Field : AggregateType->fields()) |
569 | if (N-- == 0) |
570 | return Field->getType(); |
571 | return QualType(); |
572 | } |
573 | |
574 | if (Kind == CK_Template) { |
575 | TemplateParameterList *TPL = getTemplate()->getTemplateParameters(); |
576 | if (N < TPL->size()) |
577 | if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(Val: TPL->getParam(Idx: N))) |
578 | return D->getType(); |
579 | return QualType(); |
580 | } |
581 | |
582 | if (const auto *FT = getFunctionType()) |
583 | if (const auto *FPT = dyn_cast<FunctionProtoType>(Val: FT)) |
584 | if (N < FPT->getNumParams()) |
585 | return FPT->getParamType(i: N); |
586 | return QualType(); |
587 | } |
588 | |
589 | const NamedDecl * |
590 | CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const { |
591 | if (Kind == CK_Aggregate) { |
592 | if (const auto *CRD = dyn_cast<CXXRecordDecl>(Val: AggregateType)) { |
593 | if (N < CRD->getNumBases()) |
594 | return std::next(x: CRD->bases_begin(), n: N)->getType()->getAsTagDecl(); |
595 | N -= CRD->getNumBases(); |
596 | } |
597 | for (const auto *Field : AggregateType->fields()) |
598 | if (N-- == 0) |
599 | return Field; |
600 | return nullptr; |
601 | } |
602 | |
603 | if (Kind == CK_Template) { |
604 | TemplateParameterList *TPL = getTemplate()->getTemplateParameters(); |
605 | if (N < TPL->size()) |
606 | return TPL->getParam(Idx: N); |
607 | return nullptr; |
608 | } |
609 | |
610 | // Note that if we only have a FunctionProtoType, we don't have param decls. |
611 | if (const auto *FD = getFunction()) { |
612 | if (N < FD->param_size()) |
613 | return FD->getParamDecl(i: N); |
614 | } else if (Kind == CK_FunctionProtoTypeLoc) { |
615 | if (N < ProtoTypeLoc.getNumParams()) { |
616 | return ProtoTypeLoc.getParam(i: N); |
617 | } |
618 | } |
619 | |
620 | return nullptr; |
621 | } |
622 | |
623 | //===----------------------------------------------------------------------===// |
624 | // Code completion consumer implementation |
625 | //===----------------------------------------------------------------------===// |
626 | |
627 | CodeCompleteConsumer::~CodeCompleteConsumer() = default; |
628 | |
629 | bool PrintingCodeCompleteConsumer::isResultFilteredOut( |
630 | StringRef Filter, CodeCompletionResult Result) { |
631 | switch (Result.Kind) { |
632 | case CodeCompletionResult::RK_Declaration: |
633 | return !( |
634 | Result.Declaration->getIdentifier() && |
635 | Result.Declaration->getIdentifier()->getName().starts_with(Prefix: Filter)); |
636 | case CodeCompletionResult::RK_Keyword: |
637 | return !StringRef(Result.Keyword).starts_with(Prefix: Filter); |
638 | case CodeCompletionResult::RK_Macro: |
639 | return !Result.Macro->getName().starts_with(Prefix: Filter); |
640 | case CodeCompletionResult::RK_Pattern: |
641 | return !(Result.Pattern->getTypedText() && |
642 | StringRef(Result.Pattern->getTypedText()).starts_with(Prefix: Filter)); |
643 | } |
644 | llvm_unreachable("Unknown code completion result Kind." ); |
645 | } |
646 | |
647 | void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults( |
648 | Sema &SemaRef, CodeCompletionContext Context, CodeCompletionResult *Results, |
649 | unsigned NumResults) { |
650 | std::stable_sort(first: Results, last: Results + NumResults); |
651 | |
652 | if (!Context.getPreferredType().isNull()) |
653 | OS << "PREFERRED-TYPE: " << Context.getPreferredType() << '\n'; |
654 | |
655 | StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter(); |
656 | // Print the completions. |
657 | for (unsigned I = 0; I != NumResults; ++I) { |
658 | if (!Filter.empty() && isResultFilteredOut(Filter, Result: Results[I])) |
659 | continue; |
660 | OS << "COMPLETION: " ; |
661 | switch (Results[I].Kind) { |
662 | case CodeCompletionResult::RK_Declaration: |
663 | OS << *Results[I].Declaration; |
664 | { |
665 | std::vector<std::string> Tags; |
666 | if (Results[I].Hidden) |
667 | Tags.push_back(x: "Hidden" ); |
668 | if (Results[I].InBaseClass) |
669 | Tags.push_back(x: "InBase" ); |
670 | if (Results[I].Availability == |
671 | CXAvailabilityKind::CXAvailability_NotAccessible) |
672 | Tags.push_back(x: "Inaccessible" ); |
673 | if (!Tags.empty()) |
674 | OS << " (" << llvm::join(R&: Tags, Separator: "," ) << ")" ; |
675 | } |
676 | if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString( |
677 | S&: SemaRef, CCContext: Context, Allocator&: getAllocator(), CCTUInfo, |
678 | IncludeBriefComments: includeBriefComments())) { |
679 | OS << " : " << CCS->getAsString(); |
680 | if (const char * = CCS->getBriefComment()) |
681 | OS << " : " << BriefComment; |
682 | } |
683 | break; |
684 | |
685 | case CodeCompletionResult::RK_Keyword: |
686 | OS << Results[I].Keyword; |
687 | break; |
688 | |
689 | case CodeCompletionResult::RK_Macro: |
690 | OS << Results[I].Macro->getName(); |
691 | if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString( |
692 | S&: SemaRef, CCContext: Context, Allocator&: getAllocator(), CCTUInfo, |
693 | IncludeBriefComments: includeBriefComments())) { |
694 | OS << " : " << CCS->getAsString(); |
695 | } |
696 | break; |
697 | |
698 | case CodeCompletionResult::RK_Pattern: |
699 | OS << "Pattern : " << Results[I].Pattern->getAsString(); |
700 | break; |
701 | } |
702 | for (const FixItHint &FixIt : Results[I].FixIts) { |
703 | const SourceLocation BLoc = FixIt.RemoveRange.getBegin(); |
704 | const SourceLocation ELoc = FixIt.RemoveRange.getEnd(); |
705 | |
706 | SourceManager &SM = SemaRef.SourceMgr; |
707 | std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(Loc: BLoc); |
708 | std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(Loc: ELoc); |
709 | // Adjust for token ranges. |
710 | if (FixIt.RemoveRange.isTokenRange()) |
711 | EInfo.second += Lexer::MeasureTokenLength(Loc: ELoc, SM, LangOpts: SemaRef.LangOpts); |
712 | |
713 | OS << " (requires fix-it:" |
714 | << " {" << SM.getLineNumber(FID: BInfo.first, FilePos: BInfo.second) << ':' |
715 | << SM.getColumnNumber(FID: BInfo.first, FilePos: BInfo.second) << '-' |
716 | << SM.getLineNumber(FID: EInfo.first, FilePos: EInfo.second) << ':' |
717 | << SM.getColumnNumber(FID: EInfo.first, FilePos: EInfo.second) << "}" |
718 | << " to \"" << FixIt.CodeToInsert << "\")" ; |
719 | } |
720 | OS << '\n'; |
721 | } |
722 | } |
723 | |
724 | // This function is used solely to preserve the former presentation of overloads |
725 | // by "clang -cc1 -code-completion-at", since CodeCompletionString::getAsString |
726 | // needs to be improved for printing the newer and more detailed overload |
727 | // chunks. |
728 | static std::string getOverloadAsString(const CodeCompletionString &CCS) { |
729 | std::string Result; |
730 | llvm::raw_string_ostream OS(Result); |
731 | |
732 | for (auto &C : CCS) { |
733 | switch (C.Kind) { |
734 | case CodeCompletionString::CK_Informative: |
735 | case CodeCompletionString::CK_ResultType: |
736 | OS << "[#" << C.Text << "#]" ; |
737 | break; |
738 | |
739 | case CodeCompletionString::CK_CurrentParameter: |
740 | OS << "<#" << C.Text << "#>" ; |
741 | break; |
742 | |
743 | // FIXME: We can also print optional parameters of an overload. |
744 | case CodeCompletionString::CK_Optional: |
745 | break; |
746 | |
747 | default: |
748 | OS << C.Text; |
749 | break; |
750 | } |
751 | } |
752 | return Result; |
753 | } |
754 | |
755 | void PrintingCodeCompleteConsumer::ProcessOverloadCandidates( |
756 | Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates, |
757 | unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) { |
758 | OS << "OPENING_PAREN_LOC: " ; |
759 | OpenParLoc.print(OS, SM: SemaRef.getSourceManager()); |
760 | OS << "\n" ; |
761 | |
762 | for (unsigned I = 0; I != NumCandidates; ++I) { |
763 | if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString( |
764 | CurrentArg, S&: SemaRef, Allocator&: getAllocator(), CCTUInfo, |
765 | IncludeBriefComments: includeBriefComments(), Braced)) { |
766 | OS << "OVERLOAD: " << getOverloadAsString(CCS: *CCS) << "\n" ; |
767 | } |
768 | } |
769 | } |
770 | |
771 | /// Retrieve the effective availability of the given declaration. |
772 | static AvailabilityResult getDeclAvailability(const Decl *D) { |
773 | AvailabilityResult AR = D->getAvailability(); |
774 | if (isa<EnumConstantDecl>(Val: D)) |
775 | AR = std::max(a: AR, b: cast<Decl>(Val: D->getDeclContext())->getAvailability()); |
776 | return AR; |
777 | } |
778 | |
779 | void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { |
780 | switch (Kind) { |
781 | case RK_Pattern: |
782 | if (!Declaration) { |
783 | // Do nothing: Patterns can come with cursor kinds! |
784 | break; |
785 | } |
786 | [[fallthrough]]; |
787 | |
788 | case RK_Declaration: { |
789 | // Set the availability based on attributes. |
790 | switch (getDeclAvailability(D: Declaration)) { |
791 | case AR_Available: |
792 | case AR_NotYetIntroduced: |
793 | Availability = CXAvailability_Available; |
794 | break; |
795 | |
796 | case AR_Deprecated: |
797 | Availability = CXAvailability_Deprecated; |
798 | break; |
799 | |
800 | case AR_Unavailable: |
801 | Availability = CXAvailability_NotAvailable; |
802 | break; |
803 | } |
804 | |
805 | if (const auto *Function = dyn_cast<FunctionDecl>(Val: Declaration)) |
806 | if (Function->isDeleted()) |
807 | Availability = CXAvailability_NotAvailable; |
808 | |
809 | CursorKind = getCursorKindForDecl(D: Declaration); |
810 | if (CursorKind == CXCursor_UnexposedDecl) { |
811 | // FIXME: Forward declarations of Objective-C classes and protocols |
812 | // are not directly exposed, but we want code completion to treat them |
813 | // like a definition. |
814 | if (isa<ObjCInterfaceDecl>(Val: Declaration)) |
815 | CursorKind = CXCursor_ObjCInterfaceDecl; |
816 | else if (isa<ObjCProtocolDecl>(Val: Declaration)) |
817 | CursorKind = CXCursor_ObjCProtocolDecl; |
818 | else |
819 | CursorKind = CXCursor_NotImplemented; |
820 | } |
821 | break; |
822 | } |
823 | |
824 | case RK_Macro: |
825 | case RK_Keyword: |
826 | llvm_unreachable("Macro and keyword kinds are handled by the constructors" ); |
827 | } |
828 | |
829 | if (!Accessible) |
830 | Availability = CXAvailability_NotAccessible; |
831 | } |
832 | |
833 | /// Retrieve the name that should be used to order a result. |
834 | /// |
835 | /// If the name needs to be constructed as a string, that string will be |
836 | /// saved into Saved and the returned StringRef will refer to it. |
837 | StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const { |
838 | switch (Kind) { |
839 | case RK_Keyword: |
840 | return Keyword; |
841 | case RK_Pattern: |
842 | return Pattern->getTypedText(); |
843 | case RK_Macro: |
844 | return Macro->getName(); |
845 | case RK_Declaration: |
846 | // Handle declarations below. |
847 | break; |
848 | } |
849 | |
850 | DeclarationName Name = Declaration->getDeclName(); |
851 | |
852 | // If the name is a simple identifier (by far the common case), or a |
853 | // zero-argument selector, just return a reference to that identifier. |
854 | if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) |
855 | return Id->getName(); |
856 | if (Name.isObjCZeroArgSelector()) |
857 | if (const IdentifierInfo *Id = |
858 | Name.getObjCSelector().getIdentifierInfoForSlot(argIndex: 0)) |
859 | return Id->getName(); |
860 | |
861 | Saved = Name.getAsString(); |
862 | return Saved; |
863 | } |
864 | |
865 | bool clang::operator<(const CodeCompletionResult &X, |
866 | const CodeCompletionResult &Y) { |
867 | std::string XSaved, YSaved; |
868 | StringRef XStr = X.getOrderedName(Saved&: XSaved); |
869 | StringRef YStr = Y.getOrderedName(Saved&: YSaved); |
870 | int cmp = XStr.compare_insensitive(RHS: YStr); |
871 | if (cmp) |
872 | return cmp < 0; |
873 | |
874 | // If case-insensitive comparison fails, try case-sensitive comparison. |
875 | return XStr.compare(RHS: YStr) < 0; |
876 | } |
877 | |