[CodeCompletion] Avoid spurious signature help for init-list args

Somewhat surprisingly, signature help is emitted as a side-effect of
computing the expected type of a function argument.
The reason is that both actions require enumerating the possible
function signatures and running partial overload resolution, and doing
this twice would be wasteful and complicated.

Change #1: document this, it's subtle :-)

However, sometimes we need to compute the expected type without having
reached the code completion cursor yet - in particular to allow
completion of designators.
eb4ab3358c did this but introduced a
regression - it emits signature help in the wrong location as a side-effect.

Change #2: only emit signature help if the code completion cursor was reached.

Currently there is PP.isCodeCompletionReached(), but we can't use it
because it's set *after* running code completion.
It'd be nice to set this implicitly when the completion token is lexed,
but ConsumeCodeCompletionToken() makes this complicated.

Change #3: call cutOffParsing() *first* when seeing a completion token.

After this, the fact that the Sema::Produce*SignatureHelp() functions
are even more confusing, as they only sometimes do that.
I don't want to rename them in this patch as it's another large
mechanical change, but we should soon.

Change #4: prepare to rename ProduceSignatureHelp() to GuessArgumentType() etc.

Differential Revision: https://reviews.llvm.org/D98488
This commit is contained in:
Sam McCall 2021-03-12 12:00:54 +01:00
parent 5ac3b37599
commit 128ce70eef
15 changed files with 144 additions and 84 deletions

View File

