Bladeren bron

[CodeComplete] Clearly distinguish signature help and code completion.

Summary:
Code completion in clang is actually a mix of two features:
- Code completion is a familiar feature. Results are exposed via the
  CodeCompleteConsumer::ProcessCodeCompleteResults callback.
- Signature help figures out if the current expression is an argument of
  some function call and shows corresponding signatures if so.
  Results are exposed via CodeCompleteConsumer::ProcessOverloadCandidates.

This patch refactors the implementation to untangle those two from each
other and makes some naming tweaks to avoid confusion when reading the
code.

The refactoring is required for signature help fixes, see D51038.

The only intended behavior change is the order of callbacks.
ProcessOverloadCandidates is now called before ProcessCodeCompleteResults.

Reviewers: sammccall, kadircet

Reviewed By: sammccall

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D51782

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341660 91177308-0d34-0410-b5e6-96231b3b80d8
Ilya Biryukov 7 jaren geleden
bovenliggende
commit
96b8b58101

+ 9 - 5
include/clang/Sema/Sema.h

@@ -10231,6 +10231,7 @@ public:
   struct CodeCompleteExpressionData;
   struct CodeCompleteExpressionData;
   void CodeCompleteExpression(Scope *S,
   void CodeCompleteExpression(Scope *S,
                               const CodeCompleteExpressionData &Data);
                               const CodeCompleteExpressionData &Data);
+  void CodeCompleteExpression(Scope *S, QualType PreferredType);
   void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase,
   void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase,
                                        SourceLocation OpLoc, bool IsArrow,
                                        SourceLocation OpLoc, bool IsArrow,
                                        bool IsBaseExprStatement);
                                        bool IsBaseExprStatement);
@@ -10241,11 +10242,14 @@ public:
                                       const VirtSpecifiers *VS = nullptr);
                                       const VirtSpecifiers *VS = nullptr);
   void CodeCompleteBracketDeclarator(Scope *S);
   void CodeCompleteBracketDeclarator(Scope *S);
   void CodeCompleteCase(Scope *S);
   void CodeCompleteCase(Scope *S);
-  void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args,
-                        SourceLocation OpenParLoc);
-  void CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc,
-                               ArrayRef<Expr *> Args,
-                               SourceLocation OpenParLoc);
+  /// Reports signatures for a call to CodeCompleteConsumer and returns the
+  /// preferred type for the current argument. Returned type can be null.
+  QualType ProduceCallSignatureHelp(Scope *S, Expr *Fn, ArrayRef<Expr *> Args,
+                                    SourceLocation OpenParLoc);
+  QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type,
+                                           SourceLocation Loc,
+                                           ArrayRef<Expr *> Args,
+                                           SourceLocation OpenParLoc);
   void CodeCompleteInitializer(Scope *S, Decl *D);
   void CodeCompleteInitializer(Scope *S, Decl *D);
   void CodeCompleteReturn(Scope *S);
   void CodeCompleteReturn(Scope *S);
   void CodeCompleteAfterIf(Scope *S);
   void CodeCompleteAfterIf(Scope *S);

+ 4 - 3
lib/Parse/ParseDecl.cpp

@@ -2302,16 +2302,17 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
     llvm::function_ref<void()> ExprListCompleter;
     llvm::function_ref<void()> ExprListCompleter;
     auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
     auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
     auto ConstructorCompleter = [&, ThisVarDecl] {
     auto ConstructorCompleter = [&, ThisVarDecl] {
-      Actions.CodeCompleteConstructor(
+      QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
           getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
           getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
           ThisDecl->getLocation(), Exprs, T.getOpenLocation());
           ThisDecl->getLocation(), Exprs, T.getOpenLocation());
+      Actions.CodeCompleteExpression(getCurScope(), PreferredType);
     };
     };
     if (ThisVarDecl) {
     if (ThisVarDecl) {
       // ParseExpressionList can sometimes succeed even when ThisDecl is not
       // ParseExpressionList can sometimes succeed even when ThisDecl is not
       // VarDecl. This is an error and it is reported in a call to
       // VarDecl. This is an error and it is reported in a call to
       // Actions.ActOnInitializerError(). However, we call
       // Actions.ActOnInitializerError(). However, we call
-      // CodeCompleteConstructor only on VarDecls, falling back to default
-      // completer in other cases.
+      // ProduceConstructorSignatureHelp only on VarDecls, falling back to
+      // default completer in other cases.
       ExprListCompleter = ConstructorCompleter;
       ExprListCompleter = ConstructorCompleter;
     }
     }
 
 

+ 6 - 4
lib/Parse/ParseExpr.cpp

@@ -1650,8 +1650,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       CommaLocsTy CommaLocs;
       CommaLocsTy CommaLocs;
 
 
       if (Tok.is(tok::code_completion)) {
       if (Tok.is(tok::code_completion)) {
-        Actions.CodeCompleteCall(getCurScope(), LHS.get(), None,
-                                 PT.getOpenLocation());
+        QualType PreferredType = Actions.ProduceCallSignatureHelp(
+            getCurScope(), LHS.get(), None, PT.getOpenLocation());
+        Actions.CodeCompleteExpression(getCurScope(), PreferredType);
         cutOffParsing();
         cutOffParsing();
         return ExprError();
         return ExprError();
       }
       }
