Path: blob/main/contrib/llvm-project/clang/lib/Sema/CodeCompleteConsumer.cpp
35233 views
//===- CodeCompleteConsumer.cpp - Code Completion Interface ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the CodeCompleteConsumer class.9//10//===----------------------------------------------------------------------===//1112#include "clang/Sema/CodeCompleteConsumer.h"13#include "clang-c/Index.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclBase.h"16#include "clang/AST/DeclObjC.h"17#include "clang/AST/DeclTemplate.h"18#include "clang/AST/DeclarationName.h"19#include "clang/AST/Type.h"20#include "clang/Basic/IdentifierTable.h"21#include "clang/Lex/Preprocessor.h"22#include "clang/Sema/Sema.h"23#include "llvm/ADT/SmallString.h"24#include "llvm/ADT/SmallVector.h"25#include "llvm/ADT/StringExtras.h"26#include "llvm/ADT/StringRef.h"27#include "llvm/ADT/Twine.h"28#include "llvm/Support/Casting.h"29#include "llvm/Support/Compiler.h"30#include "llvm/Support/ErrorHandling.h"31#include "llvm/Support/FormatVariadic.h"32#include "llvm/Support/raw_ostream.h"33#include <algorithm>34#include <cassert>35#include <cstdint>36#include <string>3738using namespace clang;3940//===----------------------------------------------------------------------===//41// Code completion context implementation42//===----------------------------------------------------------------------===//4344bool CodeCompletionContext::wantConstructorResults() const {45switch (CCKind) {46case CCC_Recovery:47case CCC_Statement:48case CCC_Expression:49case CCC_ObjCMessageReceiver:50case CCC_ParenthesizedExpression:51case CCC_Symbol:52case CCC_SymbolOrNewName:53case CCC_TopLevelOrExpression:54return true;5556case CCC_TopLevel:57case CCC_ObjCInterface:58case CCC_ObjCImplementation:59case CCC_ObjCIvarList:60case CCC_ClassStructUnion:61case CCC_DotMemberAccess:62case CCC_ArrowMemberAccess:63case CCC_ObjCPropertyAccess:64case CCC_EnumTag:65case CCC_UnionTag:66case CCC_ClassOrStructTag:67case CCC_ObjCProtocolName:68case CCC_Namespace:69case CCC_Type:70case CCC_NewName:71case CCC_MacroName:72case CCC_MacroNameUse:73case CCC_PreprocessorExpression:74case CCC_PreprocessorDirective:75case CCC_NaturalLanguage:76case CCC_SelectorName:77case CCC_TypeQualifiers:78case CCC_Other:79case CCC_OtherWithMacros:80case CCC_ObjCInstanceMessage:81case CCC_ObjCClassMessage:82case CCC_ObjCInterfaceName:83case CCC_ObjCCategoryName:84case CCC_IncludedFile:85case CCC_Attribute:86case CCC_ObjCClassForwardDecl:87return false;88}8990llvm_unreachable("Invalid CodeCompletionContext::Kind!");91}9293StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) {94using CCKind = CodeCompletionContext::Kind;95switch (Kind) {96case CCKind::CCC_Other:97return "Other";98case CCKind::CCC_OtherWithMacros:99return "OtherWithMacros";100case CCKind::CCC_TopLevel:101return "TopLevel";102case CCKind::CCC_ObjCInterface:103return "ObjCInterface";104case CCKind::CCC_ObjCImplementation:105return "ObjCImplementation";106case CCKind::CCC_ObjCIvarList:107return "ObjCIvarList";108case CCKind::CCC_ClassStructUnion:109return "ClassStructUnion";110case CCKind::CCC_Statement:111return "Statement";112case CCKind::CCC_Expression:113return "Expression";114case CCKind::CCC_ObjCMessageReceiver:115return "ObjCMessageReceiver";116case CCKind::CCC_DotMemberAccess:117return "DotMemberAccess";118case CCKind::CCC_ArrowMemberAccess:119return "ArrowMemberAccess";120case CCKind::CCC_ObjCPropertyAccess:121return "ObjCPropertyAccess";122case CCKind::CCC_EnumTag:123return "EnumTag";124case CCKind::CCC_UnionTag:125return "UnionTag";126case CCKind::CCC_ClassOrStructTag:127return "ClassOrStructTag";128case CCKind::CCC_ObjCProtocolName:129return "ObjCProtocolName";130case CCKind::CCC_Namespace:131return "Namespace";132case CCKind::CCC_Type:133return "Type";134case CCKind::CCC_NewName:135return "NewName";136case CCKind::CCC_Symbol:137return "Symbol";138case CCKind::CCC_SymbolOrNewName:139return "SymbolOrNewName";140case CCKind::CCC_MacroName:141return "MacroName";142case CCKind::CCC_MacroNameUse:143return "MacroNameUse";144case CCKind::CCC_PreprocessorExpression:145return "PreprocessorExpression";146case CCKind::CCC_PreprocessorDirective:147return "PreprocessorDirective";148case CCKind::CCC_NaturalLanguage:149return "NaturalLanguage";150case CCKind::CCC_SelectorName:151return "SelectorName";152case CCKind::CCC_TypeQualifiers:153return "TypeQualifiers";154case CCKind::CCC_ParenthesizedExpression:155return "ParenthesizedExpression";156case CCKind::CCC_ObjCInstanceMessage:157return "ObjCInstanceMessage";158case CCKind::CCC_ObjCClassMessage:159return "ObjCClassMessage";160case CCKind::CCC_ObjCInterfaceName:161return "ObjCInterfaceName";162case CCKind::CCC_ObjCCategoryName:163return "ObjCCategoryName";164case CCKind::CCC_IncludedFile:165return "IncludedFile";166case CCKind::CCC_Attribute:167return "Attribute";168case CCKind::CCC_Recovery:169return "Recovery";170case CCKind::CCC_ObjCClassForwardDecl:171return "ObjCClassForwardDecl";172case CCKind::CCC_TopLevelOrExpression:173return "ReplTopLevel";174}175llvm_unreachable("Invalid CodeCompletionContext::Kind!");176}177178//===----------------------------------------------------------------------===//179// Code completion string implementation180//===----------------------------------------------------------------------===//181182CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)183: Kind(Kind), Text("") {184switch (Kind) {185case CK_TypedText:186case CK_Text:187case CK_Placeholder:188case CK_Informative:189case CK_ResultType:190case CK_CurrentParameter:191this->Text = Text;192break;193194case CK_Optional:195llvm_unreachable("Optional strings cannot be created from text");196197case CK_LeftParen:198this->Text = "(";199break;200201case CK_RightParen:202this->Text = ")";203break;204205case CK_LeftBracket:206this->Text = "[";207break;208209case CK_RightBracket:210this->Text = "]";211break;212213case CK_LeftBrace:214this->Text = "{";215break;216217case CK_RightBrace:218this->Text = "}";219break;220221case CK_LeftAngle:222this->Text = "<";223break;224225case CK_RightAngle:226this->Text = ">";227break;228229case CK_Comma:230this->Text = ", ";231break;232233case CK_Colon:234this->Text = ":";235break;236237case CK_SemiColon:238this->Text = ";";239break;240241case CK_Equal:242this->Text = " = ";243break;244245case CK_HorizontalSpace:246this->Text = " ";247break;248249case CK_VerticalSpace:250this->Text = "\n";251break;252}253}254255CodeCompletionString::Chunk256CodeCompletionString::Chunk::CreateText(const char *Text) {257return Chunk(CK_Text, Text);258}259260CodeCompletionString::Chunk261CodeCompletionString::Chunk::CreateOptional(CodeCompletionString *Optional) {262Chunk Result;263Result.Kind = CK_Optional;264Result.Optional = Optional;265return Result;266}267268CodeCompletionString::Chunk269CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {270return Chunk(CK_Placeholder, Placeholder);271}272273CodeCompletionString::Chunk274CodeCompletionString::Chunk::CreateInformative(const char *Informative) {275return Chunk(CK_Informative, Informative);276}277278CodeCompletionString::Chunk279CodeCompletionString::Chunk::CreateResultType(const char *ResultType) {280return Chunk(CK_ResultType, ResultType);281}282283CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter(284const char *CurrentParameter) {285return Chunk(CK_CurrentParameter, CurrentParameter);286}287288CodeCompletionString::CodeCompletionString(289const Chunk *Chunks, unsigned NumChunks, unsigned Priority,290CXAvailabilityKind Availability, const char **Annotations,291unsigned NumAnnotations, StringRef ParentName, const char *BriefComment)292: NumChunks(NumChunks), NumAnnotations(NumAnnotations), Priority(Priority),293Availability(Availability), ParentName(ParentName),294BriefComment(BriefComment) {295assert(NumChunks <= 0xffff);296assert(NumAnnotations <= 0xffff);297298Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1);299for (unsigned I = 0; I != NumChunks; ++I)300StoredChunks[I] = Chunks[I];301302const char **StoredAnnotations =303reinterpret_cast<const char **>(StoredChunks + NumChunks);304for (unsigned I = 0; I != NumAnnotations; ++I)305StoredAnnotations[I] = Annotations[I];306}307308unsigned CodeCompletionString::getAnnotationCount() const {309return NumAnnotations;310}311312const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const {313if (AnnotationNr < NumAnnotations)314return reinterpret_cast<const char *const *>(end())[AnnotationNr];315else316return nullptr;317}318319std::string CodeCompletionString::getAsString() const {320std::string Result;321llvm::raw_string_ostream OS(Result);322323for (const Chunk &C : *this) {324switch (C.Kind) {325case CK_Optional:326OS << "{#" << C.Optional->getAsString() << "#}";327break;328case CK_Placeholder:329OS << "<#" << C.Text << "#>";330break;331case CK_Informative:332case CK_ResultType:333OS << "[#" << C.Text << "#]";334break;335case CK_CurrentParameter:336OS << "<#" << C.Text << "#>";337break;338default:339OS << C.Text;340break;341}342}343return Result;344}345346const char *CodeCompletionString::getTypedText() const {347for (const Chunk &C : *this)348if (C.Kind == CK_TypedText)349return C.Text;350351return nullptr;352}353354std::string CodeCompletionString::getAllTypedText() const {355std::string Res;356for (const Chunk &C : *this)357if (C.Kind == CK_TypedText)358Res += C.Text;359360return Res;361}362363const char *CodeCompletionAllocator::CopyString(const Twine &String) {364SmallString<128> Data;365StringRef Ref = String.toStringRef(Data);366// FIXME: It would be more efficient to teach Twine to tell us its size and367// then add a routine there to fill in an allocated char* with the contents368// of the string.369char *Mem = (char *)Allocate(Ref.size() + 1, 1);370std::copy(Ref.begin(), Ref.end(), Mem);371Mem[Ref.size()] = 0;372return Mem;373}374375StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {376if (!isa<NamedDecl>(DC))377return {};378379// Check whether we've already cached the parent name.380StringRef &CachedParentName = ParentNames[DC];381if (!CachedParentName.empty())382return CachedParentName;383384// If we already processed this DeclContext and assigned empty to it, the385// data pointer will be non-null.386if (CachedParentName.data() != nullptr)387return {};388389// Find the interesting names.390SmallVector<const DeclContext *, 2> Contexts;391while (DC && !DC->isFunctionOrMethod()) {392if (const auto *ND = dyn_cast<NamedDecl>(DC)) {393if (ND->getIdentifier())394Contexts.push_back(DC);395}396397DC = DC->getParent();398}399400{401SmallString<128> S;402llvm::raw_svector_ostream OS(S);403bool First = true;404for (const DeclContext *CurDC : llvm::reverse(Contexts)) {405if (First)406First = false;407else {408OS << "::";409}410411if (const auto *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))412CurDC = CatImpl->getCategoryDecl();413414if (const auto *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {415const ObjCInterfaceDecl *Interface = Cat->getClassInterface();416if (!Interface) {417// Assign an empty StringRef but with non-null data to distinguish418// between empty because we didn't process the DeclContext yet.419CachedParentName = StringRef((const char *)(uintptr_t)~0U, 0);420return {};421}422423OS << Interface->getName() << '(' << Cat->getName() << ')';424} else {425OS << cast<NamedDecl>(CurDC)->getName();426}427}428429CachedParentName = AllocatorRef->CopyString(OS.str());430}431432return CachedParentName;433}434435CodeCompletionString *CodeCompletionBuilder::TakeString() {436void *Mem = getAllocator().Allocate(437sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() +438sizeof(const char *) * Annotations.size(),439alignof(CodeCompletionString));440CodeCompletionString *Result = new (Mem) CodeCompletionString(441Chunks.data(), Chunks.size(), Priority, Availability, Annotations.data(),442Annotations.size(), ParentName, BriefComment);443Chunks.clear();444return Result;445}446447void CodeCompletionBuilder::AddTypedTextChunk(const char *Text) {448Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text));449}450451void CodeCompletionBuilder::AddTextChunk(const char *Text) {452Chunks.push_back(Chunk::CreateText(Text));453}454455void CodeCompletionBuilder::AddOptionalChunk(CodeCompletionString *Optional) {456Chunks.push_back(Chunk::CreateOptional(Optional));457}458459void CodeCompletionBuilder::AddPlaceholderChunk(const char *Placeholder) {460Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));461}462463void CodeCompletionBuilder::AddInformativeChunk(const char *Text) {464Chunks.push_back(Chunk::CreateInformative(Text));465}466467void CodeCompletionBuilder::AddResultTypeChunk(const char *ResultType) {468Chunks.push_back(Chunk::CreateResultType(ResultType));469}470471void CodeCompletionBuilder::AddCurrentParameterChunk(472const char *CurrentParameter) {473Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter));474}475476void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,477const char *Text) {478Chunks.push_back(Chunk(CK, Text));479}480481void CodeCompletionBuilder::addParentContext(const DeclContext *DC) {482if (DC->isTranslationUnit())483return;484485if (DC->isFunctionOrMethod())486return;487488if (!isa<NamedDecl>(DC))489return;490491ParentName = getCodeCompletionTUInfo().getParentName(DC);492}493494void CodeCompletionBuilder::addBriefComment(StringRef Comment) {495BriefComment = Allocator.CopyString(Comment);496}497498//===----------------------------------------------------------------------===//499// Code completion overload candidate implementation500//===----------------------------------------------------------------------===//501FunctionDecl *CodeCompleteConsumer::OverloadCandidate::getFunction() const {502if (getKind() == CK_Function)503return Function;504else if (getKind() == CK_FunctionTemplate)505return FunctionTemplate->getTemplatedDecl();506else507return nullptr;508}509510const FunctionType *511CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {512switch (Kind) {513case CK_Function:514return Function->getType()->getAs<FunctionType>();515516case CK_FunctionTemplate:517return FunctionTemplate->getTemplatedDecl()518->getType()519->getAs<FunctionType>();520521case CK_FunctionType:522return Type;523case CK_FunctionProtoTypeLoc:524return ProtoTypeLoc.getTypePtr();525case CK_Template:526case CK_Aggregate:527return nullptr;528}529530llvm_unreachable("Invalid CandidateKind!");531}532533const FunctionProtoTypeLoc534CodeCompleteConsumer::OverloadCandidate::getFunctionProtoTypeLoc() const {535if (Kind == CK_FunctionProtoTypeLoc)536return ProtoTypeLoc;537return FunctionProtoTypeLoc();538}539540unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const {541if (Kind == CK_Template)542return Template->getTemplateParameters()->size();543544if (Kind == CK_Aggregate) {545unsigned Count =546std::distance(AggregateType->field_begin(), AggregateType->field_end());547if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType))548Count += CRD->getNumBases();549return Count;550}551552if (const auto *FT = getFunctionType())553if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))554return FPT->getNumParams();555556return 0;557}558559QualType560CodeCompleteConsumer::OverloadCandidate::getParamType(unsigned N) const {561if (Kind == CK_Aggregate) {562if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {563if (N < CRD->getNumBases())564return std::next(CRD->bases_begin(), N)->getType();565N -= CRD->getNumBases();566}567for (const auto *Field : AggregateType->fields())568if (N-- == 0)569return Field->getType();570return QualType();571}572573if (Kind == CK_Template) {574TemplateParameterList *TPL = getTemplate()->getTemplateParameters();575if (N < TPL->size())576if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(TPL->getParam(N)))577return D->getType();578return QualType();579}580581if (const auto *FT = getFunctionType())582if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))583if (N < FPT->getNumParams())584return FPT->getParamType(N);585return QualType();586}587588const NamedDecl *589CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const {590if (Kind == CK_Aggregate) {591if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {592if (N < CRD->getNumBases())593return std::next(CRD->bases_begin(), N)->getType()->getAsTagDecl();594N -= CRD->getNumBases();595}596for (const auto *Field : AggregateType->fields())597if (N-- == 0)598return Field;599return nullptr;600}601602if (Kind == CK_Template) {603TemplateParameterList *TPL = getTemplate()->getTemplateParameters();604if (N < TPL->size())605return TPL->getParam(N);606return nullptr;607}608609// Note that if we only have a FunctionProtoType, we don't have param decls.610if (const auto *FD = getFunction()) {611if (N < FD->param_size())612return FD->getParamDecl(N);613} else if (Kind == CK_FunctionProtoTypeLoc) {614if (N < ProtoTypeLoc.getNumParams()) {615return ProtoTypeLoc.getParam(N);616}617}618619return nullptr;620}621622//===----------------------------------------------------------------------===//623// Code completion consumer implementation624//===----------------------------------------------------------------------===//625626CodeCompleteConsumer::~CodeCompleteConsumer() = default;627628bool PrintingCodeCompleteConsumer::isResultFilteredOut(629StringRef Filter, CodeCompletionResult Result) {630switch (Result.Kind) {631case CodeCompletionResult::RK_Declaration:632return !(633Result.Declaration->getIdentifier() &&634Result.Declaration->getIdentifier()->getName().starts_with(Filter));635case CodeCompletionResult::RK_Keyword:636return !StringRef(Result.Keyword).starts_with(Filter);637case CodeCompletionResult::RK_Macro:638return !Result.Macro->getName().starts_with(Filter);639case CodeCompletionResult::RK_Pattern:640return !(Result.Pattern->getTypedText() &&641StringRef(Result.Pattern->getTypedText()).starts_with(Filter));642}643llvm_unreachable("Unknown code completion result Kind.");644}645646void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(647Sema &SemaRef, CodeCompletionContext Context, CodeCompletionResult *Results,648unsigned NumResults) {649std::stable_sort(Results, Results + NumResults);650651if (!Context.getPreferredType().isNull())652OS << "PREFERRED-TYPE: " << Context.getPreferredType() << '\n';653654StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();655// Print the completions.656for (unsigned I = 0; I != NumResults; ++I) {657if (!Filter.empty() && isResultFilteredOut(Filter, Results[I]))658continue;659OS << "COMPLETION: ";660switch (Results[I].Kind) {661case CodeCompletionResult::RK_Declaration:662OS << *Results[I].Declaration;663{664std::vector<std::string> Tags;665if (Results[I].Hidden)666Tags.push_back("Hidden");667if (Results[I].InBaseClass)668Tags.push_back("InBase");669if (Results[I].Availability ==670CXAvailabilityKind::CXAvailability_NotAccessible)671Tags.push_back("Inaccessible");672if (!Tags.empty())673OS << " (" << llvm::join(Tags, ",") << ")";674}675if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(676SemaRef, Context, getAllocator(), CCTUInfo,677includeBriefComments())) {678OS << " : " << CCS->getAsString();679if (const char *BriefComment = CCS->getBriefComment())680OS << " : " << BriefComment;681}682break;683684case CodeCompletionResult::RK_Keyword:685OS << Results[I].Keyword;686break;687688case CodeCompletionResult::RK_Macro:689OS << Results[I].Macro->getName();690if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(691SemaRef, Context, getAllocator(), CCTUInfo,692includeBriefComments())) {693OS << " : " << CCS->getAsString();694}695break;696697case CodeCompletionResult::RK_Pattern:698OS << "Pattern : " << Results[I].Pattern->getAsString();699break;700}701for (const FixItHint &FixIt : Results[I].FixIts) {702const SourceLocation BLoc = FixIt.RemoveRange.getBegin();703const SourceLocation ELoc = FixIt.RemoveRange.getEnd();704705SourceManager &SM = SemaRef.SourceMgr;706std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);707std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);708// Adjust for token ranges.709if (FixIt.RemoveRange.isTokenRange())710EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts);711712OS << " (requires fix-it:"713<< " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':'714<< SM.getColumnNumber(BInfo.first, BInfo.second) << '-'715<< SM.getLineNumber(EInfo.first, EInfo.second) << ':'716<< SM.getColumnNumber(EInfo.first, EInfo.second) << "}"717<< " to \"" << FixIt.CodeToInsert << "\")";718}719OS << '\n';720}721}722723// This function is used solely to preserve the former presentation of overloads724// by "clang -cc1 -code-completion-at", since CodeCompletionString::getAsString725// needs to be improved for printing the newer and more detailed overload726// chunks.727static std::string getOverloadAsString(const CodeCompletionString &CCS) {728std::string Result;729llvm::raw_string_ostream OS(Result);730731for (auto &C : CCS) {732switch (C.Kind) {733case CodeCompletionString::CK_Informative:734case CodeCompletionString::CK_ResultType:735OS << "[#" << C.Text << "#]";736break;737738case CodeCompletionString::CK_CurrentParameter:739OS << "<#" << C.Text << "#>";740break;741742// FIXME: We can also print optional parameters of an overload.743case CodeCompletionString::CK_Optional:744break;745746default:747OS << C.Text;748break;749}750}751return Result;752}753754void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(755Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates,756unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) {757OS << "OPENING_PAREN_LOC: ";758OpenParLoc.print(OS, SemaRef.getSourceManager());759OS << "\n";760761for (unsigned I = 0; I != NumCandidates; ++I) {762if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString(763CurrentArg, SemaRef, getAllocator(), CCTUInfo,764includeBriefComments(), Braced)) {765OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n";766}767}768}769770/// Retrieve the effective availability of the given declaration.771static AvailabilityResult getDeclAvailability(const Decl *D) {772AvailabilityResult AR = D->getAvailability();773if (isa<EnumConstantDecl>(D))774AR = std::max(AR, cast<Decl>(D->getDeclContext())->getAvailability());775return AR;776}777778void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {779switch (Kind) {780case RK_Pattern:781if (!Declaration) {782// Do nothing: Patterns can come with cursor kinds!783break;784}785[[fallthrough]];786787case RK_Declaration: {788// Set the availability based on attributes.789switch (getDeclAvailability(Declaration)) {790case AR_Available:791case AR_NotYetIntroduced:792Availability = CXAvailability_Available;793break;794795case AR_Deprecated:796Availability = CXAvailability_Deprecated;797break;798799case AR_Unavailable:800Availability = CXAvailability_NotAvailable;801break;802}803804if (const auto *Function = dyn_cast<FunctionDecl>(Declaration))805if (Function->isDeleted())806Availability = CXAvailability_NotAvailable;807808CursorKind = getCursorKindForDecl(Declaration);809if (CursorKind == CXCursor_UnexposedDecl) {810// FIXME: Forward declarations of Objective-C classes and protocols811// are not directly exposed, but we want code completion to treat them812// like a definition.813if (isa<ObjCInterfaceDecl>(Declaration))814CursorKind = CXCursor_ObjCInterfaceDecl;815else if (isa<ObjCProtocolDecl>(Declaration))816CursorKind = CXCursor_ObjCProtocolDecl;817else818CursorKind = CXCursor_NotImplemented;819}820break;821}822823case RK_Macro:824case RK_Keyword:825llvm_unreachable("Macro and keyword kinds are handled by the constructors");826}827828if (!Accessible)829Availability = CXAvailability_NotAccessible;830}831832/// Retrieve the name that should be used to order a result.833///834/// If the name needs to be constructed as a string, that string will be835/// saved into Saved and the returned StringRef will refer to it.836StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const {837switch (Kind) {838case RK_Keyword:839return Keyword;840case RK_Pattern:841return Pattern->getTypedText();842case RK_Macro:843return Macro->getName();844case RK_Declaration:845// Handle declarations below.846break;847}848849DeclarationName Name = Declaration->getDeclName();850851// If the name is a simple identifier (by far the common case), or a852// zero-argument selector, just return a reference to that identifier.853if (IdentifierInfo *Id = Name.getAsIdentifierInfo())854return Id->getName();855if (Name.isObjCZeroArgSelector())856if (const IdentifierInfo *Id =857Name.getObjCSelector().getIdentifierInfoForSlot(0))858return Id->getName();859860Saved = Name.getAsString();861return Saved;862}863864bool clang::operator<(const CodeCompletionResult &X,865const CodeCompletionResult &Y) {866std::string XSaved, YSaved;867StringRef XStr = X.getOrderedName(XSaved);868StringRef YStr = Y.getOrderedName(YSaved);869int cmp = XStr.compare_insensitive(YStr);870if (cmp)871return cmp < 0;872873// If case-insensitive comparison fails, try case-sensitive comparison.874return XStr.compare(YStr) < 0;875}876877878