Index: include/clang/Sema/CodeCompleteConsumer.h =================================================================== --- include/clang/Sema/CodeCompleteConsumer.h +++ include/clang/Sema/CodeCompleteConsumer.h @@ -946,6 +946,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 @@ -1598,6 +1598,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, @@ -1706,6 +1766,9 @@ if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); + + AddOverrideResults(Results, CodeCompletionContext::CCC_ClassStructUnion, + Builder, SemaRef); } } LLVM_FALLTHROUGH; @@ -2834,7 +2897,16 @@ return Result.TakeString(); } assert(Kind == RK_Declaration && "Missed a result kind?"); - const NamedDecl *ND = Declaration; + createCodeCompletionStringForDecl(PP, Ctx, Result, IncludeBriefComments, + CCContext, Policy); + return Result.TakeString(); +} + +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) { @@ -2848,7 +2920,7 @@ Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); Result.AddTextChunk("::"); - return Result.TakeString(); + return; } for (const auto *I : ND->specific_attrs()) @@ -2864,7 +2936,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)) { @@ -2918,7 +2990,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)) { @@ -2929,15 +3001,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(); @@ -3019,7 +3090,7 @@ MaybeAddSentinel(PP, Method, Result); } - return Result.TakeString(); + return; } if (Qualifier) @@ -3028,7 +3099,6 @@ Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); - return Result.TakeString(); } const RawComment *clang::getCompletionComment(const ASTContext &Ctx, Index: test/CodeCompletion/overrides.cpp =================================================================== --- /dev/null +++ test/CodeCompletion/overrides.cpp @@ -0,0 +1,30 @@ +class A { + public: + virtual void vfunc(bool param); + virtual void vfunc(bool param, int p); + void func(bool param); +}; +class B : public A { +virtual int ttt(bool param) const; +void vfunc(bool param, int p) override; +}; +class C : public B { + public: + void vfunc(bool param) override; + void +}; + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:3 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:5 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC1: COMPLETION: Pattern : int ttt(bool param) const override +// CHECK-CC2-NOT: COMPLETION: Pattern : int ttt(bool param) const override +// CHECK-CC3-NOT: COMPLETION: Pattern : int ttt(bool param) const override +// +// CHECK-CC1: COMPLETION: Pattern : void vfunc(bool param, int p) override +// CHECK-CC2: COMPLETION: Pattern : void vfunc(bool param, int p) override +// CHECK-CC3-NOT: COMPLETION: Pattern : void vfunc(bool param, int p) override +// +// CHECK-CC1-NOT: COMPLETION: Pattern : void vfunc(bool param) override +// CHECK-CC2-NOT: COMPLETION: Pattern : void vfunc(bool param) override +// CHECK-CC3-NOT: COMPLETION: Pattern : void vfunc(bool param) override