Browse Source

[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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@354864 91177308-0d34-0410-b5e6-96231b3b80d8
Ilya Biryukov 6 years ago
parent
commit
ee7f333417

+ 4 - 4
include/clang/Parse/Parser.h

@@ -1680,10 +1680,10 @@ private:
   typedef SmallVector<SourceLocation, 20> CommaLocsTy;
   typedef SmallVector<SourceLocation, 20> CommaLocsTy;
 
 
   /// ParseExpressionList - Used for C/C++ (argument-)expression-list.
   /// ParseExpressionList - Used for C/C++ (argument-)expression-list.
-  bool ParseExpressionList(
-      SmallVectorImpl<Expr *> &Exprs,
-      SmallVectorImpl<SourceLocation> &CommaLocs,
-      llvm::function_ref<void()> Completer = llvm::function_ref<void()>());
+  bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
+                           SmallVectorImpl<SourceLocation> &CommaLocs,
+                           llvm::function_ref<void()> ExpressionStarts =
+                               llvm::function_ref<void()>());
 
 
   /// ParseSimpleExpressionList - A simple comma-separated list of expressions,
   /// ParseSimpleExpressionList - A simple comma-separated list of expressions,
   /// used for misc language extensions.
   /// used for misc language extensions.

+ 18 - 3
include/clang/Sema/Sema.h

@@ -286,6 +286,14 @@ public:
   void enterCondition(Sema &S, SourceLocation Tok);
   void enterCondition(Sema &S, SourceLocation Tok);
   void enterReturn(Sema &S, SourceLocation Tok);
   void enterReturn(Sema &S, SourceLocation Tok);
   void enterVariableInit(SourceLocation Tok, Decl *D);
   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<QualType()> ComputeType);
 
 
   void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc);
   void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc);
   void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind,
   void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind,
@@ -297,8 +305,12 @@ public:
   void enterTypeCast(SourceLocation Tok, QualType CastType);
   void enterTypeCast(SourceLocation Tok, QualType CastType);
 
 
   QualType get(SourceLocation Tok) const {
   QualType get(SourceLocation Tok) const {
-    if (Tok == ExpectedLoc)
+    if (Tok != ExpectedLoc)
+      return QualType();
+    if (!Type.isNull())
       return Type;
       return Type;
+    if (ComputeType)
+      return ComputeType();
     return QualType();
     return QualType();
   }
   }
 
 
@@ -307,6 +319,9 @@ private:
   SourceLocation ExpectedLoc;
   SourceLocation ExpectedLoc;
   /// Expected type for a token starting at ExpectedLoc.
   /// Expected type for a token starting at ExpectedLoc.
   QualType Type;
   QualType Type;
+  /// A function to compute expected type at ExpectedLoc. It is only considered
+  /// if Type is null.
+  llvm::function_ref<QualType()> ComputeType;
 };
 };
 
 
 /// Sema - This implements semantic analysis and AST building for C.
 /// Sema - This implements semantic analysis and AST building for C.
@@ -9280,7 +9295,7 @@ public:
                                        SourceLocation StartLoc,
                                        SourceLocation StartLoc,
                                        SourceLocation LParenLoc,
                                        SourceLocation LParenLoc,
                                        SourceLocation EndLoc);
                                        SourceLocation EndLoc);
-  
+
   OMPClause *ActOnOpenMPSingleExprWithArgClause(
   OMPClause *ActOnOpenMPSingleExprWithArgClause(
       OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr,
       OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr,
       SourceLocation StartLoc, SourceLocation LParenLoc,
       SourceLocation StartLoc, SourceLocation LParenLoc,
@@ -9335,7 +9350,7 @@ public:
   /// Called on well-formed 'unified_address' clause.
   /// Called on well-formed 'unified_address' clause.
   OMPClause *ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc,
   OMPClause *ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc,
                                                   SourceLocation EndLoc);
                                                   SourceLocation EndLoc);
-  
+
   /// Called on well-formed 'reverse_offload' clause.
   /// Called on well-formed 'reverse_offload' clause.
   OMPClause *ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc,
   OMPClause *ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc,
                                              SourceLocation EndLoc);
                                              SourceLocation EndLoc);

+ 10 - 8
lib/Parse/ParseDecl.cpp

@@ -2332,25 +2332,27 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
 
 
     InitializerScopeRAII InitScope(*this, D, ThisDecl);
     InitializerScopeRAII InitScope(*this, D, ThisDecl);
 
 
-    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 RunSignatureHelp = [&]() {
       QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
       QualType PreferredType = Actions.ProduceConstructorSignatureHelp(
           getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
           getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
           ThisDecl->getLocation(), Exprs, T.getOpenLocation());
           ThisDecl->getLocation(), Exprs, T.getOpenLocation());
       CalledSignatureHelp = true;
       CalledSignatureHelp = true;
