[clang-tools-extra] 128ce70 - [CodeCompletion] Avoid spurious signature help for init-list args
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 16 04:46:48 PDT 2021
Author: Sam McCall
Date: 2021-03-16T12:46:40+01:00
New Revision: 128ce70eef9948b81e725fd0e2ed46a7c004a118
URL: https://github.com/llvm/llvm-project/commit/128ce70eef9948b81e725fd0e2ed46a7c004a118
DIFF: https://github.com/llvm/llvm-project/commit/128ce70eef9948b81e725fd0e2ed46a7c004a118.diff
LOG: [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.
eb4ab3358cd4dc834a761191b5531b38114f7b13 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
Added:
Modified:
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
clang/include/clang/Sema/Sema.h
clang/lib/Lex/PPDirectives.cpp
clang/lib/Lex/Preprocessor.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Parse/ParseInit.cpp
clang/lib/Parse/ParseObjc.cpp
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Parse/ParseStmt.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaCodeComplete.cpp
clang/test/CodeCompletion/desig-init.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 0ff1e83b7613..a57ae49f9159 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -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);
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9e3eb4f07472..79e2471fdabe 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -306,6 +306,9 @@ class PreferredTypeBuilder {
/// 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 @@ class PreferredTypeBuilder {
/// 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 @@ class Sema final {
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,
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index c854d3e9c02b..f04d896247c9 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -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)
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 177786d90390..e39b78d5ffec 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -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
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 9edf4d3d614a..a044fbc3039c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -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.
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index dd1cccf72668..0e9bc42bfcb8 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -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);
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index c417985cbe34..c2b47f6375b8 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -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)) {
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 9292541d7ede..8052795c0c1e 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -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;
}
diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp
index 97bd7d8fc51a..9d9c03d28a97 100644
--- a/clang/lib/Parse/ParseInit.cpp
+++ b/clang/lib/Parse/ParseInit.cpp
@@ -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)) {
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 223b36d7a0e6..9e145f57d61f 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -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
diff erent
// 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();
}
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 3de01be0db87..54c05aea0e33 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -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;
}
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index f59271c45848..54655863e3ab 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -178,8 +178,8 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
}
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();
}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index fb182883b88a..b178b56e967c 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -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;
}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 18605b321c70..dc7a67e92827 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -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);
}
diff --git a/clang/test/CodeCompletion/desig-init.cpp b/clang/test/CodeCompletion/desig-init.cpp
index 8a66f4554217..999f368ba563 100644
--- a/clang/test/CodeCompletion/desig-init.cpp
+++ b/clang/test/CodeCompletion/desig-init.cpp
@@ -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
+}
+
More information about the cfe-commits
mailing list