@@ -1659,8 +1660,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       if (OpKind == tok::l_paren || !LHS.isInvalid()) {
       if (OpKind == tok::l_paren || !LHS.isInvalid()) {
         if (Tok.isNot(tok::r_paren)) {
         if (Tok.isNot(tok::r_paren)) {
           if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
           if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
-                Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs,
-                                         PT.getOpenLocation());
+                QualType PreferredType = Actions.ProduceCallSignatureHelp(
+                    getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation());
+                Actions.CodeCompleteExpression(getCurScope(), PreferredType);
               })) {
               })) {
             (void)Actions.CorrectDelayedTyposInExpr(LHS);
             (void)Actions.CorrectDelayedTyposInExpr(LHS);
             LHS = ExprError();
             LHS = ExprError();

+ 4 - 2
lib/Parse/ParseExprCXX.cpp

@@ -1685,9 +1685,10 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
 
 
     if (Tok.isNot(tok::r_paren)) {
     if (Tok.isNot(tok::r_paren)) {
       if (ParseExpressionList(Exprs, CommaLocs, [&] {
       if (ParseExpressionList(Exprs, CommaLocs, [&] {
-            Actions.CodeCompleteConstructor(
+            QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
                 getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
                 getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
                 DS.getEndLoc(), Exprs, T.getOpenLocation());
                 DS.getEndLoc(), Exprs, T.getOpenLocation());
+            Actions.CodeCompleteExpression(getCurScope(), PreferredType);
           })) {
           })) {
         SkipUntil(tok::r_paren, StopAtSemi);
         SkipUntil(tok::r_paren, StopAtSemi);
         return ExprError();
         return ExprError();
@@ -2819,9 +2820,10 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
       if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] {
       if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] {
             ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(),
             ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(),
                                                        DeclaratorInfo).get();
                                                        DeclaratorInfo).get();
-            Actions.CodeCompleteConstructor(
+            QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
                 getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
                 getCurScope(), TypeRep.get()->getCanonicalTypeInternal(),
                 DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen);
                 DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen);
+            Actions.CodeCompleteExpression(getCurScope(), PreferredType);
       })) {
       })) {
         SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
         SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
         return ExprError();
         return ExprError();

+ 2 - 1
lib/Parse/ParseOpenMP.cpp

@@ -418,10 +418,11 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
     SourceLocation LParLoc = T.getOpenLocation();
     SourceLocation LParLoc = T.getOpenLocation();
     if (ParseExpressionList(
     if (ParseExpressionList(
             Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] {
             Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] {
-              Actions.CodeCompleteConstructor(
+              QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
                   getCurScope(),
                   getCurScope(),
                   OmpPrivParm->getType()->getCanonicalTypeInternal(),
                   OmpPrivParm->getType()->getCanonicalTypeInternal(),
                   OmpPrivParm->getLocation(), Exprs, LParLoc);
                   OmpPrivParm->getLocation(), Exprs, LParLoc);
+              Actions.CodeCompleteExpression(getCurScope(), PreferredType);
             })) {
             })) {
       Actions.ActOnInitializerError(OmpPrivParm);
       Actions.ActOnInitializerError(OmpPrivParm);
       SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
       SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);

+ 29 - 40
lib/Sema/SemaCodeComplete.cpp

@@ -3752,6 +3752,10 @@ void Sema::CodeCompleteExpression(Scope *S,
                             Results.data(), Results.size());
                             Results.data(), Results.size());
 }
 }
 
 
+void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType) {
+  return CodeCompleteExpression(S, CodeCompleteExpressionData(PreferredType));
+}
+
 void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
 void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
   if (E.isInvalid())
   if (E.isInvalid())
     CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction);
     CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction);
@@ -4435,42 +4439,28 @@ static QualType getParamType(Sema &SemaRef,
   return ParamType;
   return ParamType;
 }
 }
 
 
-static void
-CodeCompleteOverloadResults(Sema &SemaRef, Scope *S,
-                            MutableArrayRef<ResultCandidate> Candidates,
-                            unsigned CurrentArg, SourceLocation OpenParLoc,
-                            bool CompleteExpressionWithCurrentArg = true) {
-  QualType ParamType;
-  if (CompleteExpressionWithCurrentArg)
-    ParamType = getParamType(SemaRef, Candidates, CurrentArg);
-
-  if (ParamType.isNull())
-    SemaRef.CodeCompleteOrdinaryName(S, Sema::PCC_Expression);
-  else
-    SemaRef.CodeCompleteExpression(S, ParamType);
-
-  if (!Candidates.empty())
-    SemaRef.CodeCompleter->ProcessOverloadCandidates(
-        SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc);
+static QualType
+ProduceSignatureHelp(Sema &SemaRef, Scope *S,
+                     MutableArrayRef<ResultCandidate> Candidates,
+                     unsigned CurrentArg, SourceLocation OpenParLoc) {
+  if (Candidates.empty())
+    return QualType();
+  SemaRef.CodeCompleter->ProcessOverloadCandidates(
+      SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc);
+  return getParamType(SemaRef, Candidates, CurrentArg);
 }
 }
 
 
-void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args,
-                            SourceLocation OpenParLoc) {
+QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
+                                        ArrayRef<Expr *> Args,
+                                        SourceLocation OpenParLoc) {
   if (!CodeCompleter)
   if (!CodeCompleter)
-    return;
-
-  // When we're code-completing for a call, we fall back to ordinary
-  // name code-completion whenever we can't produce specific
-  // results. We may want to revisit this strategy in the future,
-  // e.g., by merging the two kinds of results.
+    return QualType();
 
 
   // FIXME: Provide support for variadic template functions.
   // FIXME: Provide support for variadic template functions.
-
   // Ignore type-dependent call expressions entirely.
   // Ignore type-dependent call expressions entirely.
   if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) ||
   if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) ||
       Expr::hasAnyTypeDependentArguments(Args)) {
       Expr::hasAnyTypeDependentArguments(Args)) {
-    CodeCompleteOrdinaryName(S, PCC_Expression);
-    return;
+    return QualType();
   }
   }
 
 
   // Build an overload candidate set based on the functions we find.
   // Build an overload candidate set based on the functions we find.
@@ -4551,25 +4541,24 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args,
         Results.push_back(ResultCandidate(FT));
         Results.push_back(ResultCandidate(FT));
     }
     }
   }
   }
-
   mergeCandidatesWithResults(*this, Results, CandidateSet, Loc);
   mergeCandidatesWithResults(*this, Results, CandidateSet, Loc);
-  CodeCompleteOverloadResults(*this, S, Results, Args.size(), OpenParLoc,
-                              !CandidateSet.empty());
+  QualType ParamType =
+      ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc);
+  return !CandidateSet.empty() ? ParamType : QualType();
 }
 }
 
 
-void Sema::CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc,
-                                   ArrayRef<Expr *> Args,
-                                   SourceLocation OpenParLoc) {
+QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
+                                               SourceLocation Loc,
+                                               ArrayRef<Expr *> Args,
+                                               SourceLocation OpenParLoc) {
   if (!CodeCompleter)
   if (!CodeCompleter)
-    return;
+    return QualType();
 
 
   // A complete type is needed to lookup for constructors.
   // A complete type is needed to lookup for constructors.
   CXXRecordDecl *RD =
   CXXRecordDecl *RD =
       isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr;
       isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr;
-  if (!RD) {
-    CodeCompleteExpression(S, Type);
-    return;
-  }
+  if (!RD)
+    return Type;
 
 
   // FIXME: Provide support for member initializers.
   // FIXME: Provide support for member initializers.
   // FIXME: Provide support for variadic template constructors.
   // FIXME: Provide support for variadic template constructors.
@@ -4594,7 +4583,7 @@ void Sema::CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc,
 
 
   SmallVector<ResultCandidate, 8> Results;
   SmallVector<ResultCandidate, 8> Results;
   mergeCandidatesWithResults(*this, Results, CandidateSet, Loc);
   mergeCandidatesWithResults(*this, Results, CandidateSet, Loc);
-  CodeCompleteOverloadResults(*this, S, Results, Args.size(), OpenParLoc);
+  return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc);
 }
 }
 
 
 void Sema::CodeCompleteInitializer(Scope *S, Decl *D) {
 void Sema::CodeCompleteInitializer(Scope *S, Decl *D) {

+ 1 - 1
test/CodeCompletion/call.cpp

@@ -18,10 +18,10 @@ void f();
 void test() {
 void test() {
   f(Y(), 0, 0);
   f(Y(), 0, 0);
   // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
   // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
-  // CHECK-CC1: COMPLETION: Pattern : dynamic_cast<<#type#>>(<#expression#>)
   // CHECK-CC1: f(Y y, <#int ZZ#>)
   // CHECK-CC1: f(Y y, <#int ZZ#>)
   // CHECK-CC1-NEXT: f(int i, <#int j#>, int k)
   // CHECK-CC1-NEXT: f(int i, <#int j#>, int k)
   // CHECK-CC1-NEXT: f(float x, <#float y#>)
   // CHECK-CC1-NEXT: f(float x, <#float y#>)
+  // CHECK-CC1: COMPLETION: Pattern : dynamic_cast<<#type#>>(<#expression#>)
   // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
   // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
   // CHECK-CC2-NOT: f(Y y, int ZZ)
   // CHECK-CC2-NOT: f(Y y, int ZZ)
   // CHECK-CC2: f(int i, int j, <#int k#>)
   // CHECK-CC2: f(int i, int j, <#int k#>)