[CodeCompletion] Signature help for braced constructor calls

Implementation is based on the "expected type" as used for
designated-initializers in braced init lists. This means it can deduce the type
in some cases where it's not written:

  void foo(Widget);
  foo({ /*help here*/ });

Only basic constructor calls are in scope of this patch, excluded are:
 - aggregate initialization (no help is offered for aggregates)
 - initializer_list initialization (no help is offered for these constructors)

Fixes https://github.com/clangd/clangd/issues/306

Differential Revision: https://reviews.llvm.org/D116317
This commit is contained in:
Sam McCall 2021-12-27 20:42:11 +01:00
parent a390c9905d
commit 92417eaf33
17 changed files with 169 additions and 54 deletions

View File

@ -555,7 +555,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
}}, }},
{"signatureHelpProvider", {"signatureHelpProvider",
llvm::json::Object{ llvm::json::Object{
{"triggerCharacters", {"(", ",", ")", "<", ">"}}, {"triggerCharacters", {"(", ")", "{", "}", "<", ">", ","}},
}}, }},
{"declarationProvider", true}, {"declarationProvider", true},
{"definitionProvider", true}, {"definitionProvider", true},

View File

@ -921,7 +921,8 @@ public:
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) override { SourceLocation OpenParLoc,
bool Braced) override {
assert(!OpenParLoc.isInvalid()); assert(!OpenParLoc.isInvalid());
SourceManager &SrcMgr = S.getSourceManager(); SourceManager &SrcMgr = S.getSourceManager();
OpenParLoc = SrcMgr.getFileLoc(OpenParLoc); OpenParLoc = SrcMgr.getFileLoc(OpenParLoc);
@ -961,8 +962,9 @@ public:
paramIndexForArg(Candidate, SigHelp.activeParameter); paramIndexForArg(Candidate, SigHelp.activeParameter);
} }
const auto *CCS = Candidate.CreateSignatureString( const auto *CCS =
CurrentArg, S, *Allocator, CCTUInfo, true); Candidate.CreateSignatureString(CurrentArg, S, *Allocator, CCTUInfo,
/*IncludeBriefComment=*/true, Braced);
assert(CCS && "Expected the CodeCompletionString to be non-null"); assert(CCS && "Expected the CodeCompletionString to be non-null");
ScoredSignatures.push_back(processOverloadCandidate( ScoredSignatures.push_back(processOverloadCandidate(
Candidate, *CCS, Candidate, *CCS,
@ -1163,7 +1165,8 @@ public:
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) override { SourceLocation OpenParLoc,
bool Braced) override {
assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() && assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() &&
"too many arguments"); "too many arguments");

View File

@ -107,10 +107,12 @@
# CHECK-NEXT: "signatureHelpProvider": { # CHECK-NEXT: "signatureHelpProvider": {
# CHECK-NEXT: "triggerCharacters": [ # CHECK-NEXT: "triggerCharacters": [
# CHECK-NEXT: "(", # CHECK-NEXT: "(",
# CHECK-NEXT: ",",
# CHECK-NEXT: ")", # CHECK-NEXT: ")",
# CHECK-NEXT: "{",
# CHECK-NEXT: "}",
# CHECK-NEXT: "<", # CHECK-NEXT: "<",
# CHECK-NEXT: ">" # CHECK-NEXT: ">"
# CHECK-NEXT: ","
# CHECK-NEXT: ] # CHECK-NEXT: ]
# CHECK-NEXT: }, # CHECK-NEXT: },
# CHECK-NEXT: "textDocumentSync": { # CHECK-NEXT: "textDocumentSync": {

View File

@ -1212,6 +1212,10 @@ struct ExpectedParameter {
std::string Text; std::string Text;
std::pair<unsigned, unsigned> Offsets; std::pair<unsigned, unsigned> Offsets;
}; };
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const ExpectedParameter &P) {
return OS << P.Text;
}
MATCHER_P(ParamsAre, P, "") { MATCHER_P(ParamsAre, P, "") {
if (P.size() != arg.parameters.size()) if (P.size() != arg.parameters.size())
return false; return false;
@ -1260,6 +1264,36 @@ TEST(SignatureHelpTest, Overloads) {
EXPECT_EQ(0, Results.activeParameter); EXPECT_EQ(0, Results.activeParameter);
} }
TEST(SignatureHelpTest, Constructors) {
std::string Top = R"cpp(
struct S {
S(int);
S(const S &) = delete;
};
)cpp";
auto CheckParenInit = [&](std::string Init) {
EXPECT_THAT(signatures(Top + Init).signatures,
UnorderedElementsAre(Sig("S([[int]])")))
<< Init;
};
CheckParenInit("S s(^);");
CheckParenInit("auto s = S(^);");
CheckParenInit("auto s = new S(^);");
auto CheckBracedInit = [&](std::string Init) {
EXPECT_THAT(signatures(Top + Init).signatures,
UnorderedElementsAre(Sig("S{[[int]]}")))
<< Init;
};
CheckBracedInit("S s{^};");
CheckBracedInit("S s = {^};");
CheckBracedInit("auto s = S{^};");
// FIXME: doesn't work: no ExpectedType set in ParseCXXNewExpression.
// CheckBracedInit("auto s = new S{^};");
CheckBracedInit("int x(S); int i = x({^});");
}
TEST(SignatureHelpTest, OverloadInitListRegression) { TEST(SignatureHelpTest, OverloadInitListRegression) {
auto Results = signatures(R"cpp( auto Results = signatures(R"cpp(
struct A {int x;}; struct A {int x;};

View File

@ -1081,11 +1081,11 @@ public:
/// Create a new code-completion string that describes the function /// Create a new code-completion string that describes the function
/// signature of this overload candidate. /// signature of this overload candidate.
CodeCompletionString *CreateSignatureString(unsigned CurrentArg, CodeCompletionString *
Sema &S, CreateSignatureString(unsigned CurrentArg, Sema &S,
CodeCompletionAllocator &Allocator, CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo, CodeCompletionTUInfo &CCTUInfo,
bool IncludeBriefComments) const; bool IncludeBriefComments, bool Braced) const;
}; };
CodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts) CodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts)
@ -1159,7 +1159,8 @@ public:
virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) {} SourceLocation OpenParLoc,
bool Braced) {}
//@} //@}
/// Retrieve the allocator that will be used to allocate /// Retrieve the allocator that will be used to allocate
@ -1210,7 +1211,8 @@ public:
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) override; SourceLocation OpenParLoc,
bool Braced) override;
bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override; bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override;

