Skip to content

Commit d94d925

Browse files
authored
Merge pull request #20066 from rintaro/ide-completion-subscript
[CodeCompletion] Implement context type analysis at subscript position
2 parents 9103db8 + 74356d6 commit d94d925

File tree

3 files changed

+93
-19
lines changed

3 files changed

+93
-19
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3897,15 +3897,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
38973897
return;
38983898

38993899
for (auto *VD : decls) {
3900-
if (!isa<AbstractFunctionDecl>(VD) ||
3900+
if ((!isa<AbstractFunctionDecl>(VD) && !isa<SubscriptDecl>(VD)) ||
39013901
shouldHideDeclFromCompletionResults(VD))
39023902
continue;
39033903
resolver->resolveDeclSignature(VD);
39043904
if (!VD->hasInterfaceType())
39053905
continue;
39063906
Type declaredMemberType = VD->getInterfaceType();
39073907
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD))
3908-
declaredMemberType = AFD->getMethodInterfaceType();
3908+
if (AFD->getDeclContext()->isTypeContext())
3909+
declaredMemberType = AFD->getMethodInterfaceType();
39093910

39103911
auto fnType =
39113912
baseTy->getTypeOfMember(DC.getParentModule(), VD, declaredMemberType);
@@ -3935,8 +3936,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
39353936
}
39363937