-      Actions.CodeCompleteExpression(getCurScope(), PreferredType);
+      return PreferredType;
     };
     };
+    auto SetPreferredType = [&] {
+      PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp);
+    };
+
+    llvm::function_ref<void()> ExpressionStarts;
     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
-      // 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) {
       if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
         Actions.ProduceConstructorSignatureHelp(
         Actions.ProduceConstructorSignatureHelp(
             getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
             getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),

+ 11 - 11
lib/Parse/ParseDeclCXX.cpp

@@ -3481,20 +3481,20 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
     // Parse the optional expression-list.
     // Parse the optional expression-list.
     ExprVector ArgExprs;
     ExprVector ArgExprs;
     CommaLocsTy CommaLocs;
     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) &&
     if (Tok.isNot(tok::r_paren) &&
         ParseExpressionList(ArgExprs, CommaLocs, [&] {
         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);
       SkipUntil(tok::r_paren, StopAtSemi);
       return true;
       return true;
     }
     }

+ 11 - 27
lib/Parse/ParseExpr.cpp

@@ -1658,34 +1658,25 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
 
 
       ExprVector ArgExprs;
       ExprVector ArgExprs;
       CommaLocsTy CommaLocs;
       CommaLocsTy CommaLocs;
-
-      if (Tok.is(tok::code_completion)) {
+      auto RunSignatureHelp = [&]() -> QualType {
         QualType PreferredType = Actions.ProduceCallSignatureHelp(
         QualType PreferredType = Actions.ProduceCallSignatureHelp(
-            getCurScope(), LHS.get(), None, PT.getOpenLocation());
+            getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation());
         CalledSignatureHelp = true;
         CalledSignatureHelp = true;
-        Actions.CodeCompleteExpression(getCurScope(), PreferredType);
-        cutOffParsing();
-        return ExprError();
-      }
-
+        return PreferredType;
+      };
       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, [&] {
-                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);
             (void)Actions.CorrectDelayedTyposInExpr(LHS);
             // If we got an error when parsing expression list, we don't call
             // If we got an error when parsing expression list, we don't call
             // the CodeCompleteCall handler inside the parser. So call it here
             // the CodeCompleteCall handler inside the parser. So call it here
             // to make sure we get overload suggestions even when we are in the
             // to make sure we get overload suggestions even when we are in the
             // middle of a parameter.
             // 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();
             LHS = ExprError();
           } else if (LHS.isInvalid()) {
           } else if (LHS.isInvalid()) {
             for (auto &E : ArgExprs)
             for (auto &E : ArgExprs)
@@ -2856,18 +2847,11 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS,
 /// \endverbatim
 /// \endverbatim
 bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
 bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
                                  SmallVectorImpl<SourceLocation> &CommaLocs,
                                  SmallVectorImpl<SourceLocation> &CommaLocs,
-                                 llvm::function_ref<void()> Completer) {
+                                 llvm::function_ref<void()> ExpressionStarts) {
   bool SawError = false;
   bool SawError = false;
   while (1) {
   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;
     ExprResult Expr;
     if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
     if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {

+ 25 - 26
lib/Parse/ParseExprCXX.cpp

@@ -1677,20 +1677,21 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
     ExprVector Exprs;
     ExprVector Exprs;
     CommaLocsTy CommaLocs;
     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 (Tok.isNot(tok::r_paren)) {
       if (ParseExpressionList(Exprs, CommaLocs, [&] {
       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);
         SkipUntil(tok::r_paren, StopAtSemi);
         return ExprError();
         return ExprError();
       }
       }
@@ -2846,23 +2847,21 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
     ConstructorLParen = T.getOpenLocation();
     ConstructorLParen = T.getOpenLocation();
     if (Tok.isNot(tok::r_paren)) {
     if (Tok.isNot(tok::r_paren)) {
       CommaLocsTy CommaLocs;
       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, [&] {
       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);
         SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch);
         return ExprError();
         return ExprError();
       }
       }

+ 15 - 17
lib/Parse/ParseOpenMP.cpp

@@ -424,21 +424,19 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
     CommaLocsTy CommaLocs;
     CommaLocsTy CommaLocs;
 
 
     SourceLocation LParLoc = T.getOpenLocation();
     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);
       Actions.ActOnInitializerError(OmpPrivParm);
       SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
       SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
     } else {
     } else {
@@ -893,7 +891,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
     SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
     SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
     FirstClauses(OMPC_unknown + 1);
     FirstClauses(OMPC_unknown + 1);
     if (Tok.is(tok::annot_pragma_openmp_end)) {
     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);
           << getOpenMPDirectiveName(OMPD_requires);
       break;
       break;
     }
     }