@ -1253,6 +1253,19 @@ TEST(SignatureHelpTest, Overloads) {
EXPECT_EQ(0, Results.activeParameter);
}
TEST(SignatureHelpTest, OverloadInitListRegression) {
auto Results = signatures(R"cpp(
struct A {int x;};
struct B {B(A);};
void f();
int main() {
B b({1});
f(^);
}
)cpp");
EXPECT_THAT(Results.signatures, UnorderedElementsAre(Sig("f() -> void")));
}
TEST(SignatureHelpTest, DefaultArgs) {
auto Results = signatures(R"cpp(
void bar(int x, int y = 0);

View File

@ -306,6 +306,9 @@ public:
/// Clients should be very careful when using this funciton, as it stores a
/// function_ref, clients should make sure all calls to get() with the same
/// location happen while function_ref is alive.
///
/// The callback should also emit signature help as a side-effect, but only
/// if the completion point has been reached.
void enterFunctionArgument(SourceLocation Tok,
llvm::function_ref<QualType()> ComputeType);
@ -318,6 +321,12 @@ public:
/// Handles all type casts, including C-style cast, C++ casts, etc.
void enterTypeCast(SourceLocation Tok, QualType CastType);
/// Get the expected type associated with this location, if any.
///
/// If the location is a function argument, determining the expected type
/// involves considering all function overloads and the arguments so far.
/// In this case, signature help for these function overloads will be reported
/// as a side-effect (only if the completion point has been reached).
QualType get(SourceLocation Tok) const {
if (!Enabled || Tok != ExpectedLoc)
return QualType();
@ -12216,8 +12225,14 @@ public:
const VirtSpecifiers *VS = nullptr);
void CodeCompleteBracketDeclarator(Scope *S);
void CodeCompleteCase(Scope *S);
/// Reports signatures for a call to CodeCompleteConsumer and returns the
/// preferred type for the current argument. Returned type can be null.
/// Determines the preferred type of the current function argument, by
/// examining the signatures of all possible overloads.
/// Returns null if unknown or ambiguous, or if code completion is off.
///
/// If the code completion point has been reached, also reports the function
/// signatures that were considered.
///
/// FIXME: rename to GuessCallArgumentType to reduce confusion.
QualType ProduceCallSignatureHelp(Scope *S, Expr *Fn, ArrayRef<Expr *> Args,
SourceLocation OpenParLoc);
QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type,

View File

@ -441,9 +441,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
CurLexer->Lex(Tok);
if (Tok.is(tok::code_completion)) {
setCodeCompletionReached();
if (CodeComplete)
CodeComplete->CodeCompleteInConditionalExclusion();
setCodeCompletionReached();
continue;
}
@ -966,10 +966,10 @@ void Preprocessor::HandleDirective(Token &Result) {
case tok::eod:
return; // null directive.
case tok::code_completion:
setCodeCompletionReached();
if (CodeComplete)
CodeComplete->CodeCompleteDirective(
CurPPLexer->getConditionalStackDepth() > 0);
setCodeCompletionReached();
return;
case tok::numeric_constant: // # 7 GNU line marker directive.
if (getLangOpts().AsmPreprocessor)

View File

@ -442,15 +442,15 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
void Preprocessor::CodeCompleteIncludedFile(llvm::StringRef Dir,
bool IsAngled) {
setCodeCompletionReached();
if (CodeComplete)
CodeComplete->CodeCompleteIncludedFile(Dir, IsAngled);
setCodeCompletionReached();
}
void Preprocessor::CodeCompleteNaturalLanguage() {
setCodeCompletionReached();
if (CodeComplete)
CodeComplete->CodeCompleteNaturalLanguage();
setCodeCompletionReached();
}
/// getSpelling - This method is used to get the spelling of a token into a

View File

@ -1970,8 +1970,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Check to see if we have a function *definition* which must have a body.
if (D.isFunctionDeclarator()) {
if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) {
Actions.CodeCompleteAfterFunctionEquals(D);
cutOffParsing();
Actions.CodeCompleteAfterFunctionEquals(D);
return nullptr;
}
// Look at the next token to make sure that this isn't a function
@ -2310,9 +2310,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
InitializerScopeRAII InitScope(*this, D, ThisDecl);
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteInitializer(getCurScope(), ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
cutOffParsing();
return nullptr;
}
@ -3090,10 +3090,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
= DSContext == DeclSpecContext::DSC_top_level ||
(DSContext == DeclSpecContext::DSC_class && DS.isFriendSpecified());
cutOffParsing();
Actions.CodeCompleteDeclSpec(getCurScope(), DS,
AllowNonIdentifiers,
AllowNestedNameSpecifiers);
return cutOffParsing();
return;
}
if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
@ -3106,8 +3107,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
else if (CurParsedObjCImpl)
CCC = Sema::PCC_ObjCImplementation;
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
return cutOffParsing();
return;
}
case tok::coloncolon: // ::foo::bar
@ -4362,8 +4364,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Parse the tag portion of this.
if (Tok.is(tok::code_completion)) {
// Code completion for an enum name.
cutOffParsing();
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
return cutOffParsing();
return;
}
// If attributes exist after tag, parse them.
@ -5457,11 +5460,12 @@ void Parser::ParseTypeQualifierListOpt(
switch (Tok.getKind()) {
case tok::code_completion:
cutOffParsing();
if (CodeCompletionHandler)
(*CodeCompletionHandler)();
else
Actions.CodeCompleteTypeQualifiers(DS);
return cutOffParsing();
return;
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
@ -6998,8 +7002,9 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
std::move(attrs), T.getCloseLocation());
return;
} else if (Tok.getKind() == tok::code_completion) {
cutOffParsing();
Actions.CodeCompleteBracketDeclarator(getCurScope());
return cutOffParsing();
return;
}
// If valid, this location is the position where we read the 'static' keyword.

View File

@ -63,8 +63,8 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceDecl(getCurScope());
cutOffParsing();
Actions.CodeCompleteNamespaceDecl(getCurScope());
return nullptr;
}
@ -283,8 +283,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
ConsumeToken(); // eat the '='.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
cutOffParsing();
Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
return nullptr;
}
@ -471,8 +471,8 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context,
SourceLocation UsingLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsing(getCurScope());
cutOffParsing();
Actions.CodeCompleteUsing(getCurScope());
return nullptr;
}
@ -525,8 +525,8 @@ Decl *Parser::ParseUsingDirective(DeclaratorContext Context,
SourceLocation NamespcLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsingDirective(getCurScope());
cutOffParsing();
Actions.CodeCompleteUsingDirective(getCurScope());
return nullptr;
}
@ -1433,8 +1433,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::code_completion)) {
// Code completion for a struct, class, or union name.
cutOffParsing();
Actions.CodeCompleteTag(getCurScope(), TagType);
return cutOffParsing();
return;
}
// C++03 [temp.explicit] 14.7.2/8:
@ -2749,8 +2750,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
else if (KW.is(tok::kw_delete))
DefinitionKind = FunctionDefinitionKind::Deleted;
else if (KW.is(tok::code_completion)) {
Actions.CodeCompleteAfterFunctionEquals(DeclaratorInfo);
cutOffParsing();
Actions.CodeCompleteAfterFunctionEquals(DeclaratorInfo);
return nullptr;
}
}
@ -3498,9 +3499,10 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
do {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
MemInitializers);
return cutOffParsing();
return;
}
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);

