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