123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- //===- CodeCompleteConsumer.cpp - Code Completion Interface ---------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the CodeCompleteConsumer class.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Sema/CodeCompleteConsumer.h"
- #include "clang-c/Index.h"
- #include "clang/AST/Decl.h"
- #include "clang/AST/DeclBase.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/DeclTemplate.h"
- #include "clang/AST/DeclarationName.h"
- #include "clang/AST/Type.h"
- #include "clang/Basic/IdentifierTable.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Sema/Sema.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/Compiler.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/FormatVariadic.h"
- #include "llvm/Support/raw_ostream.h"
- #include <algorithm>
- #include <cassert>
- #include <cstdint>
- #include <string>
- using namespace clang;
- //===----------------------------------------------------------------------===//
- // Code completion context implementation
- //===----------------------------------------------------------------------===//
- bool CodeCompletionContext::wantConstructorResults() const {
- switch (CCKind) {
- case CCC_Recovery:
- case CCC_Statement:
- case CCC_Expression:
- case CCC_ObjCMessageReceiver:
- case CCC_ParenthesizedExpression:
- case CCC_Symbol:
- case CCC_SymbolOrNewName:
- return true;
- case CCC_TopLevel:
- case CCC_ObjCInterface:
- case CCC_ObjCImplementation:
- case CCC_ObjCIvarList:
- case CCC_ClassStructUnion:
- case CCC_DotMemberAccess:
- case CCC_ArrowMemberAccess:
- case CCC_ObjCPropertyAccess:
- case CCC_EnumTag:
- case CCC_UnionTag:
- case CCC_ClassOrStructTag:
- case CCC_ObjCProtocolName:
- case CCC_Namespace:
- case CCC_Type:
- case CCC_NewName:
- case CCC_MacroName:
- case CCC_MacroNameUse:
- case CCC_PreprocessorExpression:
- case CCC_PreprocessorDirective:
- case CCC_NaturalLanguage:
- case CCC_SelectorName:
- case CCC_TypeQualifiers:
- case CCC_Other:
- case CCC_OtherWithMacros:
- case CCC_ObjCInstanceMessage:
- case CCC_ObjCClassMessage:
- case CCC_ObjCInterfaceName:
- case CCC_ObjCCategoryName:
- case CCC_IncludedFile:
- case CCC_Attribute:
- return false;
- }
- llvm_unreachable("Invalid CodeCompletionContext::Kind!");
- }
- StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) {
- using CCKind = CodeCompletionContext::Kind;
- switch (Kind) {
- case CCKind::CCC_Other:
- return "Other";
- case CCKind::CCC_OtherWithMacros:
- return "OtherWithMacros";
- case CCKind::CCC_TopLevel:
- return "TopLevel";
- case CCKind::CCC_ObjCInterface:
- return "ObjCInterface";
- case CCKind::CCC_ObjCImplementation:
- return "ObjCImplementation";
- case CCKind::CCC_ObjCIvarList:
- return "ObjCIvarList";
- case CCKind::CCC_ClassStructUnion:
- return "ClassStructUnion";
- case CCKind::CCC_Statement:
- return "Statement";
- case CCKind::CCC_Expression:
- return "Expression";
- case CCKind::CCC_ObjCMessageReceiver:
- return "ObjCMessageReceiver";
- case CCKind::CCC_DotMemberAccess:
- return "DotMemberAccess";
- case CCKind::CCC_ArrowMemberAccess:
- return "ArrowMemberAccess";
- case CCKind::CCC_ObjCPropertyAccess:
- return "ObjCPropertyAccess";
- case CCKind::CCC_EnumTag:
- return "EnumTag";
- case CCKind::CCC_UnionTag:
- return "UnionTag";
- case CCKind::CCC_ClassOrStructTag:
- return "ClassOrStructTag";
- case CCKind::CCC_ObjCProtocolName:
- return "ObjCProtocolName";
- case CCKind::CCC_Namespace:
- return "Namespace";
- case CCKind::CCC_Type:
- return "Type";
- case CCKind::CCC_NewName:
- return "NewName";
- case CCKind::CCC_Symbol:
- return "Symbol";
- case CCKind::CCC_SymbolOrNewName:
- return "SymbolOrNewName";
- case CCKind::CCC_MacroName:
- return "MacroName";
- case CCKind::CCC_MacroNameUse:
- return "MacroNameUse";
- case CCKind::CCC_PreprocessorExpression:
- return "PreprocessorExpression";
- case CCKind::CCC_PreprocessorDirective:
- return "PreprocessorDirective";
- case CCKind::CCC_NaturalLanguage:
- return "NaturalLanguage";
- case CCKind::CCC_SelectorName:
- return "SelectorName";
- case CCKind::CCC_TypeQualifiers:
- return "TypeQualifiers";
- case CCKind::CCC_ParenthesizedExpression:
- return "ParenthesizedExpression";
- case CCKind::CCC_ObjCInstanceMessage:
- return "ObjCInstanceMessage";
- case CCKind::CCC_ObjCClassMessage:
- return "ObjCClassMessage";
- case CCKind::CCC_ObjCInterfaceName:
- return "ObjCInterfaceName";
- case CCKind::CCC_ObjCCategoryName:
- return "ObjCCategoryName";
- case CCKind::CCC_IncludedFile:
- return "IncludedFile";
- case CCKind::CCC_Attribute:
- return "Attribute";
- case CCKind::CCC_Recovery:
- return "Recovery";
- }
- llvm_unreachable("Invalid CodeCompletionContext::Kind!");
- }
- //===----------------------------------------------------------------------===//
- // Code completion string implementation
- //===----------------------------------------------------------------------===//
- CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)
- : Kind(Kind), Text("") {
- switch (Kind) {
- case CK_TypedText:
- case CK_Text:
- case CK_Placeholder:
- case CK_Informative:
- case CK_ResultType:
- case CK_CurrentParameter:
- this->Text = Text;
- break;
- case CK_Optional:
- llvm_unreachable("Optional strings cannot be created from text");
- case CK_LeftParen:
- this->Text = "(";
- break;
- case CK_RightParen:
- this->Text = ")";
- break;
- case CK_LeftBracket:
- this->Text = "[";
- break;
- case CK_RightBracket:
- this->Text = "]";
- break;
- case CK_LeftBrace:
- this->Text = "{";
- break;
- case CK_RightBrace:
- this->Text = "}";
- break;
- case CK_LeftAngle:
- this->Text = "<";
- break;
- case CK_RightAngle:
- this->Text = ">";
- break;
- case CK_Comma:
- this->Text = ", ";
- break;
- case CK_Colon:
- this->Text = ":";
- break;
- case CK_SemiColon:
- this->Text = ";";
- break;
- case CK_Equal:
- this->Text = " = ";
- break;
- case CK_HorizontalSpace:
- this->Text = " ";
- break;
- case CK_VerticalSpace:
- this->Text = "\n";
- break;
- }
- }
- CodeCompletionString::Chunk
- CodeCompletionString::Chunk::CreateText(const char *Text) {
- return Chunk(CK_Text, Text);
- }
- CodeCompletionString::Chunk
- CodeCompletionString::Chunk::CreateOptional(CodeCompletionString *Optional) {
- Chunk Result;
- Result.Kind = CK_Optional;
- Result.Optional = Optional;
- return Result;
- }
- CodeCompletionString::Chunk
- CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
- return Chunk(CK_Placeholder, Placeholder);
- }
- CodeCompletionString::Chunk
- CodeCompletionString::Chunk::CreateInformative(const char *Informative) {
- return Chunk(CK_Informative, Informative);
- }
- CodeCompletionString::Chunk
- CodeCompletionString::Chunk::CreateResultType(const char *ResultType) {
- return Chunk(CK_ResultType, ResultType);
- }
- CodeCompletionString::Chunk CodeCompletionString::Chunk::CreateCurrentParameter(
- const char *CurrentParameter) {
- return Chunk(CK_CurrentParameter, CurrentParameter);
- }
- CodeCompletionString::CodeCompletionString(
- const Chunk *Chunks, unsigned NumChunks, unsigned Priority,
- CXAvailabilityKind Availability, const char **Annotations,
- unsigned NumAnnotations, StringRef ParentName, const char *BriefComment)
- : NumChunks(NumChunks), NumAnnotations(NumAnnotations), Priority(Priority),
- Availability(Availability), ParentName(ParentName),
- BriefComment(BriefComment) {
- assert(NumChunks <= 0xffff);
- assert(NumAnnotations <= 0xffff);
- Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1);
- for (unsigned I = 0; I != NumChunks; ++I)
- StoredChunks[I] = Chunks[I];
- const char **StoredAnnotations =
- reinterpret_cast<const char **>(StoredChunks + NumChunks);
- for (unsigned I = 0; I != NumAnnotations; ++I)
- StoredAnnotations[I] = Annotations[I];
- }
- unsigned CodeCompletionString::getAnnotationCount() const {
- return NumAnnotations;
- }
- const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const {
- if (AnnotationNr < NumAnnotations)
- return reinterpret_cast<const char *const *>(end())[AnnotationNr];
- else
- return nullptr;
- }
- std::string CodeCompletionString::getAsString() const {
- std::string Result;
- llvm::raw_string_ostream OS(Result);
- for (const Chunk &C : *this) {
- switch (C.Kind) {
- case CK_Optional:
- OS << "{#" << C.Optional->getAsString() << "#}";
- break;
- case CK_Placeholder:
- OS << "<#" << C.Text << "#>";
- break;
- case CK_Informative:
- case CK_ResultType:
- OS << "[#" << C.Text << "#]";
- break;
- case CK_CurrentParameter:
- OS << "<#" << C.Text << "#>";
- break;
- default:
- OS << C.Text;
- break;
- }
- }
- return Result;
- }
- const char *CodeCompletionString::getTypedText() const {
- for (const Chunk &C : *this)
- if (C.Kind == CK_TypedText)
- return C.Text;
- return nullptr;
- }
- std::string CodeCompletionString::getAllTypedText() const {
- std::string Res;
- for (const Chunk &C : *this)
- if (C.Kind == CK_TypedText)
- Res += C.Text;
- return Res;
- }
- const char *CodeCompletionAllocator::CopyString(const Twine &String) {
- SmallString<128> Data;
- StringRef Ref = String.toStringRef(Data);
- // FIXME: It would be more efficient to teach Twine to tell us its size and
- // then add a routine there to fill in an allocated char* with the contents
- // of the string.
- char *Mem = (char *)Allocate(Ref.size() + 1, 1);
- std::copy(Ref.begin(), Ref.end(), Mem);
- Mem[Ref.size()] = 0;
- return Mem;
- }
- StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {
- if (!isa<NamedDecl>(DC))
- return {};
- // Check whether we've already cached the parent name.
- StringRef &CachedParentName = ParentNames[DC];
- if (!CachedParentName.empty())
- return CachedParentName;
- // If we already processed this DeclContext and assigned empty to it, the
- // data pointer will be non-null.
- if (CachedParentName.data() != nullptr)
- return {};
- // Find the interesting names.
- SmallVector<const DeclContext *, 2> Contexts;
- while (DC && !DC->isFunctionOrMethod()) {
- if (const auto *ND = dyn_cast<NamedDecl>(DC)) {
- if (ND->getIdentifier())
- Contexts.push_back(DC);
- }
- DC = DC->getParent();
- }
- {
- SmallString<128> S;
- llvm::raw_svector_ostream OS(S);
- bool First = true;
- for (const DeclContext *CurDC : llvm::reverse(Contexts)) {
- if (First)
- First = false;
- else {
- OS << "::";
- }
- if (const auto *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
- CurDC = CatImpl->getCategoryDecl();
- if (const auto *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
- const ObjCInterfaceDecl *Interface = Cat->getClassInterface();
- if (!Interface) {
- // Assign an empty StringRef but with non-null data to distinguish
- // between empty because we didn't process the DeclContext yet.
- CachedParentName = StringRef((const char *)(uintptr_t)~0U, 0);
- return {};
- }
- OS << Interface->getName() << '(' << Cat->getName() << ')';
- } else {
- OS << cast<NamedDecl>(CurDC)->getName();
- }
- }
- CachedParentName = AllocatorRef->CopyString(OS.str());
- }
- return CachedParentName;
- }
- CodeCompletionString *CodeCompletionBuilder::TakeString() {
- void *Mem = getAllocator().Allocate(
- sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() +
- sizeof(const char *) * Annotations.size(),
- alignof(CodeCompletionString));
- CodeCompletionString *Result = new (Mem) CodeCompletionString(
- Chunks.data(), Chunks.size(), Priority, Availability, Annotations.data(),
- Annotations.size(), ParentName, BriefComment);
- Chunks.clear();
- return Result;
- }
- void CodeCompletionBuilder::AddTypedTextChunk(const char *Text) {
- Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text));
- }
- void CodeCompletionBuilder::AddTextChunk(const char *Text) {
- Chunks.push_back(Chunk::CreateText(Text));
- }
- void CodeCompletionBuilder::AddOptionalChunk(CodeCompletionString *Optional) {
- Chunks.push_back(Chunk::CreateOptional(Optional));
- }
- void CodeCompletionBuilder::AddPlaceholderChunk(const char *Placeholder) {
- Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));
- }
- void CodeCompletionBuilder::AddInformativeChunk(const char *Text) {
- Chunks.push_back(Chunk::CreateInformative(Text));
- }
- void CodeCompletionBuilder::AddResultTypeChunk(const char *ResultType) {
- Chunks.push_back(Chunk::CreateResultType(ResultType));
- }
- void CodeCompletionBuilder::AddCurrentParameterChunk(
- const char *CurrentParameter) {
- Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter));
- }
- void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
- const char *Text) {
- Chunks.push_back(Chunk(CK, Text));
- }
- void CodeCompletionBuilder::addParentContext(const DeclContext *DC) {
- if (DC->isTranslationUnit())
- return;
- if (DC->isFunctionOrMethod())
- return;
- if (!isa<NamedDecl>(DC))
- return;
- ParentName = getCodeCompletionTUInfo().getParentName(DC);
- }
- void CodeCompletionBuilder::addBriefComment(StringRef Comment) {
- BriefComment = Allocator.CopyString(Comment);
- }
- //===----------------------------------------------------------------------===//
- // Code completion overload candidate implementation
- //===----------------------------------------------------------------------===//
- FunctionDecl *CodeCompleteConsumer::OverloadCandidate::getFunction() const {
- if (getKind() == CK_Function)
- return Function;
- else if (getKind() == CK_FunctionTemplate)
- return FunctionTemplate->getTemplatedDecl();
- else
- return nullptr;
- }
- const FunctionType *
- CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
- switch (Kind) {
- case CK_Function:
- return Function->getType()->getAs<FunctionType>();
- case CK_FunctionTemplate:
- return FunctionTemplate->getTemplatedDecl()
- ->getType()
- ->getAs<FunctionType>();
- case CK_FunctionType:
- return Type;
- case CK_FunctionProtoTypeLoc:
- return ProtoTypeLoc.getTypePtr();
- case CK_Template:
- case CK_Aggregate:
- return nullptr;
- }
- llvm_unreachable("Invalid CandidateKind!");
- }
- const FunctionProtoTypeLoc
- CodeCompleteConsumer::OverloadCandidate::getFunctionProtoTypeLoc() const {
- if (Kind == CK_FunctionProtoTypeLoc)
- return ProtoTypeLoc;
- return FunctionProtoTypeLoc();
- }
- unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const {
- if (Kind == CK_Template)
- return Template->getTemplateParameters()->size();
- if (Kind == CK_Aggregate) {
- unsigned Count =
- std::distance(AggregateType->field_begin(), AggregateType->field_end());
- if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType))
- Count += CRD->getNumBases();
- return Count;
- }
- if (const auto *FT = getFunctionType())
- if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))
- return FPT->getNumParams();
- return 0;
- }
- QualType
- CodeCompleteConsumer::OverloadCandidate::getParamType(unsigned N) const {
- if (Kind == CK_Aggregate) {
- if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {
- if (N < CRD->getNumBases())
- return std::next(CRD->bases_begin(), N)->getType();
- N -= CRD->getNumBases();
- }
- for (const auto *Field : AggregateType->fields())
- if (N-- == 0)
- return Field->getType();
- return QualType();
- }
- if (Kind == CK_Template) {
- TemplateParameterList *TPL = getTemplate()->getTemplateParameters();
- if (N < TPL->size())
- if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(TPL->getParam(N)))
- return D->getType();
- return QualType();
- }
- if (const auto *FT = getFunctionType())
- if (const auto *FPT = dyn_cast<FunctionProtoType>(FT))
- if (N < FPT->getNumParams())
- return FPT->getParamType(N);
- return QualType();
- }
- const NamedDecl *
- CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const {
- if (Kind == CK_Aggregate) {
- if (const auto *CRD = dyn_cast<CXXRecordDecl>(AggregateType)) {
- if (N < CRD->getNumBases())
- return std::next(CRD->bases_begin(), N)->getType()->getAsTagDecl();
- N -= CRD->getNumBases();
- }
- for (const auto *Field : AggregateType->fields())
- if (N-- == 0)
- return Field;
- return nullptr;
- }
- if (Kind == CK_Template) {
- TemplateParameterList *TPL = getTemplate()->getTemplateParameters();
- if (N < TPL->size())
- return TPL->getParam(N);
- return nullptr;
- }
- // Note that if we only have a FunctionProtoType, we don't have param decls.
- if (const auto *FD = getFunction()) {
- if (N < FD->param_size())
- return FD->getParamDecl(N);
- } else if (Kind == CK_FunctionProtoTypeLoc) {
- if (N < ProtoTypeLoc.getNumParams()) {
- return ProtoTypeLoc.getParam(N);
- }
- }
- return nullptr;
- }
- //===----------------------------------------------------------------------===//
- // Code completion consumer implementation
- //===----------------------------------------------------------------------===//
- CodeCompleteConsumer::~CodeCompleteConsumer() = default;
- bool PrintingCodeCompleteConsumer::isResultFilteredOut(
- StringRef Filter, CodeCompletionResult Result) {
- switch (Result.Kind) {
- case CodeCompletionResult::RK_Declaration:
- return !(Result.Declaration->getIdentifier() &&
- Result.Declaration->getIdentifier()->getName().startswith(Filter));
- case CodeCompletionResult::RK_Keyword:
- return !StringRef(Result.Keyword).startswith(Filter);
- case CodeCompletionResult::RK_Macro:
- return !Result.Macro->getName().startswith(Filter);
- case CodeCompletionResult::RK_Pattern:
- return !(Result.Pattern->getTypedText() &&
- StringRef(Result.Pattern->getTypedText()).startswith(Filter));
- }
- llvm_unreachable("Unknown code completion result Kind.");
- }
- void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(
- Sema &SemaRef, CodeCompletionContext Context, CodeCompletionResult *Results,
- unsigned NumResults) {
- std::stable_sort(Results, Results + NumResults);
- if (!Context.getPreferredType().isNull())
- OS << "PREFERRED-TYPE: " << Context.getPreferredType() << '\n';
- StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();
- // Print the completions.
- for (unsigned I = 0; I != NumResults; ++I) {
- if (!Filter.empty() && isResultFilteredOut(Filter, Results[I]))
- continue;
- OS << "COMPLETION: ";
- switch (Results[I].Kind) {
- case CodeCompletionResult::RK_Declaration:
- OS << *Results[I].Declaration;
- {
- std::vector<std::string> Tags;
- if (Results[I].Hidden)
- Tags.push_back("Hidden");
- if (Results[I].InBaseClass)
- Tags.push_back("InBase");
- if (Results[I].Availability ==
- CXAvailabilityKind::CXAvailability_NotAccessible)
- Tags.push_back("Inaccessible");
- if (!Tags.empty())
- OS << " (" << llvm::join(Tags, ",") << ")";
- }
- if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(
- SemaRef, Context, getAllocator(), CCTUInfo,
- includeBriefComments())) {
- OS << " : " << CCS->getAsString();
- if (const char *BriefComment = CCS->getBriefComment())
- OS << " : " << BriefComment;
- }
- break;
- case CodeCompletionResult::RK_Keyword:
- OS << Results[I].Keyword;
- break;
- case CodeCompletionResult::RK_Macro:
- OS << Results[I].Macro->getName();
- if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(
- SemaRef, Context, getAllocator(), CCTUInfo,
- includeBriefComments())) {
- OS << " : " << CCS->getAsString();
- }
- break;
- case CodeCompletionResult::RK_Pattern:
- OS << "Pattern : " << Results[I].Pattern->getAsString();
- break;
- }
- for (const FixItHint &FixIt : Results[I].FixIts) {
- const SourceLocation BLoc = FixIt.RemoveRange.getBegin();
- const SourceLocation ELoc = FixIt.RemoveRange.getEnd();
- SourceManager &SM = SemaRef.SourceMgr;
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
- // Adjust for token ranges.
- if (FixIt.RemoveRange.isTokenRange())
- EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts);
- OS << " (requires fix-it:"
- << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << SM.getColumnNumber(EInfo.first, EInfo.second) << "}"
- << " to \"" << FixIt.CodeToInsert << "\")";
- }
- OS << '\n';
- }
- }
- // This function is used solely to preserve the former presentation of overloads
- // by "clang -cc1 -code-completion-at", since CodeCompletionString::getAsString
- // needs to be improved for printing the newer and more detailed overload
- // chunks.
- static std::string getOverloadAsString(const CodeCompletionString &CCS) {
- std::string Result;
- llvm::raw_string_ostream OS(Result);
- for (auto &C : CCS) {
- switch (C.Kind) {
- case CodeCompletionString::CK_Informative:
- case CodeCompletionString::CK_ResultType:
- OS << "[#" << C.Text << "#]";
- break;
- case CodeCompletionString::CK_CurrentParameter:
- OS << "<#" << C.Text << "#>";
- break;
- // FIXME: We can also print optional parameters of an overload.
- case CodeCompletionString::CK_Optional:
- break;
- default:
- OS << C.Text;
- break;
- }
- }
- return Result;
- }
- void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(
- Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates,
- unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) {
- OS << "OPENING_PAREN_LOC: ";
- OpenParLoc.print(OS, SemaRef.getSourceManager());
- OS << "\n";
- for (unsigned I = 0; I != NumCandidates; ++I) {
- if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString(
- CurrentArg, SemaRef, getAllocator(), CCTUInfo,
- includeBriefComments(), Braced)) {
- OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n";
- }
- }
- }
- /// Retrieve the effective availability of the given declaration.
- static AvailabilityResult getDeclAvailability(const Decl *D) {
- AvailabilityResult AR = D->getAvailability();
- if (isa<EnumConstantDecl>(D))
- AR = std::max(AR, cast<Decl>(D->getDeclContext())->getAvailability());
- return AR;
- }
- void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
- switch (Kind) {
- case RK_Pattern:
- if (!Declaration) {
- // Do nothing: Patterns can come with cursor kinds!
- break;
- }
- [[fallthrough]];
- case RK_Declaration: {
- // Set the availability based on attributes.
- switch (getDeclAvailability(Declaration)) {
- case AR_Available:
- case AR_NotYetIntroduced:
- Availability = CXAvailability_Available;
- break;
- case AR_Deprecated:
- Availability = CXAvailability_Deprecated;
- break;
- case AR_Unavailable:
- Availability = CXAvailability_NotAvailable;
- break;
- }
- if (const auto *Function = dyn_cast<FunctionDecl>(Declaration))
- if (Function->isDeleted())
- Availability = CXAvailability_NotAvailable;
- CursorKind = getCursorKindForDecl(Declaration);
- if (CursorKind == CXCursor_UnexposedDecl) {
- // FIXME: Forward declarations of Objective-C classes and protocols
- // are not directly exposed, but we want code completion to treat them
- // like a definition.
- if (isa<ObjCInterfaceDecl>(Declaration))
- CursorKind = CXCursor_ObjCInterfaceDecl;
- else if (isa<ObjCProtocolDecl>(Declaration))
- CursorKind = CXCursor_ObjCProtocolDecl;
- else
- CursorKind = CXCursor_NotImplemented;
- }
- break;
- }
- case RK_Macro:
- case RK_Keyword:
- llvm_unreachable("Macro and keyword kinds are handled by the constructors");
- }
- if (!Accessible)
- Availability = CXAvailability_NotAccessible;
- }
- /// Retrieve the name that should be used to order a result.
- ///
- /// If the name needs to be constructed as a string, that string will be
- /// saved into Saved and the returned StringRef will refer to it.
- StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const {
- switch (Kind) {
- case RK_Keyword:
- return Keyword;
- case RK_Pattern:
- return Pattern->getTypedText();
- case RK_Macro:
- return Macro->getName();
- case RK_Declaration:
- // Handle declarations below.
- break;
- }
- DeclarationName Name = Declaration->getDeclName();
- // If the name is a simple identifier (by far the common case), or a
- // zero-argument selector, just return a reference to that identifier.
- if (IdentifierInfo *Id = Name.getAsIdentifierInfo())
- return Id->getName();
- if (Name.isObjCZeroArgSelector())
- if (IdentifierInfo *Id = Name.getObjCSelector().getIdentifierInfoForSlot(0))
- return Id->getName();
- Saved = Name.getAsString();
- return Saved;
- }
- bool clang::operator<(const CodeCompletionResult &X,
- const CodeCompletionResult &Y) {
- std::string XSaved, YSaved;
- StringRef XStr = X.getOrderedName(XSaved);
- StringRef YStr = Y.getOrderedName(YSaved);
- int cmp = XStr.compare_insensitive(YStr);
- if (cmp)
- return cmp < 0;
- // If case-insensitive comparison fails, try case-sensitive comparison.
- return XStr.compare(YStr) < 0;
- }
|