View File

@ -159,9 +159,9 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
/// Parse an expr that doesn't include (top-level) commas.
ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
cutOffParsing();
return ExprError();
}
@ -1156,9 +1156,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
ConsumeToken();
if (Tok.is(tok::code_completion) && &II != Ident_super) {
cutOffParsing();
Actions.CodeCompleteObjCClassPropertyRefExpr(
getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc);
cutOffParsing();
return ExprError();
}
// Allow either an identifier or the keyword 'class' (in C++).
@ -1724,9 +1724,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
Res = ParseBlockLiteralExpression();
break;
case tok::code_completion: {
cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
cutOffParsing();
return ExprError();
}
case tok::l_square:
@ -1856,9 +1856,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (InMessageExpression)
return LHS;
cutOffParsing();
Actions.CodeCompletePostfixExpression(
getCurScope(), LHS, PreferredType.get(Tok.getLocation()));
cutOffParsing();
return ExprError();
case tok::identifier:
@ -2140,12 +2140,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
CorrectedBase = Base;
// Code completion for a member access expression.
cutOffParsing();
Actions.CodeCompleteMemberReferenceExpr(
getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow,
Base && ExprStatementTokLoc == Base->getBeginLoc(),
PreferredType.get(Tok.getLocation()));
cutOffParsing();
return ExprError();
}
@ -2778,10 +2778,10 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
CastTy = nullptr;
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteExpression(
getCurScope(), PreferredType.get(Tok.getLocation()),
/*IsParenthesized=*/ExprType >= CompoundLiteral);
cutOffParsing();
return ExprError();
}
@ -3412,8 +3412,9 @@ Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
/// \endverbatim
void Parser::ParseBlockId(SourceLocation CaretLoc) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
return cutOffParsing();
return;
}
// Parse the specifier-qualifier-list piece.
@ -3598,8 +3599,8 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
} else {
// Parse the platform name.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteAvailabilityPlatformName();
cutOffParsing();
Actions.CodeCompleteAvailabilityPlatformName();
return None;
}
if (Tok.isNot(tok::identifier)) {

View File

@ -235,6 +235,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
while (true) {
if (HasScopeSpecifier) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
// Code completion for a nested-name-specifier, where the code
// completion token follows the '::'.
Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext,
@ -245,7 +246,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
// token will cause assertion in
// Preprocessor::AnnotatePreviousCachedTokens.
SS.setEndLoc(Tok.getLocation());
cutOffParsing();
return true;
}
@ -877,9 +877,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// expression parser perform the completion.
if (Tok.is(tok::code_completion) &&
!(getLangOpts().ObjC && Tentative)) {
cutOffParsing();
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/false);
cutOffParsing();
break;
}
@ -891,6 +891,7 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
}
if (Tok.is(tok::code_completion)) {
cutOffParsing();
// If we're in Objective-C++ and we have a bare '[', then this is more
// likely to be a message receiver.
if (getLangOpts().ObjC && Tentative && First)
@ -898,7 +899,6 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
else
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/false);
cutOffParsing();
break;
}
@ -943,9 +943,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
ConsumeToken();
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/true);
cutOffParsing();
break;
}
}
@ -1996,8 +1996,8 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
PreferredType.enterCondition(Actions, Tok.getLocation());
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition);
return Sema::ConditionError();
}
@ -2608,10 +2608,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
}
case tok::code_completion: {
// Don't try to parse any further.
cutOffParsing();
// Code completion for the operator name.
Actions.CodeCompleteOperatorName(getCurScope());
cutOffParsing();
// Don't try to parse any further.
return true;
}