View File

@ -12542,13 +12542,12 @@ public:
QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type, QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type,
SourceLocation Loc, SourceLocation Loc,
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
SourceLocation OpenParLoc); SourceLocation OpenParLoc,
QualType ProduceCtorInitMemberSignatureHelp(Scope *S, Decl *ConstructorDecl, bool Braced);
CXXScopeSpec SS, QualType ProduceCtorInitMemberSignatureHelp(
ParsedType TemplateTypeTy, Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS,
ArrayRef<Expr *> ArgExprs, ParsedType TemplateTypeTy, ArrayRef<Expr *> ArgExprs, IdentifierInfo *II,
IdentifierInfo *II, SourceLocation OpenParLoc, bool Braced);
SourceLocation OpenParLoc);
QualType ProduceTemplateArgumentSignatureHelp( QualType ProduceTemplateArgumentSignatureHelp(
TemplateTy, ArrayRef<ParsedTemplateArgument>, SourceLocation LAngleLoc); TemplateTy, ArrayRef<ParsedTemplateArgument>, SourceLocation LAngleLoc);
void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteInitializer(Scope *S, Decl *D);

View File

@ -1922,9 +1922,10 @@ namespace {
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) override { SourceLocation OpenParLoc,
bool Braced) override {
Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates, Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates,
OpenParLoc); OpenParLoc, Braced);
} }
CodeCompletionAllocator &getAllocator() override { CodeCompletionAllocator &getAllocator() override {

View File

@ -2420,7 +2420,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
auto RunSignatureHelp = [&]() { auto RunSignatureHelp = [&]() {
QualType PreferredType = Actions.ProduceConstructorSignatureHelp( QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
ThisDecl->getLocation(), Exprs, T.getOpenLocation()); ThisDecl->getLocation(), Exprs, T.getOpenLocation(),
/*Braced=*/false);
CalledSignatureHelp = true; CalledSignatureHelp = true;
return PreferredType; return PreferredType;
}; };
@ -2440,7 +2441,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp( Actions.ProduceConstructorSignatureHelp(
getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
ThisDecl->getLocation(), Exprs, T.getOpenLocation()); ThisDecl->getLocation(), Exprs, T.getOpenLocation(),
/*Braced=*/false);
CalledSignatureHelp = true; CalledSignatureHelp = true;
} }
Actions.ActOnInitializerError(ThisDecl); Actions.ActOnInitializerError(ThisDecl);

View File

