From 9a74d9fcc63fc7eb3dfa1cf86891ad9f9f473030 Mon Sep 17 00:00:00 2001 From: Kadir Cetinkaya Date: Mon, 10 Sep 2018 13:46:28 +0000 Subject: [PATCH] [clang] Make sure codecompletion is called for calls even when inside a token. Summary: Currently CodeCompleteCall only gets called after a comma or parantheses. This patch makes sure it is called even at the cases like: ```foo(1^);``` Reviewers: ilya-biryukov, ioeric, hokein Reviewed By: ilya-biryukov Subscribers: MaskRay, jkorous, arphaman, cfe-commits Differential Revision: https://reviews.llvm.org/D51038 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341824 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 5 ++++ lib/Parse/ParseDecl.cpp | 7 +++++ lib/Parse/ParseExpr.cpp | 11 ++++++++ lib/Parse/ParseExprCXX.cpp | 22 ++++++++++++--- lib/Parse/ParseOpenMP.cpp | 7 +++++ lib/Sema/CodeCompleteConsumer.cpp | 4 +++ test/CodeCompletion/function-overloads.cpp | 27 +++++++++++++++++++ .../complete-block-property-assignment.m | 9 ++++++- 8 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 test/CodeCompletion/function-overloads.cpp diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 7b89127534..5b3bfb5a07 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -214,6 +214,11 @@ class Parser : public CodeCompletionHandler { /// should not be set directly. bool InMessageExpression; + /// Gets set to true after calling ProduceSignatureHelp, it is for a + /// workaround to make sure ProduceSignatureHelp is only called at the deepest + /// function call. + bool CalledSignatureHelp = false; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7a3a019898..4393c8a509 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2305,6 +2305,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), ThisDecl->getLocation(), Exprs, T.getOpenLocation()); + CalledSignatureHelp = true; Actions.CodeCompleteExpression(getCurScope(), PreferredType); }; if (ThisVarDecl) { @@ -2317,6 +2318,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) { + if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { + Actions.ProduceConstructorSignatureHelp( + getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), + ThisDecl->getLocation(), Exprs, T.getOpenLocation()); + CalledSignatureHelp = true; + } Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren, StopAtSemi); } else { diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d3bb2bbc24..0c14f62d72 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1652,6 +1652,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (Tok.is(tok::code_completion)) { QualType PreferredType = Actions.ProduceCallSignatureHelp( getCurScope(), LHS.get(), None, PT.getOpenLocation()); + CalledSignatureHelp = true; Actions.CodeCompleteExpression(getCurScope(), PreferredType); cutOffParsing(); return ExprError(); @@ -1662,9 +1663,19 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (ParseExpressionList(ArgExprs, CommaLocs, [&] { QualType PreferredType = Actions.ProduceCallSignatureHelp( getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); + CalledSignatureHelp = true; Actions.CodeCompleteExpression(getCurScope(), PreferredType); })) { (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; + } LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index deafd04506..88f1e10304 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1688,8 +1688,15 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), DS.getEndLoc(), Exprs, T.getOpenLocation()); + CalledSignatureHelp = true; Actions.CodeCompleteExpression(getCurScope(), PreferredType); })) { + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { + Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DS.getEndLoc(), Exprs, T.getOpenLocation()); + CalledSignatureHelp = true; + } SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } @@ -2818,13 +2825,22 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] { - ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), - DeclaratorInfo).get(); + 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); - })) { + })) { + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { + ParsedType TypeRep = + Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); + CalledSignatureHelp = true; + } SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 4da357bbbc..9871e5bbf9 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -422,8 +422,15 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { 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; + } Actions.ActOnInitializerError(OmpPrivParm); SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index c7d4fc4efa..226257dd39 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -619,6 +619,10 @@ static std::string getOverloadAsString(const CodeCompletionString &CCS) { OS << "<#" << C.Text << "#>"; break; + // FIXME: We can also print optional parameters of an overload. + case CodeCompletionString::CK_Optional: + break; + default: OS << C.Text; break; } } diff --git a/test/CodeCompletion/function-overloads.cpp b/test/CodeCompletion/function-overloads.cpp new file mode 100644 index 0000000000..00998b0228 --- /dev/null +++ b/test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,27 @@ +int f(int i, int j = 2, int k = 5); +int f(float x, float y...); + +class A { + public: + A(int, int, int); +}; + +void test() { + A a(f(1, 2, 3, 4), 2, 3); +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:17 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:19 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:20 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y) +// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>) +// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A( +// CHECK-CC2: OVERLOAD: [#int#]f(float x, float y) +// CHECK-CC2-NOT: OVERLOAD: [#int#]f(int i) +// CHECK-CC3: OVERLOAD: A(<#int#>, int, int) +// CHECK-CC3: OVERLOAD: A(<#const A &#>) +// CHECK-CC3: OVERLOAD: A(<#A &&#>) +// CHECK-CC4: OVERLOAD: A(int, <#int#>, int) diff --git a/test/Index/complete-block-property-assignment.m b/test/Index/complete-block-property-assignment.m index 908e186295..48b6aea3a6 100644 --- a/test/Index/complete-block-property-assignment.m +++ b/test/Index/complete-block-property-assignment.m @@ -60,7 +60,6 @@ typedef void (^FooBlock)(Foo *someParameter); // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) @@ -69,4 +68,12 @@ typedef void (^FooBlock)(Foo *someParameter); // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end -- 2.40.0