View File

@ -200,9 +200,9 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator(
SourceLocation DotLoc = ConsumeToken();
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteDesignator(DesignatorCompletion.PreferredBaseType,
DesignatorCompletion.InitExprs, Desig);
cutOffParsing();
return ExprError();
}
if (Tok.isNot(tok::identifier)) {

View File

@ -50,8 +50,8 @@ Parser::ParseObjCAtDirectives(ParsedAttributesWithRange &Attrs) {
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCAtDirective(getCurScope());
return nullptr;
}
@ -219,8 +219,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Code completion after '@interface'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
return nullptr;
}
@ -253,8 +253,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
SourceLocation categoryLoc;
IdentifierInfo *categoryId = nullptr;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
return nullptr;
}
@ -308,8 +308,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Code completion of superclass names.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
cutOffParsing();
Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
return nullptr;
}
@ -472,8 +472,8 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
if (Tok.is(tok::code_completion)) {
// FIXME: If these aren't protocol references, we'll need different
// completions.
Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
cutOffParsing();
Actions.CodeCompleteObjCProtocolReferences(protocolIdents);
// FIXME: Better recovery here?.
return nullptr;
@ -635,10 +635,11 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// Code completion within an Objective-C interface.
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
CurParsedObjCImpl? Sema::PCC_ObjCImplementation
: Sema::PCC_ObjCInterface);
return cutOffParsing();
return;
}
// If we don't have an @ directive, parse it as a function definition.
@ -668,8 +669,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// Otherwise, we have an @ directive, eat the @.
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCAtDirective(getCurScope());
return cutOffParsing();
return;
}
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
@ -778,8 +780,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// We break out of the big loop in two cases: when we see @end or when we see
// EOF. In the former case, eat the @end. In the later case, emit an error.
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCAtDirective(getCurScope());
return cutOffParsing();
return;
} else if (Tok.isObjCAtKeyword(tok::objc_end)) {
ConsumeToken(); // the "end" identifier
} else {
@ -847,8 +850,9 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
while (1) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCPropertyFlags(getCurScope(), DS);
return cutOffParsing();
return;
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
@ -893,11 +897,12 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
}
if (Tok.is(tok::code_completion)) {
cutOffParsing();
if (IsSetter)
Actions.CodeCompleteObjCPropertySetter(getCurScope());
else
Actions.CodeCompleteObjCPropertyGetter(getCurScope());
return cutOffParsing();
return;
}
SourceLocation SelLoc;
@ -1146,9 +1151,10 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
while (1) {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCPassingType(
getCurScope(), DS, Context == DeclaratorContext::ObjCParameter);
return cutOffParsing();
return;
}
if (Tok.isNot(tok::identifier))
@ -1335,9 +1341,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
/*ReturnType=*/nullptr);
cutOffParsing();
return nullptr;
}
@ -1354,9 +1360,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
methodAttrs);
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
ReturnType);
cutOffParsing();
return nullptr;
}
@ -1416,12 +1422,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
cutOffParsing();
KeyIdents.push_back(SelIdent);
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/true,
ReturnType, KeyIdents);
cutOffParsing();
return nullptr;
}
@ -1441,11 +1447,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCMethodDeclSelector(getCurScope(),
mType == tok::minus,
/*AtParameterName=*/false,
ReturnType, KeyIdents);
cutOffParsing();
return nullptr;
}
@ -1527,8 +1533,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
while (1) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
cutOffParsing();
Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents);
return true;
}
@ -1626,12 +1632,12 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers(
}
QualType BaseT = Actions.GetTypeFromParser(baseType);
cutOffParsing();
if (!BaseT.isNull() && BaseT->acceptsObjCTypeParams()) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
} else {
Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs);
}
cutOffParsing();
return;
}
@ -1920,8 +1926,9 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
// Set the default visibility to private.
if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteObjCAtVisibility(getCurScope());
return cutOffParsing();
return;
}
switch (Tok.getObjCKeywordID()) {
@ -1950,9 +1957,10 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
}
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
Sema::PCC_ObjCInstanceVariableList);
return cutOffParsing();
return;
}
// This needs to duplicate a small amount of code from
@ -2017,8 +2025,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
ConsumeToken(); // the "protocol" identifier
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
return nullptr;
}
@ -2101,8 +2109,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
// Code completion after '@implementation'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
return nullptr;
}
@ -2139,8 +2147,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
IdentifierInfo *categoryId = nullptr;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
return nullptr;
}
@ -2309,8 +2317,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
return nullptr;
}
@ -2327,8 +2335,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
if (TryConsumeToken(tok::equal)) {
// property '=' ivar-name
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
cutOffParsing();
Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
return nullptr;
}
@ -2387,8 +2395,8 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
while (true) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
return nullptr;
}
@ -2724,8 +2732,8 @@ Decl *Parser::ParseObjCMethodDefinition() {
StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
ParsedStmtContext StmtCtx) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtStatement(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCAtStatement(getCurScope());
return StmtError();
}
@ -2765,8 +2773,8 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc,
ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
case tok::code_completion:
Actions.CodeCompleteObjCAtExpression(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCAtExpression(getCurScope());
return ExprError();
case tok::minus:
@ -3012,8 +3020,8 @@ ExprResult Parser::ParseObjCMessageExpression() {
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMessageReceiver(getCurScope());
cutOffParsing();
Actions.CodeCompleteObjCMessageReceiver(getCurScope());
return ExprError();
}
@ -3149,6 +3157,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
InMessageExpressionRAIIObject InMessage(*this, true);
if (Tok.is(tok::code_completion)) {
cutOffParsing();
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
false);
@ -3158,7 +3167,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
None, false);
cutOffParsing();
return ExprError();
}
@ -3187,6 +3195,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
/// Parse the expression after ':'
if (Tok.is(tok::code_completion)) {
cutOffParsing();
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
KeyIdents,
@ -3200,7 +3209,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents,
/*AtArgumentExpression=*/true);
cutOffParsing();
return ExprError();
}
@ -3225,6 +3233,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Code completion after each argument.
if (Tok.is(tok::code_completion)) {
cutOffParsing();
if (SuperLoc.isValid())
Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
KeyIdents,
@ -3237,7 +3246,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
KeyIdents,
/*AtArgumentExpression=*/false);
cutOffParsing();
return ExprError();
}
@ -3577,8 +3585,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
ConsumeParen();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
return ExprError();
}
@ -3603,8 +3611,8 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
break;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
return ExprError();
}

