Index: include/clang/Sema/CodeCompleteConsumer.h =================================================================== --- include/clang/Sema/CodeCompleteConsumer.h +++ include/clang/Sema/CodeCompleteConsumer.h @@ -943,6 +943,12 @@ CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo); + void createCodeCompletionStringForDecl(Preprocessor &PP, ASTContext &Ctx, + CodeCompletionBuilder &Result, + bool IncludeBriefComments, + const CodeCompletionContext &CCContext, + PrintingPolicy &Policy); + /// 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 Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -1596,6 +1596,66 @@ Results.AddResult(CodeCompletionResult(Builder.TakeString())); } +static void AddOverrideResults(ResultBuilder &Results, + const CodeCompletionContext &CCContext, + CodeCompletionBuilder &Builder, Sema &S) { + const auto *CR = llvm::dyn_cast(S.CurContext); + // If not inside a class/struct/union return empty. + if (!CR) + return; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : CR->methods()) { + if (!Method->isVirtual() || !Method->getIdentifier()) + continue; + Overrides[Method->getName()].push_back(Method); + } + + for (const auto &Base : CR->bases()) { + const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); + if (!BR) + continue; + for (auto *Method : BR->methods()) { + if (!Method->isVirtual() || !Method->getIdentifier()) + continue; + const auto it = Overrides.find(Method->getName()); + bool IsOverriden = false; + if (it != Overrides.end()) { + for (auto *MD : it->second) { + // If the method in current body is not an overload of this virtual + // function, then it overrides this one. + if (!S.IsOverload(MD, Method, false)) { + IsOverriden = true; + break; + } + } + } + if (!IsOverriden) { + std::string OverrideSignature; + llvm::raw_string_ostream OS(OverrideSignature); + CodeCompletionResult CCR(Method, 0); + PrintingPolicy Policy = + getCompletionPrintingPolicy(S.getASTContext(), S.getPreprocessor()); + CCR.createCodeCompletionStringForDecl( + S.getPreprocessor(), S.getASTContext(), Builder, + false, CCContext, Policy); + for(const auto& C : *Builder.TakeString()) { + if (C.Kind == CodeCompletionString::CK_Optional) + continue; + OS << C.Text; + if (C.Kind == CodeCompletionString::CK_ResultType) + OS << ' '; + } + OS << " override"; + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(OS.str())); + Results.AddResult(CodeCompletionResult(Builder.TakeString(), Method, + CCP_CodePattern)); + } + } + } +} + /// Add language constructs that show up for "ordinary" names. static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, @@ -1704,6 +1764,9 @@ if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); + + AddOverrideResults(Results, CodeCompletionContext::CCC_ClassStructUnion, + Builder, SemaRef); } } LLVM_FALLTHROUGH; @@ -2791,48 +2854,11 @@ return Result.TakeString(); } -/// If possible, create a new code completion string for the given -/// result. -/// -/// \returns Either a new, heap-allocated code completion string describing -/// how to use this result, or NULL to indicate that the string or name of the -/// result is all that is needed. -CodeCompletionString * -CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, - Preprocessor &PP, - const CodeCompletionContext &CCContext, - CodeCompletionAllocator &Allocator, - CodeCompletionTUInfo &CCTUInfo, - bool IncludeBriefComments) { - if (Kind == RK_Macro) - return CreateCodeCompletionStringForMacro(PP, Allocator, CCTUInfo); - - CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability); - - PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP); - if (Kind == RK_Pattern) { - Pattern->Priority = Priority; - Pattern->Availability = Availability; - - if (Declaration) { - Result.addParentContext(Declaration->getDeclContext()); - Pattern->ParentName = Result.getParentName(); - if (const RawComment *RC = - getPatternCompletionComment(Ctx, Declaration)) { - Result.addBriefComment(RC->getBriefText(Ctx)); - Pattern->BriefComment = Result.getBriefComment(); - } - } - - return Pattern; - } - - if (Kind == RK_Keyword) { - Result.AddTypedTextChunk(Keyword); - return Result.TakeString(); - } - assert(Kind == RK_Declaration && "Missed a result kind?"); - const NamedDecl *ND = Declaration; +void CodeCompletionResult::createCodeCompletionStringForDecl( + Preprocessor &PP, ASTContext &Ctx, + CodeCompletionBuilder &Result, bool IncludeBriefComments, + const CodeCompletionContext &CCContext, PrintingPolicy &Policy) { + const NamedDecl* ND = Declaration; Result.addParentContext(ND->getDeclContext()); if (IncludeBriefComments) { @@ -2846,7 +2872,7 @@ Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); Result.AddTextChunk("::"); - return Result.TakeString(); + return; } for (const auto *I : ND->specific_attrs()) @@ -2862,7 +2888,7 @@ AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); - return Result.TakeString(); + return; } if (const FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { @@ -2916,7 +2942,7 @@ AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); - return Result.TakeString(); + return; } if (const TemplateDecl *Template = dyn_cast(ND)) { @@ -2927,15 +2953,14 @@ Result.AddChunk(CodeCompletionString::CK_LeftAngle); AddTemplateParameterChunks(Ctx, Policy, Template, Result); Result.AddChunk(CodeCompletionString::CK_RightAngle); - return Result.TakeString(); + return; } - if (const ObjCMethodDecl *Method = dyn_cast(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { Result.AddTypedTextChunk(Result.getAllocator().CopyString( Sel.getNameForSlot(0))); - return Result.TakeString(); + return; } std::string SelName = Sel.getNameForSlot(0).str(); @@ -3017,7 +3042,7 @@ MaybeAddSentinel(PP, Method, Result); } - return Result.TakeString(); + return; } if (Qualifier) @@ -3026,6 +3051,51 @@ Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); +} + +/// If possible, create a new code completion string for the given +/// result. +/// +/// \returns Either a new, heap-allocated code completion string describing +/// how to use this result, or NULL to indicate that the string or name of the +/// result is all that is needed. +CodeCompletionString * +CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, + Preprocessor &PP, + const CodeCompletionContext &CCContext, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + bool IncludeBriefComments) { + if (Kind == RK_Macro) + return CreateCodeCompletionStringForMacro(PP, Allocator, CCTUInfo); + + CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability); + + PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP); + if (Kind == RK_Pattern) { + Pattern->Priority = Priority; + Pattern->Availability = Availability; + + if (Declaration) { + Result.addParentContext(Declaration->getDeclContext()); + Pattern->ParentName = Result.getParentName(); + if (const RawComment *RC = + getPatternCompletionComment(Ctx, Declaration)) { + Result.addBriefComment(RC->getBriefText(Ctx)); + Pattern->BriefComment = Result.getBriefComment(); + } + } + + return Pattern; + } + + if (Kind == RK_Keyword) { + Result.AddTypedTextChunk(Keyword); + return Result.TakeString(); + } + assert(Kind == RK_Declaration && "Missed a result kind?"); + createCodeCompletionStringForDecl(PP, Ctx, Result, IncludeBriefComments, + CCContext, Policy); return Result.TakeString(); }