Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -10795,6 +10795,9 @@ Decl *D; }; +ValueDecl *tryGetMember(CXXRecordDecl *ClassDecl, CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase); } // end namespace clang namespace llvm { Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -3449,6 +3449,7 @@ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + // FIXME: Add support for signature help inside initializer lists. ExprResult InitList = ParseBraceInitializer(); if (InitList.isInvalid()) return true; @@ -3466,7 +3467,26 @@ // Parse the optional expression-list. ExprVector ArgExprs; CommaLocsTy CommaLocs; - if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { + auto SignatureHelpCaller = [&] { + if (CalledSignatureHelp) + return; + CXXConstructorDecl *Constructor = + dyn_cast(ConstructorDecl); + if (!Constructor) + return; + // FIXME: Add support for Base class constructors as well. + if (ValueDecl *MemberDecl = + tryGetMember(Constructor->getParent(), SS, TemplateTypeTy, II)) { + Actions.ProduceConstructorSignatureHelp( + getCurScope(), MemberDecl->getType(), MemberDecl->getLocation(), + ArgExprs, T.getOpenLocation()); + CalledSignatureHelp = true; + } + }; + if (Tok.isNot(tok::r_paren) && + ParseExpressionList(ArgExprs, CommaLocs, SignatureHelpCaller)) { + if (PP.isCodeCompletionReached()) + SignatureHelpCaller(); SkipUntil(tok::r_paren, StopAtSemi); return true; } Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3777,6 +3777,23 @@ } +ValueDecl *clang::tryGetMember(CXXRecordDecl *ClassDecl, CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase) { + if (!SS.getScopeRep() && !TemplateTypeTy) { + // Look for a member, first. + DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); + if (!Result.empty()) { + ValueDecl *Member; + if ((Member = dyn_cast(Result.front())) || + (Member = dyn_cast(Result.front()))) { + return Member; + } + } + } + return nullptr; +} + /// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, @@ -3820,21 +3837,14 @@ // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] - if (!SS.getScopeRep() && !TemplateTypeTy) { - // Look for a member, first. - DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); - if (!Result.empty()) { - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front()))) { - if (EllipsisLoc.isValid()) - Diag(EllipsisLoc, diag::err_pack_expansion_member_init) - << MemberOrBase - << SourceRange(IdLoc, Init->getSourceRange().getEnd()); - - return BuildMemberInitializer(Member, Init, IdLoc); - } - } + if (ValueDecl *Member = + tryGetMember(ClassDecl, SS, TemplateTypeTy, MemberOrBase)) { + if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + + return BuildMemberInitializer(Member, Init, IdLoc); } // It didn't name a member, so see if it names a class. QualType BaseType; Index: test/CodeCompletion/ctor-initializer.cpp =================================================================== --- test/CodeCompletion/ctor-initializer.cpp +++ test/CodeCompletion/ctor-initializer.cpp @@ -64,3 +64,26 @@ // CHECK-CC8: COMPLETION: Pattern : member2(<#args#> int member1, member2; }; + +struct Base2 { + Base2(int); +}; + +struct Composition1 { + Composition1() : b2_elem() {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // CHECK-CC9: OVERLOAD: Base2(<#int#>) + // CHECK-CC9: OVERLOAD: Base2(<#const Base2 &#>) + Composition1(Base2); + Base2 b2_elem; +}; + +struct Composition2 { + Composition2() : c1_elem(Base2(1)) {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + Composition1 c1_elem; +};