From: Ilya Biryukov Date: Tue, 26 Feb 2019 11:01:50 +0000 (+0000) Subject: [CodeComplete] Propagate preferred type for function arguments in more cases X-Git-Tag: llvmorg-10-init~11219 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ff2a99752f67a73e325b3e57cdafeb342b4c92ac;p=platform%2Fupstream%2Fllvm.git [CodeComplete] Propagate preferred type for function arguments in more cases Summary: See the added test for some new cases. This change also removes special code completion calls inside the ParseExpressionList function now that we properly propagate expected type to the function responsible for parsing elements of the expression list (ParseAssignmentExpression). Reviewers: kadircet Reviewed By: kadircet Subscribers: xbolva00, jdoerfert, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D58541 llvm-svn: 354864 --- diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index e19c482..e8975dc 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1680,10 +1680,10 @@ private: typedef SmallVector CommaLocsTy; /// ParseExpressionList - Used for C/C++ (argument-)expression-list. - bool ParseExpressionList( - SmallVectorImpl &Exprs, - SmallVectorImpl &CommaLocs, - llvm::function_ref Completer = llvm::function_ref()); + bool ParseExpressionList(SmallVectorImpl &Exprs, + SmallVectorImpl &CommaLocs, + llvm::function_ref ExpressionStarts = + llvm::function_ref()); /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f6eee83..3932a27 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -286,6 +286,14 @@ public: void enterCondition(Sema &S, SourceLocation Tok); void enterReturn(Sema &S, SourceLocation Tok); void enterVariableInit(SourceLocation Tok, Decl *D); + /// Computing a type for the function argument may require running + /// overloading, so we postpone its computation until it is actually needed. + /// + /// 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. + void enterFunctionArgument(SourceLocation Tok, + llvm::function_ref ComputeType); void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc); void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind, @@ -297,8 +305,12 @@ public: void enterTypeCast(SourceLocation Tok, QualType CastType); QualType get(SourceLocation Tok) const { - if (Tok == ExpectedLoc) + if (Tok != ExpectedLoc) + return QualType(); + if (!Type.isNull()) return Type; + if (ComputeType) + return ComputeType(); return QualType(); } @@ -307,6 +319,9 @@ private: SourceLocation ExpectedLoc; /// Expected type for a token starting at ExpectedLoc. QualType Type; + /// A function to compute expected type at ExpectedLoc. It is only considered + /// if Type is null. + llvm::function_ref ComputeType; }; /// Sema - This implements semantic analysis and AST building for C. @@ -9280,7 +9295,7 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - + OMPClause *ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Arguments, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9335,7 +9350,7 @@ public: /// Called on well-formed 'unified_address' clause. OMPClause *ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc, SourceLocation EndLoc); - + /// Called on well-formed 'reverse_offload' clause. OMPClause *ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc, SourceLocation EndLoc); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 882972d..84d79d9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2332,25 +2332,27 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( InitializerScopeRAII InitScope(*this, D, ThisDecl); - llvm::function_ref ExprListCompleter; auto ThisVarDecl = dyn_cast_or_null(ThisDecl); - auto ConstructorCompleter = [&, ThisVarDecl] { + auto RunSignatureHelp = [&]() { QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), ThisDecl->getLocation(), Exprs, T.getOpenLocation()); CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + return PreferredType; }; + auto SetPreferredType = [&] { + PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); + }; + + llvm::function_ref ExpressionStarts; if (ThisVarDecl) { // ParseExpressionList can sometimes succeed even when ThisDecl is not // VarDecl. This is an error and it is reported in a call to // Actions.ActOnInitializerError(). However, we call - // ProduceConstructorSignatureHelp only on VarDecls, falling back to - // default completer in other cases. - ExprListCompleter = ConstructorCompleter; + // ProduceConstructorSignatureHelp only on VarDecls. + ExpressionStarts = SetPreferredType; } - - if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) { + if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { Actions.ProduceConstructorSignatureHelp( getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index a8d5e28..895aa02 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3481,20 +3481,20 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // Parse the optional expression-list. ExprVector ArgExprs; CommaLocsTy CommaLocs; + auto RunSignatureHelp = [&] { + QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( + getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, + T.getOpenLocation()); + CalledSignatureHelp = true; + return PreferredType; + }; if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( - getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, - T.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceCtorInitMemberSignatureHelp( - getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, - T.getOpenLocation()); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); SkipUntil(tok::r_paren, StopAtSemi); return true; } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 1146afd..575d32d 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1658,34 +1658,25 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { ExprVector ArgExprs; CommaLocsTy CommaLocs; - - if (Tok.is(tok::code_completion)) { + auto RunSignatureHelp = [&]() -> QualType { QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), None, PT.getOpenLocation()); + getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); - cutOffParsing(); - return ExprError(); - } - + return PreferredType; + }; if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(ArgExprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceCallSignatureHelp( - getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); // If we got an error when parsing expression list, we don't call // the CodeCompleteCall handler inside the parser. So call it here // to make sure we get overload suggestions even when we are in the // middle of a parameter. - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceCallSignatureHelp(getCurScope(), LHS.get(), - ArgExprs, PT.getOpenLocation()); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) @@ -2856,18 +2847,11 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, /// \endverbatim bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, SmallVectorImpl &CommaLocs, - llvm::function_ref Completer) { + llvm::function_ref ExpressionStarts) { bool SawError = false; while (1) { - if (Tok.is(tok::code_completion)) { - if (Completer) - Completer(); - else - Actions.CodeCompleteExpression(getCurScope(), - PreferredType.get(Tok.getLocation())); - cutOffParsing(); - return true; - } + if (ExpressionStarts) + ExpressionStarts(); ExprResult Expr; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index c74d103..94055d4 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1677,20 +1677,21 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { ExprVector Exprs; CommaLocsTy CommaLocs; + auto RunSignatureHelp = [&]() { + QualType PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DS.getEndLoc(), Exprs, T.getOpenLocation()); + CalledSignatureHelp = true; + return PreferredType; + }; + if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(Exprs, CommaLocs, [&] { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2846,23 +2847,21 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; + auto RunSignatureHelp = [&]() { + ParsedType TypeRep = + Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + QualType PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); + CalledSignatureHelp = true; + return PreferredType; + }; if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] { - ParsedType TypeRep = - Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - ParsedType TypeRep = - Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); - CalledSignatureHelp = true; - } + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 782ad12..2740730 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -424,21 +424,19 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { CommaLocsTy CommaLocs; SourceLocation LParLoc = T.getOpenLocation(); - if (ParseExpressionList( - Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), - OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); - CalledSignatureHelp = true; - Actions.CodeCompleteExpression(getCurScope(), PreferredType); - })) { - if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { - Actions.ProduceConstructorSignatureHelp( - getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); - CalledSignatureHelp = true; - } + auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() { + QualType PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), + OmpPrivParm->getLocation(), Exprs, LParLoc); + CalledSignatureHelp = true; + return PreferredType; + }; + if (ParseExpressionList(Exprs, CommaLocs, [&] { + PreferredType.enterFunctionArgument(Tok.getLocation(), + RunSignatureHelp); + })) { + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) + RunSignatureHelp(); Actions.ActOnInitializerError(OmpPrivParm); SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { @@ -893,7 +891,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( SmallVector, OMPC_unknown + 1> FirstClauses(OMPC_unknown + 1); if (Tok.is(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::err_omp_expected_clause) + Diag(Tok, diag::err_omp_expected_clause) << getOpenMPDirectiveName(OMPD_requires); break; } @@ -2039,7 +2037,7 @@ static OpenMPMapClauseKind isMapType(Parser &P) { /// Parse map-type in map clause. /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list) -/// where, map-type ::= to | from | tofrom | alloc | release | delete +/// where, map-type ::= to | from | tofrom | alloc | release | delete static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { Token Tok = P.getCurToken(); if (Tok.is(tok::colon)) { diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index cebf97a..a727bad9 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -350,13 +350,16 @@ public: void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { if (isa(S.CurContext)) { if (sema::BlockScopeInfo *BSI = S.getCurBlock()) { + ComputeType = nullptr; Type = BSI->ReturnType; ExpectedLoc = Tok; } } else if (const auto *Function = dyn_cast(S.CurContext)) { + ComputeType = nullptr; Type = Function->getReturnType(); ExpectedLoc = Tok; } else if (const auto *Method = dyn_cast(S.CurContext)) { + ComputeType = nullptr; Type = Method->getReturnType(); ExpectedLoc = Tok; } @@ -364,10 +367,18 @@ void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) { auto *VD = llvm::dyn_cast_or_null(D); + ComputeType = nullptr; Type = VD ? VD->getType() : QualType(); ExpectedLoc = Tok; } +void PreferredTypeBuilder::enterFunctionArgument( + SourceLocation Tok, llvm::function_ref ComputeType) { + this->ComputeType = ComputeType; + Type = QualType(); + ExpectedLoc = Tok; +} + void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok, SourceLocation LParLoc) { // expected type for parenthesized expression does not change. @@ -480,13 +491,14 @@ static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType, case tok::kw___imag: return QualType(); default: - assert(false && "unhnalded unary op"); + assert(false && "unhandled unary op"); return QualType(); } } void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, tok::TokenKind Op) { + ComputeType = nullptr; Type = getPreferredTypeOfBinaryRHS(S, LHS, Op); ExpectedLoc = Tok; } @@ -495,30 +507,38 @@ void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok, Expr *Base) { if (!Base) return; - Type = this->get(Base->getBeginLoc()); + // Do we have expected type for Base? + if (ExpectedLoc != Base->getBeginLoc()) + return; + // Keep the expected type, only update the location. ExpectedLoc = Tok; + return; } void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind, SourceLocation OpLoc) { + ComputeType = nullptr; Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok, Expr *LHS) { + ComputeType = nullptr; Type = S.getASTContext().IntTy; ExpectedLoc = Tok; } void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok, QualType CastType) { + ComputeType = nullptr; Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType(); ExpectedLoc = Tok; } void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) { + ComputeType = nullptr; Type = S.getASTContext().BoolTy; ExpectedLoc = Tok; } diff --git a/clang/unittests/Sema/CodeCompleteTest.cpp b/clang/unittests/Sema/CodeCompleteTest.cpp index 6bd6074..de37e0c 100644 --- a/clang/unittests/Sema/CodeCompleteTest.cpp +++ b/clang/unittests/Sema/CodeCompleteTest.cpp @@ -442,4 +442,41 @@ TEST(PreferredTypeTest, ParenExpr) { )cpp"; EXPECT_THAT(collectPreferredTypes(Code), Each("const int *")); } + +TEST(PreferredTypeTest, FunctionArguments) { + StringRef Code = R"cpp( + void foo(const int*); + + void bar(const int*); + void bar(const int*, int b); + + struct vector { + const int *data(); + }; + void test() { + foo(^(^(^(^vec^tor^().^da^ta^())))); + bar(^(^(^(^vec^tor^().^da^ta^())))); + } + )cpp"; + EXPECT_THAT(collectPreferredTypes(Code), Each("const int *")); + + Code = R"cpp( + void bar(int, volatile double *); + void bar(int, volatile double *, int, int); + + struct vector { + double *data(); + }; + + struct class_members { + void bar(int, volatile double *); + void bar(int, volatile double *, int, int); + }; + void test() { + bar(10, ^(^(^(^vec^tor^().^da^ta^())))); + class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^())))); + } + )cpp"; + EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *")); +} } // namespace