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 +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits