]> granicus.if.org Git - clang/commitdiff
[clang] Make sure codecompletion is called for calls even when inside a token.
authorKadir Cetinkaya <kadircet@google.com>
Mon, 10 Sep 2018 13:46:28 +0000 (13:46 +0000)
committerKadir Cetinkaya <kadircet@google.com>
Mon, 10 Sep 2018 13:46:28 +0000 (13:46 +0000)
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
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseOpenMP.cpp
lib/Sema/CodeCompleteConsumer.cpp
test/CodeCompletion/function-overloads.cpp [new file with mode: 0644]
test/Index/complete-block-property-assignment.m

index 7b89127534a599a32627ff943457d8f73ccf6587..5b3bfb5a07714ed83fa8754a021589978e0ca4fe 100644 (file)
@@ -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;
 
index 7a3a0198983d34748defa92a2dcb96c6b8cfdc31..4393c8a509dee01517c80bd15a06c9401fec22c5 100644 (file)
@@ -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 {
index d3bb2bbc24ec20ae3ee043f2cf886118dee19966..0c14f62d7252221f6b803650f9f4e365db1d6b2b 100644 (file)
@@ -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)
index deafd04506c2078aea8eb82647e01357866e5e68..88f1e10304b2326d38edb97947d00c3b835b328f 100644 (file)
@@ -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();
       }
index 4da357bbbc778f4c17e40f2167eb22117c0d34c4..9871e5bbf9fafe31dc0ac346bb92ae9c692e9abd 100644 (file)
@@ -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 {
index c7d4fc4efa8711d431e729c5b38276ca1a6be44f..226257dd395b7e97a73ff4ed88470636e789761f 100644 (file)
@@ -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 (file)
index 0000000..00998b0
--- /dev/null
@@ -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)
index 908e186295289df727da752172d61adc8d239d94..48b6aea3a6750244a144c69acda1ba4e8c1415a9 100644 (file)
@@ -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