@@ -1390,8 +1390,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
1390
1390
1391
1391
// Figure out the kind of type-check we'll be performing.
1392
1392
auto CheckKind = CompletionTypeCheckKind::Normal;
1393
- if (Kind == CompletionKind::KeyPathExpr ||
1394
- Kind == CompletionKind::KeyPathExprDot)
1393
+ if (Kind == CompletionKind::KeyPathExprObjC)
1395
1394
CheckKind = CompletionTypeCheckKind::KeyPath;
1396
1395
1397
1396
// If we've already successfully type-checked the expression for some
@@ -1444,7 +1443,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
1444
1443
void completePostfixExprParen (Expr *E, Expr *CodeCompletionE) override ;
1445
1444
void completeExprSuper (SuperRefExpr *SRE) override ;
1446
1445
void completeExprSuperDot (SuperRefExpr *SRE) override ;
1447
- void completeExprKeyPath (KeyPathExpr *KPE, bool HasDot ) override ;
1446
+ void completeExprKeyPath (KeyPathExpr *KPE, SourceLoc DotLoc ) override ;
1448
1447
1449
1448
void completeTypeSimpleBeginning () override ;
1450
1449
void completeTypeIdentifierWithDot (IdentTypeRepr *ITR) override ;
@@ -1619,6 +1618,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
1619
1618
bool IsSelfRefExpr = false ;
1620
1619
bool IsKeyPathExpr = false ;
1621
1620
bool IsSwiftKeyPathExpr = false ;
1621
+ bool IsAfterSwiftKeyPathRoot = false ;
1622
1622
bool IsDynamicLookup = false ;
1623
1623
bool PreferFunctionReferencesToCalls = false ;
1624
1624
bool HaveLeadingSpace = false ;
@@ -1777,8 +1777,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
1777
1777
IsKeyPathExpr = true ;
1778
1778
}
1779
1779
1780
- void setIsSwiftKeyPathExpr () {
1780
+ void setIsSwiftKeyPathExpr (bool onRoot ) {
1781
1781
IsSwiftKeyPathExpr = true ;
1782
+ IsAfterSwiftKeyPathRoot = onRoot;
1782
1783
}
1783
1784
1784
1785
void setIsDynamicLookup () {
@@ -2625,21 +2626,33 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
2625
2626
}
2626
2627
}
2627
2628
2628
- bool shouldAddSubscriptCall () {
2629
- if (IsSwiftKeyPathExpr)
2630
- return true ;
2631
- return !HaveDot;
2632
- }
2633
-
2634
2629
void addSubscriptCall (const SubscriptDecl *SD, DeclVisibilityKind Reason) {
2635
- assert (shouldAddSubscriptCall () && " cannot add a subscript after a dot" );
2630
+ // Don't add subscript call to meta types.
2631
+ if (!ExprType || ExprType->is <AnyMetatypeType>())
2632
+ return ;
2633
+
2634
+ // Subscript after '.' is valid only after type part of Swift keypath
2635
+ // expression. (e.g. '\TyName.SubTy.[0])
2636
+ if (HaveDot && !IsAfterSwiftKeyPathRoot)
2637
+ return ;
2638
+
2636
2639
CommandWordsPairs Pairs;
2637
2640
CodeCompletionResultBuilder Builder (
2638
2641
Sink,
2639
2642
CodeCompletionResult::ResultKind::Declaration,
2640
2643
getSemanticContext (SD, Reason), ExpectedTypes);
2641
2644
Builder.setAssociatedDecl (SD);
2642
2645
setClangDeclKeywords (SD, Pairs, Builder);
2646
+
2647
+ // '\TyName#^TOKEN^#' requires leading dot.
2648
+ if (!HaveDot && IsAfterSwiftKeyPathRoot)
2649
+ Builder.addLeadingDot ();
2650
+
2651
+ if (NeedOptionalUnwrap) {
2652
+ Builder.setNumBytesToErase (NumBytesToEraseForOptionalUnwrap);
2653
+ Builder.addQuestionMark ();
2654
+ }
2655
+
2643
2656
Builder.addLeftBracket ();
2644
2657
addParameters (Builder, SD->getIndices ());
2645
2658
Builder.addRightBracket ();
@@ -2973,12 +2986,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
2973
2986
}
2974
2987
2975
2988
// Swift key path allows .[0]
2976
- if (shouldAddSubscriptCall ()) {
2977
- if (auto *SD = dyn_cast<SubscriptDecl>(D)) {
2978
- if (ExprType && !ExprType->is <AnyMetatypeType>())
2979
- addSubscriptCall (SD, Reason);
2980
- return ;
2981
- }
2989
+ if (auto *SD = dyn_cast<SubscriptDecl>(D)) {
2990
+ addSubscriptCall (SD, Reason);
2991
+ return ;
2982
2992
}
2983
2993
return ;
2984
2994
@@ -4352,8 +4362,6 @@ void CodeCompletionCallbacksImpl::completeDotExpr(Expr *E, SourceLoc DotLoc) {
4352
4362
return ;
4353
4363
4354
4364
Kind = CompletionKind::DotExpr;
4355
- if (E->getKind () == ExprKind::KeyPath)
4356
- Kind = CompletionKind::SwiftKeyPath;
4357
4365
if (ParseExprSelectorContext != ObjCSelectorContext::None) {
4358
4366
PreferFunctionReferencesToCalls = true ;
4359
4367
CompleteExprSelectorContext = ParseExprSelectorContext;
@@ -4474,9 +4482,11 @@ void CodeCompletionCallbacksImpl::completeExprSuperDot(SuperRefExpr *SRE) {
4474
4482
}
4475
4483
4476
4484
void CodeCompletionCallbacksImpl::completeExprKeyPath (KeyPathExpr *KPE,
4477
- bool HasDot) {
4478
- Kind = HasDot ? CompletionKind::KeyPathExprDot : CompletionKind::KeyPathExpr;
4485
+ SourceLoc DotLoc) {
4486
+ Kind = (!KPE || KPE->isObjC ()) ? CompletionKind::KeyPathExprObjC
4487
+ : CompletionKind::KeyPathExprSwift;
4479
4488
ParsedExpr = KPE;
4489
+ this ->DotLoc = DotLoc;
4480
4490
CurDeclContext = P.CurDeclContext ;
4481
4491
}
4482
4492
@@ -4737,9 +4747,8 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
4737
4747
case CompletionKind::CallArg:
4738
4748
case CompletionKind::AfterPound:
4739
4749
case CompletionKind::GenericParams:
4740
- case CompletionKind::KeyPathExpr:
4741
- case CompletionKind::KeyPathExprDot:
4742
- case CompletionKind::SwiftKeyPath:
4750
+ case CompletionKind::KeyPathExprObjC:
4751
+ case CompletionKind::KeyPathExprSwift:
4743
4752
break ;
4744
4753
4745
4754
case CompletionKind::StmtOrExpr:
@@ -5135,8 +5144,7 @@ void CodeCompletionCallbacksImpl::doneParsing() {
5135
5144
5136
5145
if (!ExprType && Kind != CompletionKind::PostfixExprParen &&
5137
5146
Kind != CompletionKind::CallArg &&
5138
- Kind != CompletionKind::KeyPathExpr &&
5139
- Kind != CompletionKind::KeyPathExprDot)
5147
+ Kind != CompletionKind::KeyPathExprObjC)
5140
5148
return ;
5141
5149
}
5142
5150
@@ -5190,17 +5198,32 @@ void CodeCompletionCallbacksImpl::doneParsing() {
5190
5198
break ;
5191
5199
}
5192
5200
5193
- case CompletionKind::SwiftKeyPath: {
5194
- Lookup.setHaveDot (DotLoc);
5195
- Lookup.setIsSwiftKeyPathExpr ();
5196
- if (auto BGT = (*ExprType)->getAs <BoundGenericType>()) {
5197
- auto AllArgs = BGT->getGenericArgs ();
5198
- if (AllArgs.size () == 2 ) {
5199
- // The second generic type argument of KeyPath<Root, Value> should be
5200
- // the value we pull code completion results from.
5201
- Lookup.getValueExprCompletions (AllArgs[1 ]);
5202
- }
5201
+ case CompletionKind::KeyPathExprSwift: {
5202
+ auto KPE = dyn_cast<KeyPathExpr>(ParsedExpr);
5203
+ auto BGT = (*ExprType)->getAs <BoundGenericType>();
5204
+ if (!KPE || !BGT || BGT->getGenericArgs ().size () != 2 )
5205
+ break ;
5206
+ assert (!KPE->isObjC ());
5207
+
5208
+ if (DotLoc.isValid ())
5209
+ Lookup.setHaveDot (DotLoc);
5210
+
5211
+ bool OnRoot = !KPE->getComponents ().front ().isValid ();
5212
+ Lookup.setIsSwiftKeyPathExpr (OnRoot);
5213
+
5214
+ auto ParsedType = BGT->getGenericArgs ()[1 ];
5215
+ auto Components = KPE->getComponents ();
5216
+ if (Components.back ().getKind () ==
5217
+ KeyPathExpr::Component::Kind::OptionalWrap) {
5218
+ // KeyPath expr with '?' (e.g. '\Ty.[0].prop?.another').
5219
+ // Althogh expected type is optional, we should unwrap it because it's
5220
+ // unwrapped.
5221
+ ParsedType = ParsedType->getOptionalObjectType ();
5203
5222
}
5223
+
5224
+ // The second generic type argument of KeyPath<Root, Value> should be
5225
+ // the value we pull code completion results from.
5226
+ Lookup.getValueExprCompletions (ParsedType);
5204
5227
break ;
5205
5228
}
5206
5229
@@ -5276,11 +5299,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
5276
5299
break ;
5277
5300
}
5278
5301
5279
- case CompletionKind::KeyPathExprDot:
5280
- Lookup.setHaveDot (SourceLoc ());
5281
- LLVM_FALLTHROUGH;
5282
-
5283
- case CompletionKind::KeyPathExpr: {
5302
+ case CompletionKind::KeyPathExprObjC: {
5303
+ if (DotLoc.isValid ())
5304
+ Lookup.setHaveDot (DotLoc);
5284
5305
Lookup.setIsKeyPathExpr ();
5285
5306
Lookup.includeInstanceMembers ();
5286
5307
0 commit comments