View File

@ -441,9 +441,9 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
ConsumeToken();
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm);
Actions.FinalizeDeclaration(OmpPrivParm);
cutOffParsing();
return;
}

View File

@ -178,8 +178,8 @@ Retry:
}
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
return StmtError();
case tok::identifier: {
@ -726,8 +726,8 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
ColonLoc = SourceLocation();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(getCurScope());
cutOffParsing();
Actions.CodeCompleteCase(getCurScope());
return StmtError();
}
@ -1472,8 +1472,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// Pop the 'else' scope if needed.
InnerScope.Exit();
} else if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen);
cutOffParsing();
Actions.CodeCompleteAfterIf(getCurScope(), IsBracedThen);
return StmtError();
} else if (InnerStatementTrailingElseLoc.isValid()) {
Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
@ -1827,10 +1827,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
FullExprArg ThirdPart(Actions);
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
C99orCXXorObjC? Sema::PCC_ForInit
: Sema::PCC_Expression);
cutOffParsing();
return StmtError();
}
@ -1898,8 +1898,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
cutOffParsing();
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
return StmtError();
}
Collection = ParseExpression();
@ -1934,8 +1934,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ConsumeToken(); // consume 'in'
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
cutOffParsing();
Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
return StmtError();
}
Collection = ParseExpression();
@ -2188,9 +2188,9 @@ StmtResult Parser::ParseReturnStatement() {
PreferredType.enterReturn(Actions, Tok.getLocation());
// FIXME: Code completion for co_return.
if (Tok.is(tok::code_completion) && !IsCoreturn) {
cutOffParsing();
Actions.CodeCompleteExpression(getCurScope(),
PreferredType.get(Tok.getLocation()));
cutOffParsing();
return StmtError();
}

View File

@ -870,6 +870,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SingleDecl = ParseObjCMethodDefinition();
break;
case tok::code_completion:
cutOffParsing();
if (CurParsedObjCImpl) {
// Code-complete Objective-C methods even without leading '-'/'+' prefix.
Actions.CodeCompleteObjCMethodDecl(getCurScope(),
@ -879,7 +880,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Actions.CodeCompleteOrdinaryName(
getCurScope(),
CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace);
cutOffParsing();
return nullptr;
case tok::kw_import:
SingleDecl = ParseModuleImport(SourceLocation());
@ -2114,21 +2114,21 @@ SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
for (Scope *S = getCurScope(); S; S = S->getParent()) {
if (S->getFlags() & Scope::FnScope) {
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(),
Sema::PCC_RecoveryInFunction);
cutOffParsing();
return PrevTokLocation;
}
if (S->getFlags() & Scope::ClassScope) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class);
return PrevTokLocation;
}
}
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
cutOffParsing();
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace);
return PrevTokLocation;
}
@ -2452,8 +2452,8 @@ bool Parser::ParseModuleName(
while (true) {
if (!Tok.is(tok::identifier)) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteModuleImport(UseLoc, Path);
cutOffParsing();
Actions.CodeCompleteModuleImport(UseLoc, Path);
return true;
}

View File

@ -5711,8 +5711,9 @@ ProduceSignatureHelp(Sema &SemaRef, Scope *S,
unsigned CurrentArg, SourceLocation OpenParLoc) {
if (Candidates.empty())
return QualType();
SemaRef.CodeCompleter->ProcessOverloadCandidates(
SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc);
if (SemaRef.getPreprocessor().isCodeCompletionReached())
SemaRef.CodeCompleter->ProcessOverloadCandidates(
SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc);
return getParamType(SemaRef, Candidates, CurrentArg);
}

View File

@ -62,3 +62,18 @@ void aux() {
Test<T> X{.x = T(2)};
// RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:62:14 %s -o - -std=c++2a | FileCheck -check-prefix=CHECK-CC3 %s
}
namespace signature_regression {
// Verify that an old bug is gone: passing an init-list as a constructor arg
// would emit overloads as a side-effect.
struct S{int x;};
int wrongFunction(S);
int rightFunction();
int dummy = wrongFunction({1});
int x = rightFunction();
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:73:25 %s -o - -std=c++2a | FileCheck -check-prefix=CHECK-SIGNATURE-REGRESSION %s
// CHECK-SIGNATURE-REGRESSION-NOT: OVERLOAD: [#int#]wrongFunction
// CHECK-SIGNATURE-REGRESSION: OVERLOAD: [#int#]rightFunction
// CHECK-SIGNATURE-REGRESSION-NOT: OVERLOAD: [#int#]wrongFunction
}