@@ -2039,7 +2037,7 @@ static OpenMPMapClauseKind isMapType(Parser &P) {
 
 
 /// Parse map-type in map clause.
 /// Parse map-type in map clause.
 /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] map-type : ] list)
 /// 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) {
 static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) {
   Token Tok = P.getCurToken();
   Token Tok = P.getCurToken();
   if (Tok.is(tok::colon)) {
   if (Tok.is(tok::colon)) {

+ 22 - 2
lib/Sema/SemaCodeComplete.cpp

@@ -350,13 +350,16 @@ public:
 void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) {
 void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) {
   if (isa<BlockDecl>(S.CurContext)) {
   if (isa<BlockDecl>(S.CurContext)) {
     if (sema::BlockScopeInfo *BSI = S.getCurBlock()) {
     if (sema::BlockScopeInfo *BSI = S.getCurBlock()) {
+      ComputeType = nullptr;
       Type = BSI->ReturnType;
       Type = BSI->ReturnType;
       ExpectedLoc = Tok;
       ExpectedLoc = Tok;
     }
     }
   } else if (const auto *Function = dyn_cast<FunctionDecl>(S.CurContext)) {
   } else if (const auto *Function = dyn_cast<FunctionDecl>(S.CurContext)) {
+    ComputeType = nullptr;
     Type = Function->getReturnType();
     Type = Function->getReturnType();
     ExpectedLoc = Tok;
     ExpectedLoc = Tok;
   } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(S.CurContext)) {
   } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(S.CurContext)) {
+    ComputeType = nullptr;
     Type = Method->getReturnType();
     Type = Method->getReturnType();
     ExpectedLoc = Tok;
     ExpectedLoc = Tok;
   }
   }
@@ -364,10 +367,18 @@ void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) {
 
 
 void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) {
 void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) {
   auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D);
   auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D);
+  ComputeType = nullptr;
   Type = VD ? VD->getType() : QualType();
   Type = VD ? VD->getType() : QualType();
   ExpectedLoc = Tok;
   ExpectedLoc = Tok;
 }
 }
 
 
+void PreferredTypeBuilder::enterFunctionArgument(
+    SourceLocation Tok, llvm::function_ref<QualType()> ComputeType) {
+  this->ComputeType = ComputeType;
+  Type = QualType();
+  ExpectedLoc = Tok;
+}
+
 void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok,
 void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok,
                                           SourceLocation LParLoc) {
                                           SourceLocation LParLoc) {
   // expected type for parenthesized expression does not change.
   // expected type for parenthesized expression does not change.
@@ -480,13 +491,14 @@ static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType,
   case tok::kw___imag:
   case tok::kw___imag:
     return QualType();
     return QualType();
   default:
   default:
-    assert(false && "unhnalded unary op");
+    assert(false && "unhandled unary op");
     return QualType();
     return QualType();
   }
   }
 }
 }
 
 
 void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS,
 void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS,
                                        tok::TokenKind Op) {
                                        tok::TokenKind Op) {
+  ComputeType = nullptr;
   Type = getPreferredTypeOfBinaryRHS(S, LHS, Op);
   Type = getPreferredTypeOfBinaryRHS(S, LHS, Op);
   ExpectedLoc = Tok;
   ExpectedLoc = Tok;
 }
 }
@@ -495,30 +507,38 @@ void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok,
                                           Expr *Base) {
                                           Expr *Base) {
   if (!Base)
   if (!Base)
     return;
     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;
   ExpectedLoc = Tok;
+  return;
 }
 }
 
 
 void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok,
 void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok,
                                       tok::TokenKind OpKind,
                                       tok::TokenKind OpKind,
                                       SourceLocation OpLoc) {
                                       SourceLocation OpLoc) {
+  ComputeType = nullptr;
   Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind);
   Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind);
   ExpectedLoc = Tok;
   ExpectedLoc = Tok;
 }
 }
 
 
 void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok,
 void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok,
                                           Expr *LHS) {
                                           Expr *LHS) {
+  ComputeType = nullptr;
   Type = S.getASTContext().IntTy;
   Type = S.getASTContext().IntTy;
   ExpectedLoc = Tok;
   ExpectedLoc = Tok;
 }
 }
 
 
 void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok,
 void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok,
                                          QualType CastType) {
                                          QualType CastType) {
+  ComputeType = nullptr;
   Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType();
   Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType();
   ExpectedLoc = Tok;
   ExpectedLoc = Tok;
 }
 }
 
 
 void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) {
 void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) {
+  ComputeType = nullptr;
   Type = S.getASTContext().BoolTy;
   Type = S.getASTContext().BoolTy;
   ExpectedLoc = Tok;
   ExpectedLoc = Tok;
 }
 }

+ 37 - 0
unittests/Sema/CodeCompleteTest.cpp

@@ -442,4 +442,41 @@ TEST(PreferredTypeTest, ParenExpr) {
   )cpp";
   )cpp";
   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
   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
 } // namespace