Index: include/clang/Sema/CodeCompleteConsumer.h =================================================================== --- include/clang/Sema/CodeCompleteConsumer.h +++ include/clang/Sema/CodeCompleteConsumer.h @@ -946,6 +946,16 @@ CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo); + CodeCompletionString *createCodeCompletionStringForDecl( + Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, + bool IncludeBriefComments, const CodeCompletionContext &CCContext, + PrintingPolicy &Policy); + + CodeCompletionString *createCodeCompletionStringForOverride( + 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,74 @@ Results.AddResult(CodeCompletionResult(Builder.TakeString())); } +namespace { +void printOverrideString(llvm::raw_ostream &OS, CodeCompletionString *CCS) { + for (const auto &C : *CCS) { + if (C.Kind == CodeCompletionString::CK_Optional) + printOverrideString(OS, C.Optional); + else + OS << C.Text; + // Add a space after return type. + if (C.Kind == CodeCompletionString::CK_ResultType) + OS << ' '; + } +} +} // namespace + +static void AddOverrideResults(ResultBuilder &Results, + const CodeCompletionContext &CCContext, + CodeCompletionBuilder &Builder) { + Sema &S = Results.getSema(); + 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) { + // Generates a new CodeCompletionResult by taking this function and + // converting it into an override declaration with only one chunk in the + // final CodeCompletionString as a TypedTextChunk. + std::string OverrideSignature; + llvm::raw_string_ostream OS(OverrideSignature); + CodeCompletionResult CCR(Method, 0); + PrintingPolicy Policy = + getCompletionPrintingPolicy(S.getASTContext(), S.getPreprocessor()); + auto *CCS = CCR.createCodeCompletionStringForOverride( + S.getPreprocessor(), S.getASTContext(), Builder, + /*IncludeBriefComments=*/false, CCContext, Policy); + Results.AddResult(CodeCompletionResult(CCS, Method, CCP_CodePattern)); + } + } + } +} + /// Add language constructs that show up for "ordinary" names. static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, @@ -1706,6 +1774,12 @@ if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); + + // FIXME: This adds override results only if we are at the first word of + // the declaration/definition. Also call this from other sides to have + // more use-cases. + AddOverrideResults(Results, CodeCompletionContext::CCC_ClassStructUnion, + Builder); } } LLVM_FALLTHROUGH; @@ -2834,6 +2908,30 @@ return Result.TakeString(); } assert(Kind == RK_Declaration && "Missed a result kind?"); + return createCodeCompletionStringForDecl(PP, Ctx, Result, IncludeBriefComments, + CCContext, Policy); +} + +CodeCompletionString * +CodeCompletionResult::createCodeCompletionStringForOverride( + Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, + bool IncludeBriefComments, const CodeCompletionContext &CCContext, + PrintingPolicy &Policy) { + std::string OverrideSignature; + llvm::raw_string_ostream OS(OverrideSignature); + auto *CCS = createCodeCompletionStringForDecl(PP, Ctx, Result, + /*IncludeBriefComments=*/false, + CCContext, Policy); + printOverrideString(OS, CCS); + OS << " override"; + Result.AddTypedTextChunk(Result.getAllocator().CopyString(OS.str())); + return Result.TakeString(); +} + +CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( + Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, + bool IncludeBriefComments, const CodeCompletionContext &CCContext, + PrintingPolicy &Policy) { const NamedDecl *ND = Declaration; Result.addParentContext(ND->getDeclContext()); @@ -2931,7 +3029,6 @@ Result.AddChunk(CodeCompletionString::CK_RightAngle); return Result.TakeString(); } - if (const ObjCMethodDecl *Method = dyn_cast(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { @@ -3027,7 +3124,7 @@ Ctx, Policy); Result.AddTypedTextChunk( - Result.getAllocator().CopyString(ND->getNameAsString())); + Result.getAllocator().CopyString(ND->getNameAsString())); return Result.TakeString(); } Index: test/CodeCompletion/overrides.cpp =================================================================== --- /dev/null +++ test/CodeCompletion/overrides.cpp @@ -0,0 +1,33 @@ +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, int x = 3) const; +void vfunc(bool param, int p) override; +}; +class C : public B { + public: + void vfunc(bool param) override; + void +}; + +// Runs completion at ^void. +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:3 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: COMPLETION: Pattern : int ttt(bool param, int x = 3) const override{{$}} +// CHECK-CC1: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}} +// CHECK-CC1-NOT: COMPLETION: Pattern : void vfunc(bool param) override{{$}} +// +// Runs completion at vo^id. +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:5 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}} +// CHECK-CC2-NOT: COMPLETION: Pattern : int ttt(bool param, int x = 3) const override{{$}} +// CHECK-CC2-NOT: COMPLETION: Pattern : void vfunc(bool param) override{{$}} +// +// Runs completion at void ^. +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3-NOT: COMPLETION: Pattern : int ttt(bool param, int x = 3) const override{{$}} +// CHECK-CC3-NOT: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}} +// CHECK-CC3-NOT: COMPLETION: Pattern : void vfunc(bool param) override{{$}}