@ -3740,8 +3740,8 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
if (TemplateTypeTy.isInvalid()) if (TemplateTypeTy.isInvalid())
return QualType(); return QualType();
QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp(
getCurScope(), ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II, getCurScope(), ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs,
T.getOpenLocation()); II, T.getOpenLocation(), /*Braced=*/false);
CalledSignatureHelp = true; CalledSignatureHelp = true;
return PreferredType; return PreferredType;
}; };

View File

@ -1878,7 +1878,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
if (TypeRep) if (TypeRep)
PreferredType = Actions.ProduceConstructorSignatureHelp( PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
DS.getEndLoc(), Exprs, T.getOpenLocation()); DS.getEndLoc(), Exprs, T.getOpenLocation(), /*Braced=*/false);
CalledSignatureHelp = true; CalledSignatureHelp = true;
return PreferredType; return PreferredType;
}; };
@ -3168,7 +3168,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (TypeRep) if (TypeRep)
PreferredType = Actions.ProduceConstructorSignatureHelp( PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen,
/*Braced=*/false);
CalledSignatureHelp = true; CalledSignatureHelp = true;
return PreferredType; return PreferredType;
}; };

View File

@ -459,12 +459,22 @@ ExprResult Parser::ParseBraceInitializer() {
Actions, EnterExpressionEvaluationContext::InitList); Actions, EnterExpressionEvaluationContext::InitList);
bool InitExprsOk = true; bool InitExprsOk = true;
DesignatorCompletionInfo DesignatorCompletion{ QualType LikelyType = PreferredType.get(T.getOpenLocation());
InitExprs, DesignatorCompletionInfo DesignatorCompletion{InitExprs, LikelyType};
PreferredType.get(T.getOpenLocation()), bool CalledSignatureHelp = false;
auto RunSignatureHelp = [&] {
QualType PreferredType;
if (!LikelyType.isNull())
PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), LikelyType->getCanonicalTypeInternal(),
T.getOpenLocation(), InitExprs, T.getOpenLocation(), /*Braced=*/true);
CalledSignatureHelp = true;
return PreferredType;
}; };
while (1) { while (1) {
PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp);
// Handle Microsoft __if_exists/if_not_exists if necessary. // Handle Microsoft __if_exists/if_not_exists if necessary.
if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) { Tok.is(tok::kw___if_not_exists))) {

View File

@ -471,7 +471,7 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() { auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() {
QualType PreferredType = Actions.ProduceConstructorSignatureHelp( QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(),
OmpPrivParm->getLocation(), Exprs, LParLoc); OmpPrivParm->getLocation(), Exprs, LParLoc, /*Braced=*/false);
CalledSignatureHelp = true; CalledSignatureHelp = true;
return PreferredType; return PreferredType;
}; };

View File

