brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.5 KiB · 50a5522 Raw
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