872 lines · cpp
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-exception6//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 35using namespace clang;36 37//===----------------------------------------------------------------------===//38// Code completion context implementation39//===----------------------------------------------------------------------===//40 41bool 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 90StringRef 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 implementation177//===----------------------------------------------------------------------===//178 179CodeCompletionString::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 252CodeCompletionString::Chunk253CodeCompletionString::Chunk::CreateText(const char *Text) {254 return Chunk(CK_Text, Text);255}256 257CodeCompletionString::Chunk258CodeCompletionString::Chunk::CreateOptional(CodeCompletionString *Optional) {259 Chunk Result;260 Result.Kind = CK_Optional;261 Result.Optional = Optional;262 return Result;263}264 265CodeCompletionString::Chunk266CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {267 return Chunk(CK_Placeholder, Placeholder);268}269 270CodeCompletionString::Chunk271CodeCompletionString::Chunk::CreateInformative(const char *Informative) {272 return Chunk(CK_Informative, Informative);273}274 275CodeCompletionString::Chunk276CodeCompletionString::Chunk::CreateResultType(const char *ResultType) {277 return Chunk(CK_ResultType, ResultType);278}279 280CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter(281 const char *CurrentParameter) {282 return Chunk(CK_CurrentParameter, CurrentParameter);283}284 285CodeCompletionString::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 305unsigned CodeCompletionString::getAnnotationCount() const {306 return NumAnnotations;307}308 309const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const {310 if (AnnotationNr < NumAnnotations)311 return reinterpret_cast<const char *const *>(end())[AnnotationNr];312 else313 return nullptr;314}315 316std::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 343const 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 351std::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 360const char *CodeCompletionAllocator::CopyString(const Twine &String) {361 SmallString<128> Data;362 StringRef Ref = String.toStringRef(Data);363 // FIXME: It would be more efficient to teach Twine to tell us its size and364 // then add a routine there to fill in an allocated char* with the contents365 // of the string.366 char *Mem = (char *)Allocate(Ref.size() + 1, 1);367 std::copy(Ref.begin(), Ref.end(), Mem);368 Mem[Ref.size()] = 0;369 return Mem;370}371 372StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {373 if (!isa<NamedDecl>(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, the382 // 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>(DC)) {390 if (ND->getIdentifier())391 Contexts.push_back(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(Contexts)) {402 if (First)403 First = false;404 else {405 OS << "::";406 }407 408 if (const auto *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))409 CurDC = CatImpl->getCategoryDecl();410 411 if (const auto *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {412 const ObjCInterfaceDecl *Interface = Cat->getClassInterface();413 if (!Interface) {414 // Assign an empty StringRef but with non-null data to distinguish415 // 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>(CurDC)->getName();423 }424 }425 426 CachedParentName = AllocatorRef->CopyString(OS.str());427 }428 429 return CachedParentName;430}431 432CodeCompletionString *CodeCompletionBuilder::TakeString() {433 void *Mem = getAllocator().Allocate(434 sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() +435 sizeof(const char *) * Annotations.size(),436 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 444void CodeCompletionBuilder::AddTypedTextChunk(const char *Text) {445 Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text));446}447 448void CodeCompletionBuilder::AddTextChunk(const char *Text) {449 Chunks.push_back(Chunk::CreateText(Text));450}451 452void CodeCompletionBuilder::AddOptionalChunk(CodeCompletionString *Optional) {453 Chunks.push_back(Chunk::CreateOptional(Optional));454}455 456void CodeCompletionBuilder::AddPlaceholderChunk(const char *Placeholder) {457 Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));458}459 460void CodeCompletionBuilder::AddInformativeChunk(const char *Text) {461 Chunks.push_back(Chunk::CreateInformative(Text));462}463 464void CodeCompletionBuilder::AddResultTypeChunk(const char *ResultType) {465 Chunks.push_back(Chunk::CreateResultType(ResultType));466}467 468void CodeCompletionBuilder::AddCurrentParameterChunk(469 const char *CurrentParameter) {470 Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter));471}472 473void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,474 const char *Text) {475 Chunks.push_back(Chunk(CK, Text));476}477 478void CodeCompletionBuilder::addParentContext(const DeclContext *DC) {479 if (DC->isTranslationUnit())480 return;481 482 if (DC->isFunctionOrMethod())483 return;484 485 if (!isa<NamedDecl>(DC))486 return;487 488 ParentName = getCodeCompletionTUInfo().getParentName(DC);489}490 491void CodeCompletionBuilder::addBriefComment(StringRef Comment) {492 BriefComment = Allocator.CopyString(Comment);493}494 495//===----------------------------------------------------------------------===//496// Code completion overload candidate implementation497//===----------------------------------------------------------------------===//498FunctionDecl *CodeCompleteConsumer::OverloadCandidate::getFunction() const {499 if (getKind() == CK_Function)500 return Function;501 else if (getKind() == CK_FunctionTemplate)502 return FunctionTemplate->getTemplatedDecl();503 else504 return nullptr;505}506 507const FunctionType *508CodeCompleteConsumer::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 530const FunctionProtoTypeLoc531CodeCompleteConsumer::OverloadCandidate::getFunctionProtoTypeLoc() const {532 if (Kind == CK_FunctionProtoTypeLoc)533 return ProtoTypeLoc;534 return FunctionProtoTypeLoc();535}536 537unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const {538 if (Kind == CK_Template)539 return Template->getTemplateParameters()->size();540 541 if (Kind == CK_Aggregate) {542 unsigned Count = AggregateType->getNumFields();543 if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType))544 Count += CRD->getNumBases();545 return Count;546 }547 548 if (const auto *FT = getFunctionType())549 if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))550 return FPT->getNumParams();551 552 return 0;553}554 555QualType556CodeCompleteConsumer::OverloadCandidate::getParamType(unsigned N) const {557 if (Kind == CK_Aggregate) {558 if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {559 if (N < CRD->getNumBases())560 return std::next(CRD->bases_begin(), N)->getType();561 N -= CRD->getNumBases();562 }563 for (const auto *Field : AggregateType->fields())564 if (N-- == 0)565 return Field->getType();566 return QualType();567 }568 569 if (Kind == CK_Template) {570 TemplateParameterList *TPL = getTemplate()->getTemplateParameters();571 if (N < TPL->size())572 if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(TPL->getParam(N)))573 return D->getType();574 return QualType();575 }576 577 if (const auto *FT = getFunctionType())578 if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))579 if (N < FPT->getNumParams())580 return FPT->getParamType(N);581 return QualType();582}583 584const NamedDecl *585CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const {586 if (Kind == CK_Aggregate) {587 if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {588 if (N < CRD->getNumBases())589 return std::next(CRD->bases_begin(), N)->getType()->getAsTagDecl();590 N -= CRD->getNumBases();591 }592 for (const auto *Field : AggregateType->fields())593 if (N-- == 0)594 return Field;595 return nullptr;596 }597 598 if (Kind == CK_Template) {599 TemplateParameterList *TPL = getTemplate()->getTemplateParameters();600 if (N < TPL->size())601 return TPL->getParam(N);602 return nullptr;603 }604 605 // Note that if we only have a FunctionProtoType, we don't have param decls.606 if (const auto *FD = getFunction()) {607 if (N < FD->param_size())608 return FD->getParamDecl(N);609 } else if (Kind == CK_FunctionProtoTypeLoc) {610 if (N < ProtoTypeLoc.getNumParams()) {611 return ProtoTypeLoc.getParam(N);612 }613 }614 615 return nullptr;616}617 618//===----------------------------------------------------------------------===//619// Code completion consumer implementation620//===----------------------------------------------------------------------===//621 622CodeCompleteConsumer::~CodeCompleteConsumer() = default;623 624bool PrintingCodeCompleteConsumer::isResultFilteredOut(625 StringRef Filter, CodeCompletionResult Result) {626 switch (Result.Kind) {627 case CodeCompletionResult::RK_Declaration:628 return !(629 Result.Declaration->getIdentifier() &&630 Result.Declaration->getIdentifier()->getName().starts_with(Filter));631 case CodeCompletionResult::RK_Keyword:632 return !StringRef(Result.Keyword).starts_with(Filter);633 case CodeCompletionResult::RK_Macro:634 return !Result.Macro->getName().starts_with(Filter);635 case CodeCompletionResult::RK_Pattern:636 return !(Result.Pattern->getTypedText() &&637 StringRef(Result.Pattern->getTypedText()).starts_with(Filter));638 }639 llvm_unreachable("Unknown code completion result Kind.");640}641 642void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(643 Sema &SemaRef, CodeCompletionContext Context, CodeCompletionResult *Results,644 unsigned NumResults) {645 std::stable_sort(Results, Results + NumResults);646 647 if (!Context.getPreferredType().isNull())648 OS << "PREFERRED-TYPE: " << Context.getPreferredType() << '\n';649 650 StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();651 // Print the completions.652 for (unsigned I = 0; I != NumResults; ++I) {653 if (!Filter.empty() && isResultFilteredOut(Filter, Results[I]))654 continue;655 OS << "COMPLETION: ";656 switch (Results[I].Kind) {657 case CodeCompletionResult::RK_Declaration:658 OS << *Results[I].Declaration;659 {660 std::vector<std::string> Tags;661 if (Results[I].Hidden)662 Tags.push_back("Hidden");663 if (Results[I].InBaseClass)664 Tags.push_back("InBase");665 if (Results[I].Availability ==666 CXAvailabilityKind::CXAvailability_NotAccessible)667 Tags.push_back("Inaccessible");668 if (!Tags.empty())669 OS << " (" << llvm::join(Tags, ",") << ")";670 }671 if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(672 SemaRef, Context, getAllocator(), CCTUInfo,673 includeBriefComments())) {674 OS << " : " << CCS->getAsString();675 if (const char *BriefComment = CCS->getBriefComment())676 OS << " : " << BriefComment;677 }678 break;679 680 case CodeCompletionResult::RK_Keyword:681 OS << Results[I].Keyword;682 break;683 684 case CodeCompletionResult::RK_Macro:685 OS << Results[I].Macro->getName();686 if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(687 SemaRef, Context, getAllocator(), CCTUInfo,688 includeBriefComments())) {689 OS << " : " << CCS->getAsString();690 }691 break;692 693 case CodeCompletionResult::RK_Pattern:694 OS << "Pattern : " << Results[I].Pattern->getAsString();695 break;696 }697 for (const FixItHint &FixIt : Results[I].FixIts) {698 const SourceLocation BLoc = FixIt.RemoveRange.getBegin();699 const SourceLocation ELoc = FixIt.RemoveRange.getEnd();700 701 SourceManager &SM = SemaRef.SourceMgr;702 FileIDAndOffset BInfo = SM.getDecomposedLoc(BLoc);703 FileIDAndOffset EInfo = SM.getDecomposedLoc(ELoc);704 // Adjust for token ranges.705 if (FixIt.RemoveRange.isTokenRange())706 EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts);707 708 OS << " (requires fix-it:"709 << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':'710 << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'711 << SM.getLineNumber(EInfo.first, EInfo.second) << ':'712 << SM.getColumnNumber(EInfo.first, EInfo.second) << "}"713 << " to \"" << FixIt.CodeToInsert << "\")";714 }715 OS << '\n';716 }717}718 719// This function is used solely to preserve the former presentation of overloads720// by "clang -cc1 -code-completion-at", since CodeCompletionString::getAsString721// needs to be improved for printing the newer and more detailed overload722// chunks.723static std::string getOverloadAsString(const CodeCompletionString &CCS) {724 std::string Result;725 llvm::raw_string_ostream OS(Result);726 727 for (auto &C : CCS) {728 switch (C.Kind) {729 case CodeCompletionString::CK_Informative:730 case CodeCompletionString::CK_ResultType:731 OS << "[#" << C.Text << "#]";732 break;733 734 case CodeCompletionString::CK_CurrentParameter:735 OS << "<#" << C.Text << "#>";736 break;737 738 // FIXME: We can also print optional parameters of an overload.739 case CodeCompletionString::CK_Optional:740 break;741 742 default:743 OS << C.Text;744 break;745 }746 }747 return Result;748}749 750void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(751 Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates,752 unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) {753 OS << "OPENING_PAREN_LOC: ";754 OpenParLoc.print(OS, SemaRef.getSourceManager());755 OS << "\n";756 757 for (unsigned I = 0; I != NumCandidates; ++I) {758 if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString(759 CurrentArg, SemaRef, getAllocator(), CCTUInfo,760 includeBriefComments(), Braced)) {761 OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n";762 }763 }764}765 766/// Retrieve the effective availability of the given declaration.767static AvailabilityResult getDeclAvailability(const Decl *D) {768 AvailabilityResult AR = D->getAvailability();769 if (isa<EnumConstantDecl>(D))770 AR = std::max(AR, cast<Decl>(D->getDeclContext())->getAvailability());771 return AR;772}773 774void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {775 switch (Kind) {776 case RK_Pattern:777 if (!Declaration) {778 // Do nothing: Patterns can come with cursor kinds!779 break;780 }781 [[fallthrough]];782 783 case RK_Declaration: {784 // Set the availability based on attributes.785 switch (getDeclAvailability(Declaration)) {786 case AR_Available:787 case AR_NotYetIntroduced:788 Availability = CXAvailability_Available;789 break;790 791 case AR_Deprecated:792 Availability = CXAvailability_Deprecated;793 break;794 795 case AR_Unavailable:796 Availability = CXAvailability_NotAvailable;797 break;798 }799 800 if (const auto *Function = dyn_cast<FunctionDecl>(Declaration))801 if (Function->isDeleted())802 Availability = CXAvailability_NotAvailable;803 804 CursorKind = getCursorKindForDecl(Declaration);805 if (CursorKind == CXCursor_UnexposedDecl) {806 // FIXME: Forward declarations of Objective-C classes and protocols807 // are not directly exposed, but we want code completion to treat them808 // like a definition.809 if (isa<ObjCInterfaceDecl>(Declaration))810 CursorKind = CXCursor_ObjCInterfaceDecl;811 else if (isa<ObjCProtocolDecl>(Declaration))812 CursorKind = CXCursor_ObjCProtocolDecl;813 else814 CursorKind = CXCursor_NotImplemented;815 }816 break;817 }818 819 case RK_Macro:820 case RK_Keyword:821 llvm_unreachable("Macro and keyword kinds are handled by the constructors");822 }823 824 if (!Accessible)825 Availability = CXAvailability_NotAccessible;826}827 828/// Retrieve the name that should be used to order a result.829///830/// If the name needs to be constructed as a string, that string will be831/// saved into Saved and the returned StringRef will refer to it.832StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const {833 switch (Kind) {834 case RK_Keyword:835 return Keyword;836 case RK_Pattern:837 return Pattern->getTypedText();838 case RK_Macro:839 return Macro->getName();840 case RK_Declaration:841 // Handle declarations below.842 break;843 }844 845 DeclarationName Name = Declaration->getDeclName();846 847 // If the name is a simple identifier (by far the common case), or a848 // zero-argument selector, just return a reference to that identifier.849 if (IdentifierInfo *Id = Name.getAsIdentifierInfo())850 return Id->getName();851 if (Name.isObjCZeroArgSelector())852 if (const IdentifierInfo *Id =853 Name.getObjCSelector().getIdentifierInfoForSlot(0))854 return Id->getName();855 856 Saved = Name.getAsString();857 return Saved;858}859 860bool clang::operator<(const CodeCompletionResult &X,861 const CodeCompletionResult &Y) {862 std::string XSaved, YSaved;863 StringRef XStr = X.getOrderedName(XSaved);864 StringRef YStr = Y.getOrderedName(YSaved);865 int cmp = XStr.compare_insensitive(YStr);866 if (cmp)867 return cmp < 0;868 869 // If case-insensitive comparison fails, try case-sensitive comparison.870 return XStr.compare(YStr) < 0;871}872