diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1253,6 +1253,19 @@ 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 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -306,6 +306,9 @@ /// 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 ComputeType); @@ -318,6 +321,12 @@ /// 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 @@ 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 Args, SourceLocation OpenParLoc); QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type, diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -441,9 +441,9 @@ CurLexer->Lex(Tok); if (Tok.is(tok::code_completion)) { + setCodeCompletionReached(); if (CodeComplete) CodeComplete->CodeCompleteInConditionalExclusion(); - setCodeCompletionReached(); continue; } @@ -966,10 +966,10 @@ 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 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -442,15 +442,15 @@ 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 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1970,8 +1970,8 @@ // 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 @@ 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 @@ = 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 @@ else if (CurParsedObjCImpl) CCC = Sema::PCC_ObjCImplementation; + cutOffParsing(); Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); - return cutOffParsing(); + return; } case tok::coloncolon: // ::foo::bar @@ -4362,8 +4364,9 @@ // 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 @@ 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 @@ 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 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -63,8 +63,8 @@ ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteNamespaceDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteNamespaceDecl(getCurScope()); return nullptr; } @@ -283,8 +283,8 @@ ConsumeToken(); // eat the '='. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteNamespaceAliasDecl(getCurScope()); return nullptr; } @@ -471,8 +471,8 @@ SourceLocation UsingLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteUsing(getCurScope()); cutOffParsing(); + Actions.CodeCompleteUsing(getCurScope()); return nullptr; } @@ -525,8 +525,8 @@ SourceLocation NamespcLoc = ConsumeToken(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteUsingDirective(getCurScope()); cutOffParsing(); + Actions.CodeCompleteUsingDirective(getCurScope()); return nullptr; } @@ -1433,8 +1433,9 @@ 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 @@ 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 @@ 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 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -159,9 +159,9 @@ /// 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 @@ 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 @@ 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 @@ if (InMessageExpression) return LHS; + cutOffParsing(); Actions.CodeCompletePostfixExpression( getCurScope(), LHS, PreferredType.get(Tok.getLocation())); - cutOffParsing(); return ExprError(); case tok::identifier: @@ -2140,12 +2140,12 @@ 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 @@ 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 @@ /// \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 @@ } 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 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -235,6 +235,7 @@ 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 @@ // token will cause assertion in // Preprocessor::AnnotatePreviousCachedTokens. SS.setEndLoc(Tok.getLocation()); - cutOffParsing(); return true; } @@ -877,9 +877,9 @@ // 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 @@ } 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 @@ else Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); - cutOffParsing(); break; } @@ -943,9 +943,9 @@ ConsumeToken(); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/true); - cutOffParsing(); break; } } @@ -1996,8 +1996,8 @@ 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 @@ } 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 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -200,9 +200,9 @@ 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 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -50,8 +50,8 @@ SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCAtDirective(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCAtDirective(getCurScope()); return nullptr; } @@ -219,8 +219,8 @@ // Code completion after '@interface'. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCInterfaceDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCInterfaceDecl(getCurScope()); return nullptr; } @@ -253,8 +253,8 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ // 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ methodAttrs); if (Tok.is(tok::code_completion)) { + cutOffParsing(); Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, ReturnType); - cutOffParsing(); return nullptr; } @@ -1416,12 +1422,12 @@ // 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 @@ // 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 @@ while (1) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents); cutOffParsing(); + Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents); return true; } @@ -1626,12 +1632,12 @@ } 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 @@ // 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 @@ } 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 @@ ConsumeToken(); // the "protocol" identifier if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCProtocolDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCProtocolDecl(getCurScope()); return nullptr; } @@ -2101,8 +2109,8 @@ // Code completion after '@implementation'. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCImplementationDecl(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCImplementationDecl(getCurScope()); return nullptr; } @@ -2139,8 +2147,8 @@ 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 @@ while (true) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); return nullptr; } @@ -2327,8 +2335,8 @@ 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 @@ while (true) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCPropertyDefinition(getCurScope()); return nullptr; } @@ -2724,8 +2732,8 @@ 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 @@ 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 @@ SourceLocation LBracLoc = ConsumeBracket(); // consume '[' if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCMessageReceiver(getCurScope()); cutOffParsing(); + Actions.CodeCompleteObjCMessageReceiver(getCurScope()); return ExprError(); } @@ -3149,6 +3157,7 @@ InMessageExpressionRAIIObject InMessage(*this, true); if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None, false); @@ -3158,7 +3167,6 @@ else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, None, false); - cutOffParsing(); return ExprError(); } @@ -3187,6 +3195,7 @@ /// Parse the expression after ':' if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents, @@ -3200,7 +3209,6 @@ KeyIdents, /*AtArgumentExpression=*/true); - cutOffParsing(); return ExprError(); } @@ -3225,6 +3233,7 @@ // Code completion after each argument. if (Tok.is(tok::code_completion)) { + cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, KeyIdents, @@ -3237,7 +3246,6 @@ Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, KeyIdents, /*AtArgumentExpression=*/false); - cutOffParsing(); return ExprError(); } @@ -3577,8 +3585,8 @@ ConsumeParen(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); cutOffParsing(); + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents); return ExprError(); } @@ -3603,8 +3611,8 @@ 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 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -441,9 +441,9 @@ 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 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -178,8 +178,8 @@ } 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 @@ ColonLoc = SourceLocation(); if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteCase(getCurScope()); cutOffParsing(); + Actions.CodeCompleteCase(getCurScope()); return StmtError(); } @@ -1472,8 +1472,8 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -870,6 +870,7 @@ 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 @@ Actions.CodeCompleteOrdinaryName( getCurScope(), CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); - cutOffParsing(); return nullptr; case tok::kw_import: SingleDecl = ParseModuleImport(SourceLocation()); @@ -2114,21 +2114,21 @@ 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 @@ 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 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5711,8 +5711,9 @@ 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 --- a/clang/test/CodeCompletion/desig-init.cpp +++ b/clang/test/CodeCompletion/desig-init.cpp @@ -62,3 +62,18 @@ Test 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 +} +