@@ -745,6 +745,79 @@ static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr,
745745 return false ;
746746}
747747
748+ // / Get index of \p CCExpr in \p Params. Note that the position in \p Params may
749+ // / be different than the position in \p Args if there are defaulted arguments
750+ // / in \p Params which don't occur in \p Args.
751+ // /
752+ // / \returns \c true if success, \c false if \p CCExpr is not a part of \p Args.
753+ static bool getPositionInParams (DeclContext &DC, Expr *Args, Expr *CCExpr,
754+ ArrayRef<AnyFunctionType::Param> Params,
755+ unsigned &PosInParams) {
756+ if (isa<ParenExpr>(Args)) {
757+ PosInParams = 0 ;
758+ return true ;
759+ }
760+
761+ auto *tuple = dyn_cast<TupleExpr>(Args);
762+ if (!tuple) {
763+ return false ;
764+ }
765+
766+ auto &SM = DC.getASTContext ().SourceMgr ;
767+ PosInParams = 0 ;
768+ unsigned PosInArgs = 0 ;
769+ bool LastParamWasVariadic = false ;
770+ // We advance PosInArgs until we find argument that is after the code
771+ // completion token, which is when we stop.
772+ // For each argument, we try to find a matching parameter either by matching
773+ // argument labels, in which case PosInParams may be advanced by more than 1,
774+ // or by advancing PosInParams and PosInArgs both by 1.
775+ for (; PosInArgs < tuple->getNumElements (); ++PosInArgs) {
776+ if (!SM.isBeforeInBuffer (tuple->getElement (PosInArgs)->getEndLoc (),
777+ CCExpr->getStartLoc ())) {
778+ // The arg is after the code completion position. Stop.
779+ break ;
780+ }
781+
782+ auto ArgName = tuple->getElementName (PosInArgs);
783+ // If the last parameter we matched was variadic, we claim all following
784+ // unlabeled arguments for that variadic parameter -> advance PosInArgs but
785+ // not PosInParams.
786+ if (LastParamWasVariadic && ArgName.empty ()) {
787+ continue ;
788+ } else {
789+ LastParamWasVariadic = false ;
790+ }
791+
792+ // Look for a matching parameter label.
793+ bool FoundLabelMatch = false ;
794+ for (unsigned i = PosInParams; i < Params.size (); ++i) {
795+ if (Params[i].getLabel () == ArgName) {
796+ // We have found a label match. Advance the position in the params
797+ // to point to the param after the one with this label.
798+ PosInParams = i + 1 ;
799+ FoundLabelMatch = true ;
800+ if (Params[i].isVariadic ()) {
801+ LastParamWasVariadic = true ;
802+ }
803+ break ;
804+ }
805+ }
806+
807+ if (!FoundLabelMatch) {
808+ // We haven't found a matching argument label. Assume the current one is
809+ // named incorrectly and advance by one.
810+ ++PosInParams;
811+ }
812+ }
813+ if (PosInArgs < tuple->getNumElements () && PosInParams < Params.size ()) {
814+ // We didn't search until the end, so we found a position in Params. Success
815+ return true ;
816+ } else {
817+ return false ;
818+ }
819+ }
820+
748821// / Given an expression and its context, the analyzer tries to figure out the
749822// / expected type of the expression by analyzing its context.
750823class ExprContextAnalyzer {
@@ -791,14 +864,12 @@ class ExprContextAnalyzer {
791864 PossibleCallees.assign (Candidates.begin (), Candidates.end ());
792865
793866 // Determine the position of code completion token in call argument.
794- unsigned Position ;
867+ unsigned PositionInArgs ;
795868 bool HasName;
796- if (!getPositionInArgs (*DC, Arg, ParsedExpr, Position , HasName))
869+ if (!getPositionInArgs (*DC, Arg, ParsedExpr, PositionInArgs , HasName))
797870 return false ;
798871
799872 // Collect possible types (or labels) at the position.
800- // FIXME: Take variadic and optional parameters into account. We need to do
801- // something equivalent to 'constraints::matchCallArguments'
802873 {
803874 bool MayNeedName = !HasName && !E->isImplicit () &&
804875 (isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
@@ -811,13 +882,22 @@ class ExprContextAnalyzer {
811882 memberDC = typeAndDecl.Decl ->getInnermostDeclContext ();
812883
813884 auto Params = typeAndDecl.Type ->getParams ();
885+ unsigned PositionInParams;
886+ if (!getPositionInParams (*DC, Arg, ParsedExpr, Params,
887+ PositionInParams)) {
888+ // If the argument doesn't have a matching position in the parameters,
889+ // indicate that with optional nullptr param.
890+ if (seenArgs.insert ({Identifier (), CanType ()}).second )
891+ recordPossibleParam (nullptr , /* isRequired=*/ false );
892+ continue ;
893+ }
814894 ParameterList *paramList = nullptr ;
815895 if (auto VD = typeAndDecl.Decl ) {
816896 paramList = getParameterList (VD);
817897 if (paramList && paramList->size () != Params.size ())
818898 paramList = nullptr ;
819899 }
820- for (auto Pos = Position ; Pos < Params.size (); ++Pos) {
900+ for (auto Pos = PositionInParams ; Pos < Params.size (); ++Pos) {
821901 const auto ¶mType = Params[Pos];
822902 Type ty = paramType.getPlainType ();
823903 if (memberDC && ty->hasTypeParameter ())
@@ -843,12 +923,6 @@ class ExprContextAnalyzer {
843923 if (!canSkip)
844924 break ;
845925 }
846- // If the argument position is out of expeceted number, indicate that
847- // with optional nullptr param.
848- if (Position >= Params.size ()) {
849- if (seenArgs.insert ({Identifier (), CanType ()}).second )
850- recordPossibleParam (nullptr , /* isRequired=*/ false );
851- }
852926 }
853927 }
854928 return !PossibleTypes.empty () || !PossibleParams.empty ();
0 commit comments