From a32d253f10cb7dccf17ffaeaa037c6bef453a6d5 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 llvm-svn: 341824 --- clang/include/clang/Parse/Parser.h | 5 ++++ clang/lib/Parse/ParseDecl.cpp | 7 +++++ clang/lib/Parse/ParseExpr.cpp | 11 ++++++++ clang/lib/Parse/ParseExprCXX.cpp | 22 ++++++++++++--- clang/lib/Parse/ParseOpenMP.cpp | 7 +++++ clang/lib/Sema/CodeCompleteConsumer.cpp | 4 +++ .../CodeCompletion/function-overloads.cpp | 27 +++++++++++++++++++ .../complete-block-property-assignment.m | 9 ++++++- 8 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 clang/test/CodeCompletion/function-overloads.cpp diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 7b89127534a5..5b3bfb5a0771 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7a3a0198983d..4393c8a509de 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index d3bb2bbc24ec..0c14f62d7252 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/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/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index deafd04506c2..88f1e10304b2 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/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/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 4da357bbbc77..9871e5bbf9fa 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/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/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index c7d4fc4efa87..226257dd395b 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/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/clang/test/CodeCompletion/function-overloads.cpp b/clang/test/CodeCompletion/function-overloads.cpp new file mode 100644 index 000000000000..00998b022884 --- /dev/null +++ b/clang/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/clang/test/Index/complete-block-property-assignment.m b/clang/test/Index/complete-block-property-assignment.m index 908e18629528..48b6aea3a675 100644 --- a/clang/test/Index/complete-block-property-assignment.m +++ b/clang/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