@@ -745,6 +745,79 @@ static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr,
745
745
return false ;
746
746
}
747
747
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
+
748
821
// / Given an expression and its context, the analyzer tries to figure out the
749
822
// / expected type of the expression by analyzing its context.
750
823
class ExprContextAnalyzer {
@@ -791,14 +864,12 @@ class ExprContextAnalyzer {
791
864
PossibleCallees.assign (Candidates.begin (), Candidates.end ());
792
865
793
866
// Determine the position of code completion token in call argument.
794
- unsigned Position ;
867
+ unsigned PositionInArgs ;
795
868
bool HasName;
796
- if (!getPositionInArgs (*DC, Arg, ParsedExpr, Position , HasName))
869
+ if (!getPositionInArgs (*DC, Arg, ParsedExpr, PositionInArgs , HasName))
797
870
return false ;
798
871
799
872
// 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'
802
873
{
803
874
bool MayNeedName = !HasName && !E->isImplicit () &&
804
875
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
@@ -811,13 +882,22 @@ class ExprContextAnalyzer {
811
882
memberDC = typeAndDecl.Decl ->getInnermostDeclContext ();
812
883
813
884
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
+ }
814
894
ParameterList *paramList = nullptr ;
815
895
if (auto VD = typeAndDecl.Decl ) {
816
896
paramList = getParameterList (VD);
817
897
if (paramList && paramList->size () != Params.size ())
818
898
paramList = nullptr ;
819
899
}
820
- for (auto Pos = Position ; Pos < Params.size (); ++Pos) {
900
+ for (auto Pos = PositionInParams ; Pos < Params.size (); ++Pos) {
821
901
const auto ¶mType = Params[Pos];
822
902
Type ty = paramType.getPlainType ();
823
903
if (memberDC && ty->hasTypeParameter ())
@@ -843,12 +923,6 @@ class ExprContextAnalyzer {
843
923
if (!canSkip)
844
924
break ;
845
925
}
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
- }
852
926
}
853
927
}
854
928
return !PossibleTypes.empty () || !PossibleParams.empty ();
0 commit comments