Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2677,7 +2677,8 @@ OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, - bool PartialOverloading = false); + bool PartialOverloading = false, + bool ExtraFirstArgument = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -5868,6 +5868,7 @@ // function, e.g., X::f(). We use an empty type for the implied // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. + AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, CandidateSet, SuppressUserConversions, @@ -6317,7 +6318,8 @@ OverloadCandidateSet& CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs, bool SuppressUserConversions, - bool PartialOverloading) { + bool PartialOverloading, + bool ExtraFirstArgument) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { NamedDecl *D = F.getDecl()->getUnderlyingDecl(); if (FunctionDecl *FD = dyn_cast(D)) { @@ -6334,6 +6336,11 @@ ObjectClassification, Args.slice(1), CandidateSet, SuppressUserConversions, PartialOverloading); } else { + // Slice the first argument when we access static method as non-static + if (Args.size() > 0 && ExtraFirstArgument && isa(FD) + && !isa(FD)) { + Args = Args.slice(1); + } AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet, SuppressUserConversions, PartialOverloading); } Index: test/Index/complete-call.cpp =================================================================== --- test/Index/complete-call.cpp +++ test/Index/complete-call.cpp @@ -94,6 +94,17 @@ s.foo_7(42,); } +struct Bar { + static void foo_1(); + static void foo_1(int); +}; + +void test() { + Bar::foo_1(); + Bar b; + b.foo_1(); +} + // RUN: c-index-test -code-completion-at=%s:47:9 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) // CHECK-CC1: Completion contexts: @@ -803,3 +814,29 @@ // CHECK-CC59-NEXT: Class name // CHECK-CC59-NEXT: Nested name specifier // CHECK-CC59-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:103:14 %s | FileCheck -check-prefix=CHECK-CC60 %s +// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) +// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1) +// CHECK-CC60: Completion contexts: +// CHECK-CC60-NEXT: Any type +// CHECK-CC60-NEXT: Any value +// CHECK-CC60-NEXT: Enum tag +// CHECK-CC60-NEXT: Union tag +// CHECK-CC60-NEXT: Struct tag +// CHECK-CC60-NEXT: Class name +// CHECK-CC60-NEXT: Nested name specifier +// CHECK-CC60-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:105:11 %s | FileCheck -check-prefix=CHECK-CC61 %s +// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) +// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1) +// CHECK-CC61: Completion contexts: +// CHECK-CC61-NEXT: Any type +// CHECK-CC61-NEXT: Any value +// CHECK-CC61-NEXT: Enum tag +// CHECK-CC61-NEXT: Union tag +// CHECK-CC61-NEXT: Struct tag +// CHECK-CC61-NEXT: Class name +// CHECK-CC61-NEXT: Nested name specifier +// CHECK-CC61-NEXT: Objective-C interface