Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -1362,12 +1362,9 @@ typedef SmallVector CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. - bool - ParseExpressionList(SmallVectorImpl &Exprs, - SmallVectorImpl &CommaLocs, - void (Sema::*Completer)(Scope *S, Expr *Data, - ArrayRef Args) = nullptr, - Expr *Data = nullptr); + bool ParseExpressionList(SmallVectorImpl &Exprs, + SmallVectorImpl &CommaLocs, + std::function Completer = {}); /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -8405,6 +8405,8 @@ void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteCase(Scope *S); void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args); + void CodeCompleteConstructor(Scope *S, CXXRecordDecl *DC, SourceLocation Loc, + ArrayRef Args); void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteReturn(Scope *S); void CodeCompleteAfterIf(Scope *S); Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -1990,7 +1990,12 @@ Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); } - if (ParseExpressionList(Exprs, CommaLocs)) { + if (ParseExpressionList(Exprs, CommaLocs, [&] { + QualType T = cast(ThisDecl)->getCanonicalDecl()->getType(); + Actions.CodeCompleteConstructor(getCurScope(), + T->getAsCXXRecordDecl(), + ThisDecl->getLocation(), Exprs); + })) { Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren, StopAtSemi); Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1441,8 +1441,9 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, - LHS.get())) { + if (ParseExpressionList(ArgExprs, CommaLocs, [&] { + Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); + })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } @@ -2488,17 +2489,14 @@ /// [C++0x] assignment-expression /// [C++0x] braced-init-list /// \endverbatim -bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, +bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, SmallVectorImpl &CommaLocs, - void (Sema::*Completer)(Scope *S, - Expr *Data, - ArrayRef Args), - Expr *Data) { + std::function Completer) { bool SawError = false; while (1) { if (Tok.is(tok::code_completion)) { if (Completer) - (Actions.*Completer)(getCurScope(), Data, Exprs); + Completer(); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); cutOffParsing(); Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1598,7 +1598,12 @@ CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(Exprs, CommaLocs)) { + if (ParseExpressionList(Exprs, CommaLocs, [&] { + QualType T = TypeRep.get()->getCanonicalTypeInternal(); + Actions.CodeCompleteConstructor(getCurScope(), + T->getAsCXXRecordDecl(), + DS.getLocEnd(), Exprs); + })) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2664,7 +2669,15 @@ ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; - if (ParseExpressionList(ConstructorArgs, CommaLocs)) { + if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] { + ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), + DeclaratorInfo).get(); + QualType T = TypeRep.get()->getCanonicalTypeInternal(); + Actions.CodeCompleteConstructor(getCurScope(), + T->getAsCXXRecordDecl(), + DeclaratorInfo.getLocEnd(), + ConstructorArgs); + })) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -3824,8 +3824,6 @@ // name code-completion whenever we can't produce specific // results. This will do "parameter completion" solely. - // FIXME: Provide support for constructors - Expr *Fn = (Expr *)FnIn; // Ignore type-dependent call expressions entirely. @@ -3953,6 +3951,64 @@ } } +void Sema::CodeCompleteConstructor(Scope *S, CXXRecordDecl *DC, + SourceLocation Loc, ArrayRef Args) { + if (!CodeCompleter) + return; + + // FIXME: Provide support for completing constructors of templates that are + // being declared for the first time. + OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + + typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; + SmallVector Results; + + for(auto C : LookupConstructors(DC)) { + if (auto FD = dyn_cast(C)) { + AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), + Args, CandidateSet, + /*SuppressUsedConversions=*/false, + /*PartialOverloading=*/true); + } else if (auto FTD = dyn_cast(C)) { + AddTemplateOverloadCandidate(FTD, + DeclAccessPair::make(FTD, C->getAccess()), + /*ExplicitTemplateArgs=*/nullptr, + Args, CandidateSet, + /*SuppressUsedConversions=*/false, + /*PartialOverloading=*/true); + } + } + + if (!CandidateSet.empty()) { + // Sort the overload candidate set by placing the best overloads first. + std::stable_sort( + CandidateSet.begin(), CandidateSet.end(), + [&](const OverloadCandidate &X, const OverloadCandidate &Y) { + return isBetterOverloadCandidate(*this, X, Y, Loc); + }); + + // Add the overload candidates as code-completion results. + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) { + if (Cand->Viable || Cand->FailureKind == ovl_fail_too_many_arguments) + Results.push_back(ResultCandidate(Cand->Function)); + } + } + + if (!Results.empty()) { + // An empty ResultBuilder solely to set CodeCompletionContext + ResultBuilder r(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + mapCodeCompletionContext(*this, PCC_Expression)); + HandleCodeCompleteResults(this, CodeCompleter, r.getCompletionContext(), + r.data(), r.size()); + + CodeCompleter->ProcessOverloadCandidates(*this, Args.size(), Results.data(), + Results.size()); + } +} + void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { ValueDecl *VD = dyn_cast_or_null(D); if (!VD) { Index: test/Index/complete-constructor-params.cpp =================================================================== --- /dev/null +++ test/Index/complete-constructor-params.cpp @@ -0,0 +1,147 @@ +// Note: the run lines follow their respective tests, since line/column +// matter in this test. + +template +struct S { + template + S(T, U, U) {} +}; + +int main() { + S(42, 42, 42); // <- no completion since it's the first specialization. Fix? + S(42, 42, 42); // <- since there's a specialization already, we get completions. + S s(42, 42, 42); + + S(42, 42, 42,); + S z(42, 42, 42,); +} + +// RUN: c-index-test -code-completion-at=%s:11:10 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: Completion contexts: +// CHECK-CC1-NEXT: Unknown +// CHECK-CC1-NEXT: Any type +// CHECK-CC1-NEXT: Any value +// CHECK-CC1-NEXT: Objective-C object value +// CHECK-CC1-NEXT: Objective-C selector value +// CHECK-CC1-NEXT: C++ class type value +// CHECK-CC1-NEXT: Dot member access +// CHECK-CC1-NEXT: Arrow member access +// CHECK-CC1-NEXT: Objective-C property access +// CHECK-CC1-NEXT: Enum tag +// CHECK-CC1-NEXT: Union tag +// CHECK-CC1-NEXT: Struct tag +// CHECK-CC1-NEXT: Class name +// CHECK-CC1-NEXT: Namespace or namespace alias +// CHECK-CC1-NEXT: Nested name specifier +// CHECK-CC1-NEXT: Objective-C interface +// CHECK-CC1-NEXT: Objective-C protocol +// CHECK-CC1-NEXT: Objective-C category +// CHECK-CC1-NEXT: Objective-C instance method +// CHECK-CC1-NEXT: Objective-C class method +// CHECK-CC1-NEXT: Objective-C selector name +// CHECK-CC1-NEXT: Macro name +// CHECK-CC1-NEXT: Natural language + +// RUN: c-index-test -code-completion-at=%s:12:10 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: NotImplemented:{Text S}{LeftParen (}{CurrentParameter const S &}{RightParen )} (1) +// CHECK-CC2: NotImplemented:{Text S}{LeftParen (}{CurrentParameter int}{Comma , }{Text U}{Comma , }{Text U}{RightParen )} (1) +// CHECK-CC2: Completion contexts: +// CHECK-CC2-NEXT: Any type +// CHECK-CC2-NEXT: Any value +// CHECK-CC2-NEXT: Enum tag +// CHECK-CC2-NEXT: Union tag +// CHECK-CC2-NEXT: Struct tag +// CHECK-CC2-NEXT: Class name +// CHECK-CC2-NEXT: Nested name specifier +// CHECK-CC2-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:12:13 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: NotImplemented:{Text S}{LeftParen (}{Text int}{Comma , }{CurrentParameter U}{Comma , }{Text U}{RightParen )} (1) +// CHECK-CC3: NotImplemented:{Text S}{LeftParen (}{Text const S &}{RightParen )} (1) +// CHECK-CC3: Completion contexts: +// CHECK-CC3-NEXT: Any type +// CHECK-CC3-NEXT: Any value +// CHECK-CC3-NEXT: Enum tag +// CHECK-CC3-NEXT: Union tag +// CHECK-CC3-NEXT: Struct tag +// CHECK-CC3-NEXT: Class name +// CHECK-CC3-NEXT: Nested name specifier +// CHECK-CC3-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:12:17 %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: NotImplemented:{Text S}{LeftParen (}{Text int}{Comma , }{Text int}{Comma , }{CurrentParameter int}{RightParen )} (1) +// CHECK-CC4: NotImplemented:{Text S}{LeftParen (}{Text const S &}{RightParen )} (1) +// CHECK-CC4: Completion contexts: +// CHECK-CC4-NEXT: Any type +// CHECK-CC4-NEXT: Any value +// CHECK-CC4-NEXT: Enum tag +// CHECK-CC4-NEXT: Union tag +// CHECK-CC4-NEXT: Struct tag +// CHECK-CC4-NEXT: Class name +// CHECK-CC4-NEXT: Nested name specifier +// CHECK-CC4-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:13:12 %s | FileCheck -check-prefix=CHECK-CC5 %s +// CHECK-CC5: NotImplemented:{Text S}{LeftParen (}{CurrentParameter const S &}{RightParen )} (1) +// CHECK-CC5: NotImplemented:{Text S}{LeftParen (}{CurrentParameter int}{Comma , }{Text U}{Comma , }{Text U}{RightParen )} (1) +// CHECK-CC5: Completion contexts: +// CHECK-CC5-NEXT: Any type +// CHECK-CC5-NEXT: Any value +// CHECK-CC5-NEXT: Enum tag +// CHECK-CC5-NEXT: Union tag +// CHECK-CC5-NEXT: Struct tag +// CHECK-CC5-NEXT: Class name +// CHECK-CC5-NEXT: Nested name specifier +// CHECK-CC5-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:13:15 %s | FileCheck -check-prefix=CHECK-CC6 %s +// CHECK-CC6: NotImplemented:{Text S}{LeftParen (}{Text int}{Comma , }{CurrentParameter U}{Comma , }{Text U}{RightParen )} (1) +// CHECK-CC6: NotImplemented:{Text S}{LeftParen (}{Text const S &}{RightParen )} (1) +// CHECK-CC6: Completion contexts: +// CHECK-CC6-NEXT: Any type +// CHECK-CC6-NEXT: Any value +// CHECK-CC6-NEXT: Enum tag +// CHECK-CC6-NEXT: Union tag +// CHECK-CC6-NEXT: Struct tag +// CHECK-CC6-NEXT: Class name +// CHECK-CC6-NEXT: Nested name specifier +// CHECK-CC6-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:13:19 %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: NotImplemented:{Text S}{LeftParen (}{Text int}{Comma , }{Text int}{Comma , }{CurrentParameter int}{RightParen )} (1) +// CHECK-CC7: NotImplemented:{Text S}{LeftParen (}{Text const S &}{RightParen )} (1) +// CHECK-CC7: Completion contexts: +// CHECK-CC7-NEXT: Any type +// CHECK-CC7-NEXT: Any value +// CHECK-CC7-NEXT: Enum tag +// CHECK-CC7-NEXT: Union tag +// CHECK-CC7-NEXT: Struct tag +// CHECK-CC7-NEXT: Class name +// CHECK-CC7-NEXT: Nested name specifier +// CHECK-CC7-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:15:21 %s | FileCheck -check-prefix=CHECK-CC8 %s +// CHECK-CC8: NotImplemented:{Text S}{LeftParen (}{Text int}{Comma , }{Text U}{Comma , }{Text U}{RightParen )} (1) +// CHECK-CC8: NotImplemented:{Text S}{LeftParen (}{Text const S &}{RightParen )} (1) +// CHECK-CC8: Completion contexts: +// CHECK-CC8-NEXT: Any type +// CHECK-CC8-NEXT: Any value +// CHECK-CC8-NEXT: Enum tag +// CHECK-CC8-NEXT: Union tag +// CHECK-CC8-NEXT: Struct tag +// CHECK-CC8-NEXT: Class name +// CHECK-CC8-NEXT: Nested name specifier +// CHECK-CC8-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:16:23 %s | FileCheck -check-prefix=CHECK-CC9 %s +// CHECK-CC9: NotImplemented:{Text S}{LeftParen (}{Text int}{Comma , }{Text U}{Comma , }{Text U}{RightParen )} (1) +// CHECK-CC9: NotImplemented:{Text S}{LeftParen (}{Text const S &}{RightParen )} (1) +// CHECK-CC9: Completion contexts: +// CHECK-CC9-NEXT: Any type +// CHECK-CC9-NEXT: Any value +// CHECK-CC9-NEXT: Enum tag +// CHECK-CC9-NEXT: Union tag +// CHECK-CC9-NEXT: Struct tag +// CHECK-CC9-NEXT: Class name +// CHECK-CC9-NEXT: Nested name specifier +// CHECK-CC9-NEXT: Objective-C interface Index: test/Index/complete-exprs.cpp =================================================================== --- test/Index/complete-exprs.cpp +++ test/Index/complete-exprs.cpp @@ -66,14 +66,6 @@ // CHECK-CC2-NOT: CXXConstructor // CHECK-CC2: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50) -// RUN: c-index-test -code-completion-at=%s:26:15 %s | FileCheck -check-prefix=CHECK-CC3 %s -// CHECK-CC3: NotImplemented:{TypedText float} (50) -// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText foo}{LeftParen (}{RightParen )} (50) -// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{RightParen )} (50) -// CHECK-CC3: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50) -// CHECK-CC3: CXXConstructor:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder const T &}{Comma , }{Placeholder unsigned int n}{RightParen )} (50) -// CHECK-CC3: FunctionTemplate:{ResultType void}{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder InputIterator first}{Comma , }{Placeholder InputIterator last}{RightParen )} (50) - // RUN: c-index-test -code-completion-at=%s:34:1 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC4 %s // CHECK-CC4: NotImplemented:{ResultType const X *}{TypedText this} (40)