39373938
static bool
3938-
collectPossibleParamLists(DeclContext &DC, ApplyExpr *callExpr,
3939-
SmallVectorImpl<FunctionParams> &candidates) {
3939+
collectPossibleParamListsApply(DeclContext &DC, ApplyExpr *callExpr,
3940+
SmallVectorImpl<FunctionParams> &candidates) {
39403941
auto *fnExpr = callExpr->getFn();
39413942

39423943
if (auto type = fnExpr->getType()) {
@@ -3980,6 +3981,24 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
39803981
return !candidates.empty();
39813982
}
39823983

3984+
static bool collectPossibleParamListsSubscript(
3985+
DeclContext &DC, SubscriptExpr *subscriptExpr,
3986+
SmallVectorImpl<FunctionParams> &candidates) {
3987+
if (subscriptExpr->hasDecl()) {
3988+
if (auto SD =
3989+
dyn_cast<SubscriptDecl>(subscriptExpr->getDecl().getDecl())) {
3990+
auto declType = SD->getInterfaceType();
3991+
if (auto *funcType = declType->getAs<AnyFunctionType>())
3992+
candidates.push_back(funcType->getParams());
3993+
}
3994+
} else {
3995+
collectPossibleParamListByQualifiedLookup(DC, subscriptExpr->getBase(),
3996+
DeclBaseName::createSubscript(),
3997+
candidates);
3998+
}
3999+
return !candidates.empty();
4000+
}
4001+
39834002
static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr,
39844003
unsigned &Position, bool &HasName) {
39854004
if (auto TSE = dyn_cast<TupleShuffleExpr>(Args))
@@ -4040,26 +4059,34 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
40404059
}
40414060

40424061
static bool
4043-
collectArgumentExpectation(DeclContext &DC, ApplyExpr *CallE, Expr *CCExpr,
4062+
collectArgumentExpectation(DeclContext &DC, Expr *E, Expr *CCExpr,
40444063
std::vector<Type> &ExpectedTypes,
40454064
std::vector<StringRef> &ExpectedNames) {
40464065
// Collect parameter lists for possible func decls.
40474066
SmallVector<FunctionParams, 4> Candidates;
4048-
if (!collectPossibleParamLists(DC, CallE, Candidates))
4049-
return false;
4067+
Expr *Arg = nullptr;
4068+
if (auto *applyExpr = dyn_cast<ApplyExpr>(E)) {
4069+
if (!collectPossibleParamListsApply(DC, applyExpr, Candidates))
4070+
return false;
4071+
Arg = applyExpr->getArg();
4072+
} else if (auto *subscriptExpr = dyn_cast<SubscriptExpr>(E)) {
4073+
if (!collectPossibleParamListsSubscript(DC, subscriptExpr, Candidates))
4074+
return false;
4075+
Arg = subscriptExpr->getIndex();
4076+
}
40504077

40514078
// Determine the position of code completion token in call argument.
40524079
unsigned Position;
40534080
bool HasName;
4054-
if (!getPositionInArgs(DC, CallE->getArg(), CCExpr, Position, HasName))
4081+
if (!getPositionInArgs(DC, Arg, CCExpr, Position, HasName))
40554082
return false;
4056-
if (!translateArgIndexToParamIndex(CallE->getArg(), Position, HasName))
4083+
if (!translateArgIndexToParamIndex(Arg, Position, HasName))
40574084
return false;
40584085

40594086
// Collect possible types (or labels) at the position.
40604087
{
4061-
bool MayNeedName =
4062-
!HasName && isa<CallExpr>(CallE) && !CallE->isImplicit();
4088+
bool MayNeedName = !HasName && !E->isImplicit() &&
4089+
(isa<CallExpr>(E) | isa<SubscriptExpr>(E));
40634090
SmallPtrSet<TypeBase *, 4> seenTypes;
40644091
SmallPtrSet<Identifier, 4> seenNames;
40654092
for (auto Params : Candidates) {
@@ -5307,11 +5334,13 @@ class CodeCompletionTypeContextAnalyzer {
53075334
case ExprKind::Binary:
53085335
case ExprKind::PrefixUnary:
53095336
case ExprKind::Assign:
5337+
case ExprKind::Subscript:
53105338
return true;
53115339
case ExprKind::Tuple: {
53125340
auto ParentE = Parent.getAsExpr();
53135341
return !ParentE || (!isa<CallExpr>(ParentE) &&
5314-
!isa<BinaryExpr>(ParentE)&&
5342+
!isa<SubscriptExpr>(ParentE) &&
5343+
!isa<BinaryExpr>(ParentE) &&
53155344
!isa<TupleShuffleExpr>(ParentE));
53165345
}
53175346
default:
@@ -5351,13 +5380,13 @@ class CodeCompletionTypeContextAnalyzer {
53515380
SmallVectorImpl<StringRef> &PossibleNames) {
53525381
switch (Parent->getKind()) {
53535382
case ExprKind::Call:
5383+
case ExprKind::Subscript:
53545384
case ExprKind::Binary:
53555385
case ExprKind::PrefixUnary: {
53565386
std::vector<Type> PotentialTypes;
53575387
std::vector<StringRef> ExpectedNames;
53585388
CompletionLookup::collectArgumentExpectation(
5359-
*DC, cast<ApplyExpr>(Parent), ParsedExpr, PotentialTypes,
5360-
ExpectedNames);
5389+
*DC, Parent, ParsedExpr, PotentialTypes, ExpectedNames);
53615390
for (Type Ty : PotentialTypes)
53625391
Callback(Ty);
53635392
for (auto name : ExpectedNames)

lib/Parse/ParseExpr.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,12 +1232,8 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
12321232
/*isPostfix=*/true, isExprBasic, lSquareLoc, indexArgs,
12331233
indexArgLabels, indexArgLabelLocs, rSquareLoc, trailingClosure,
12341234
SyntaxKind::FunctionCallArgumentList);
1235-
if (status.hasCodeCompletion())
1236-
return makeParserCodeCompletionResult<Expr>();
1237-
if (status.isError() || Result.isNull())
1238-
return nullptr;
12391235
Result = makeParserResult(
1240-
Result,
1236+
status | Result,
12411237
SubscriptExpr::create(Context, Result.get(), lSquareLoc, indexArgs,
12421238
indexArgLabels, indexArgLabelLocs, rSquareLoc,
12431239
trailingClosure, ConcreteDeclRef(),

test/IDE/complete_call_arg.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SHUFFLE_2 | %FileCheck %s -check-prefix=SHUFFLE_2
5353
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SHUFFLE_3 | %FileCheck %s -check-prefix=SHUFFLE_3
5454

55+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUBSCRIPT_1 | %FileCheck %s -check-prefix=SUBSCRIPT_1
56+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUBSCRIPT_1_DOT | %FileCheck %s -check-prefix=SUBSCRIPT_1_DOT
57+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUBSCRIPT_2 | %FileCheck %s -check-prefix=SUBSCRIPT_2
58+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUBSCRIPT_2_DOT | %FileCheck %s -check-prefix=SUBSCRIPT_2_DOT
59+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUBSCRIPT_3 | %FileCheck %s -check-prefix=SUBSCRIPT_3
60+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUBSCRIPT_3_DOT | %FileCheck %s -check-prefix=SUBSCRIPT_3_DOT
61+
5562
var i1 = 1
5663
var i2 = 2
5764
var oi1 : Int?
@@ -460,3 +467,45 @@ func testTupleShuffle() {
460467
// SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific: foo[#SimpleEnum#]; name=foo
461468
// SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific: bar[#SimpleEnum#]; name=bar
462469
// SHUFFLE_3-DAG: Decl[EnumElement]/ExprSpecific: baz[#SimpleEnum#]; name=baz
470+
471+
class HasSubscript {
472+
subscript(idx: Int) -> String {}
473+
subscript(idx: Int, default defaultValue: String) -> String {}
474+
}
475+
func testSubscript(obj: HasSubscript, intValue: Int, strValue: String) {
476+
let _ = obj[#^SUBSCRIPT_1^#
477+
// SUBSCRIPT_1: Begin completions
478+
// SUBSCRIPT_1-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: i1[#Int#]; name=i1
479+
// SUBSCRIPT_1-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: i2[#Int#]; name=i2
480+
// SUBSCRIPT_1-DAG: Decl[GlobalVar]/CurrModule: s1[#String#]; name=s1
481+
// SUBSCRIPT_1-DAG: Decl[GlobalVar]/CurrModule: s2[#String#]; name=s2
482+
483+
let _ = obj[.#^SUBSCRIPT_1_DOT^#
484+
// SUBSCRIPT_1_DOT: Begin completions
485+
// SUBSCRIPT_1_DOT-NOT: i1
486+
// SUBSCRIPT_1_DOT-NOT: s1
487+
// SUBSCRIPT_1_DOT-DAG: Decl[StaticVar]/Super: max[#Int#]; name=max
488+
// SUBSCRIPT_1_DOT-DAG: Decl[StaticVar]/Super: min[#Int#]; name=min
489+
490+
let _ = obj[42, #^SUBSCRIPT_2^#
491+
// SUBSCRIPT_2: Begin completions, 1 items
492+
// SUBSCRIPT_2-NEXT: Keyword/ExprSpecific: default: [#Argument name#]; name=default:
493+
494+
let _ = obj[42, .#^SUBSCRIPT_2_DOT^#
495+
// SUBSCRIPT_2_DOT-NOT: Begin completions
496+
497+
let _ = obj[42, default: #^SUBSCRIPT_3^#
498+
// SUBSCRIPT_3: Begin completions
499+
// SUBSCRIPT_3-DAG: Decl[GlobalVar]/CurrModule: i1[#Int#]; name=i1
500+
// SUBSCRIPT_3-DAG: Decl[GlobalVar]/CurrModule: i2[#Int#]; name=i2
501+
// SUBSCRIPT_3-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s1[#String#]; name=s1
502+
// SUBSCRIPT_3-DAG: Decl[GlobalVar]/CurrModule/TypeRelation[Identical]: s2[#String#]; name=s2
503+
504+
let _ = obj[42, default: .#^SUBSCRIPT_3_DOT^#
505+
// SUBSCRIPT_3_DOT: Begin completions
506+
// SUBSCRIPT_3_DOT-NOT: i1
507+
// SUBSCRIPT_3_DOT-NOT: s1
508+
// SUBSCRIPT_3_DOT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init()[#String#]; name=init()
509+
// SUBSCRIPT_3_DOT-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Identical]: init({#(c): Character#})[#String#]; name=init(c: Character)
510+
511+
}

0 commit comments

Comments
 (0)