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