@ -656,7 +656,7 @@ static std::string getOverloadAsString(const CodeCompletionString &CCS) {
void PrintingCodeCompleteConsumer::ProcessOverloadCandidates( void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(
Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates, Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates,
unsigned NumCandidates, SourceLocation OpenParLoc) { unsigned NumCandidates, SourceLocation OpenParLoc, bool Braced) {
OS << "OPENING_PAREN_LOC: "; OS << "OPENING_PAREN_LOC: ";
OpenParLoc.print(OS, SemaRef.getSourceManager()); OpenParLoc.print(OS, SemaRef.getSourceManager());
OS << "\n"; OS << "\n";
@ -664,7 +664,7 @@ void PrintingCodeCompleteConsumer::ProcessOverloadCandidates(
for (unsigned I = 0; I != NumCandidates; ++I) { for (unsigned I = 0; I != NumCandidates; ++I) {
if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString( if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString(
CurrentArg, SemaRef, getAllocator(), CCTUInfo, CurrentArg, SemaRef, getAllocator(), CCTUInfo,
includeBriefComments())) { includeBriefComments(), Braced)) {
OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n"; OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n";
} }
} }

View File

@ -3833,7 +3833,8 @@ static CodeCompletionString *createTemplateSignatureString(
CodeCompletionString * CodeCompletionString *
CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator, unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const { CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments,
bool Braced) const {
PrintingPolicy Policy = getCompletionPrintingPolicy(S); PrintingPolicy Policy = getCompletionPrintingPolicy(S);
// Show signatures of constructors as they are declared: // Show signatures of constructors as they are declared:
// vector(int n) rather than vector<string>(int n) // vector(int n) rather than vector<string>(int n)
@ -3857,9 +3858,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
const FunctionType *FT = getFunctionType(); const FunctionType *FT = getFunctionType();
Result.AddResultTypeChunk(Result.getAllocator().CopyString( Result.AddResultTypeChunk(Result.getAllocator().CopyString(
FT->getReturnType().getAsString(Policy))); FT->getReturnType().getAsString(Policy)));
Result.AddChunk(CodeCompletionString::CK_LeftParen); Result.AddChunk(Braced ? CodeCompletionString::CK_LeftBrace
: CodeCompletionString::CK_LeftParen);
Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");
Result.AddChunk(CodeCompletionString::CK_RightParen); Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace
: CodeCompletionString::CK_RightParen);
return Result.TakeString(); return Result.TakeString();
} }
@ -3879,10 +3882,12 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Proto->getReturnType().getAsString(Policy))); Proto->getReturnType().getAsString(Policy)));
} }
Result.AddChunk(CodeCompletionString::CK_LeftParen); Result.AddChunk(Braced ? CodeCompletionString::CK_LeftBrace
: CodeCompletionString::CK_LeftParen);
AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result, AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result,
CurrentArg); CurrentArg);
Result.AddChunk(CodeCompletionString::CK_RightParen); Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace
: CodeCompletionString::CK_RightParen);
return Result.TakeString(); return Result.TakeString();
} }
@ -5940,12 +5945,14 @@ static QualType getParamType(Sema &SemaRef,
static QualType static QualType
ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates, ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates,
unsigned CurrentArg, SourceLocation OpenParLoc) { unsigned CurrentArg, SourceLocation OpenParLoc,
bool Braced) {
if (Candidates.empty()) if (Candidates.empty())
return QualType(); return QualType();
if (SemaRef.getPreprocessor().isCodeCompletionReached()) if (SemaRef.getPreprocessor().isCodeCompletionReached())
SemaRef.CodeCompleter->ProcessOverloadCandidates( SemaRef.CodeCompleter->ProcessOverloadCandidates(
SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc); SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc,
Braced);
return getParamType(SemaRef, Candidates, CurrentArg); return getParamType(SemaRef, Candidates, CurrentArg);
} }
@ -6047,15 +6054,16 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
} }
} }
mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size());
QualType ParamType = QualType ParamType = ProduceSignatureHelp(*this, Results, Args.size(),
ProduceSignatureHelp(*this, Results, Args.size(), OpenParLoc); OpenParLoc, /*Braced=*/false);
return !CandidateSet.empty() ? ParamType : QualType(); return !CandidateSet.empty() ? ParamType : QualType();
} }
QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type, QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
SourceLocation Loc, SourceLocation Loc,
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
SourceLocation OpenParLoc) { SourceLocation OpenParLoc,
bool Braced) {
if (!CodeCompleter) if (!CodeCompleter)
return QualType(); return QualType();
@ -6064,6 +6072,10 @@ QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr; isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr;
if (!RD) if (!RD)
return Type; return Type;
// FIXME: we don't support signature help for aggregate initialization, so
// don't offer a confusing partial list (e.g. the copy constructor).
if (Braced && RD->isAggregate())
return Type;
// FIXME: Provide support for member initializers. // FIXME: Provide support for member initializers.
// FIXME: Provide support for variadic template constructors. // FIXME: Provide support for variadic template constructors.
@ -6072,12 +6084,20 @@ QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
for (NamedDecl *C : LookupConstructors(RD)) { for (NamedDecl *C : LookupConstructors(RD)) {
if (auto *FD = dyn_cast<FunctionDecl>(C)) { if (auto *FD = dyn_cast<FunctionDecl>(C)) {
// FIXME: we can't yet provide correct signature help for initializer
// list constructors, so skip them entirely.
if (Braced && LangOpts.CPlusPlus && isInitListConstructor(FD))
continue;
AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args, AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
CandidateSet, CandidateSet,
/*SuppressUserConversions=*/false, /*SuppressUserConversions=*/false,
/*PartialOverloading=*/true, /*PartialOverloading=*/true,
/*AllowExplicit*/ true); /*AllowExplicit*/ true);
} else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) { } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
if (Braced && LangOpts.CPlusPlus &&
isInitListConstructor(FTD->getTemplatedDecl()))
continue;
AddTemplateOverloadCandidate( AddTemplateOverloadCandidate(
FTD, DeclAccessPair::make(FTD, C->getAccess()), FTD, DeclAccessPair::make(FTD, C->getAccess()),
/*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet, /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
@ -6088,12 +6108,13 @@ QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
SmallVector<ResultCandidate, 8> Results; SmallVector<ResultCandidate, 8> Results;
mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size()); mergeCandidatesWithResults(*this, Results, CandidateSet, Loc, Args.size());
return ProduceSignatureHelp(*this, Results, Args.size(), OpenParLoc); return ProduceSignatureHelp(*this, Results, Args.size(), OpenParLoc, Braced);
} }
QualType Sema::ProduceCtorInitMemberSignatureHelp( QualType Sema::ProduceCtorInitMemberSignatureHelp(
Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy,
ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { ArrayRef<Expr *> ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc,
bool Braced) {
if (!CodeCompleter) if (!CodeCompleter)
return QualType(); return QualType();
@ -6106,7 +6127,7 @@ QualType Sema::ProduceCtorInitMemberSignatureHelp(
Constructor->getParent(), SS, TemplateTypeTy, II)) Constructor->getParent(), SS, TemplateTypeTy, II))
return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(),
MemberDecl->getLocation(), ArgExprs, MemberDecl->getLocation(), ArgExprs,
OpenParLoc); OpenParLoc, Braced);
return QualType(); return QualType();
} }
@ -6159,7 +6180,8 @@ QualType Sema::ProduceTemplateArgumentSignatureHelp(
if (const auto *TD = llvm::dyn_cast<TemplateDecl>(ND)) if (const auto *TD = llvm::dyn_cast<TemplateDecl>(ND))
Consider(TD); Consider(TD);
} }
return ProduceSignatureHelp(*this, Results, Args.size(), LAngleLoc); return ProduceSignatureHelp(*this, Results, Args.size(), LAngleLoc,
/*Braced=*/false);
} }
static QualType getDesignatedType(QualType BaseType, const Designation &Desig) { static QualType getDesignatedType(QualType BaseType, const Designation &Desig) {

View File

@ -15,3 +15,40 @@ void foo() {
// CHECK-CC2: OVERLOAD: Foo(<#const Foo<int *> &#>) // CHECK-CC2: OVERLOAD: Foo(<#const Foo<int *> &#>)
// CHECK-CC2: OVERLOAD: Foo(<#Foo<int *> &&#> // CHECK-CC2: OVERLOAD: Foo(<#Foo<int *> &&#>
} }
namespace std {
template <typename> struct initializer_list {};
} // namespace std
struct Bar {
// CHECK-BRACED: OVERLOAD: Bar{<#int#>}
Bar(int);
// CHECK-BRACED: OVERLOAD: Bar{<#double#>, double}
Bar(double, double);
// FIXME: no support for init-list constructors yet.
// CHECK-BRACED-NOT: OVERLOAD: {{.*}}char
Bar(std::initializer_list<char> C);
// CHECK-BRACED: OVERLOAD: Bar{<#const Bar &#>}
// CHECK-BRACED: OVERLOAD: Bar{<#T *Pointer#>}
template <typename T> Bar(T *Pointer);
};
auto b1 = Bar{};
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:36:15 %s | FileCheck -check-prefix=CHECK-BRACED %s
Bar b2{};
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:38:8 %s | FileCheck -check-prefix=CHECK-BRACED %s
static int consumeBar(Bar) { return 0; }
int b3 = consumeBar({});
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:41:22 %s | FileCheck -check-prefix=CHECK-BRACED %s
struct Aggregate {
// FIXME: no support for aggregates yet.
// CHECK-AGGREGATE-NOT: OVERLOAD: Aggregate{<#const Aggregate &#>}
// CHECK-AGGREGATE-NOT: OVERLOAD: {{.*}}first
int first;
int second;
};
Aggregate a{};
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:52:13 %s | FileCheck -check-prefix=CHECK-AGGREGATE %s

View File

@ -656,14 +656,15 @@ namespace {
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) override { SourceLocation OpenParLoc,
bool Braced) override {
StoredResults.reserve(StoredResults.size() + NumCandidates); StoredResults.reserve(StoredResults.size() + NumCandidates);
for (unsigned I = 0; I != NumCandidates; ++I) { for (unsigned I = 0; I != NumCandidates; ++I) {
CodeCompletionString *StoredCompletion CodeCompletionString *StoredCompletion =
= Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(), Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(),
getCodeCompletionTUInfo(), getCodeCompletionTUInfo(),
includeBriefComments()); includeBriefComments(), Braced);
CXCompletionResult R; CXCompletionResult R;
R.CursorKind = CXCursor_OverloadCandidate; R.CursorKind = CXCursor_OverloadCandidate;
R.CompletionString = StoredCompletion; R.CompletionString = StoredCompletion;

View File

@ -995,7 +995,8 @@ public:
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates, OverloadCandidate *Candidates,
unsigned NumCandidates, unsigned NumCandidates,
SourceLocation OpenParLoc) override { SourceLocation OpenParLoc,
bool Braced) override {
// At the moment we don't filter out any overloaded candidates. // At the moment we don't filter out any overloaded candidates.
} }