Skip to content

Commit 5057cb2

Browse files
authored
Merge pull request swiftlang#24867 from rintaro/ide-completion-subscript-rdar28874899
[CodeCompletion] Implement call pattern completion for subscript
2 parents 0218ac8 + 1b688d5 commit 5057cb2

File tree

5 files changed

+141
-17
lines changed

5 files changed

+141
-17
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,15 +2286,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
22862286
Builder.addRightParen();
22872287
}
22882288

2289-
SemanticContextKind getSemanticContextKind(const AbstractFunctionDecl *AFD) {
2289+
SemanticContextKind getSemanticContextKind(const ValueDecl *VD) {
22902290
// FIXME: to get the corect semantic context we need to know how lookup
2291-
// would have found the declaration AFD. For now, just infer a reasonable
2292-
// semantics.
2291+
// would have found the VD. For now, just infer a reasonable semantics.
22932292

2294-
if (!AFD)
2293+
if (!VD)
22952294
return SemanticContextKind::CurrentModule;
22962295

2297-
DeclContext *calleeDC = AFD->getDeclContext();
2296+
DeclContext *calleeDC = VD->getDeclContext();
22982297

22992298
if (calleeDC->isTypeContext())
23002299
// FIXME: We should distinguish CurrentNominal and Super. We need to
@@ -2309,6 +2308,37 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
23092308
return SemanticContextKind::OtherModule;
23102309
}
23112310

2311+
void addSubscriptCallPattern(const AnyFunctionType *AFT,
2312+
const SubscriptDecl *SD) {
2313+
foundFunction(AFT);
2314+
auto genericSig =
2315+
SD->getInnermostDeclContext()->getGenericSignatureOfContext();
2316+
AFT = eraseArchetypes(CurrDeclContext->getParentModule(),
2317+
const_cast<AnyFunctionType *>(AFT), genericSig)
2318+
->castTo<AnyFunctionType>();
2319+
2320+
CommandWordsPairs Pairs;
2321+
CodeCompletionResultBuilder Builder(
2322+
Sink, CodeCompletionResult::ResultKind::Declaration,
2323+
getSemanticContextKind(SD), expectedTypeContext);
2324+
Builder.setAssociatedDecl(SD);
2325+
setClangDeclKeywords(SD, Pairs, Builder);
2326+
if (!HaveLParen)
2327+
Builder.addLeftBracket();
2328+
else
2329+
Builder.addAnnotatedLeftBracket();
2330+
addCallArgumentPatterns(Builder, AFT, SD->getIndices());
2331+
if (!HaveLParen)
2332+
Builder.addRightBracket();
2333+
else
2334+
Builder.addAnnotatedRightBracket();
2335+
if (SD && SD->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
2336+
addTypeAnnotationForImplicitlyUnwrappedOptional(Builder,
2337+
AFT->getResult());
2338+
else
2339+
addTypeAnnotation(Builder, AFT->getResult());
2340+
}
2341+
23122342
void addFunctionCallPattern(const AnyFunctionType *AFT,
23132343
const AbstractFunctionDecl *AFD = nullptr) {
23142344
if (AFD) {
@@ -2328,15 +2358,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
23282358
AFD ? CodeCompletionResult::ResultKind::Declaration
23292359
: CodeCompletionResult::ResultKind::Pattern,
23302360
getSemanticContextKind(AFD), expectedTypeContext);
2331-
if (!HaveLParen)
2332-
Builder.addLeftParen();
2333-
else
2334-
Builder.addAnnotatedLeftParen();
23352361
if (AFD) {
23362362
Builder.setAssociatedDecl(AFD);
23372363
setClangDeclKeywords(AFD, Pairs, Builder);
23382364
}
23392365

2366+
if (!HaveLParen)
2367+
Builder.addLeftParen();
2368+
else
2369+
Builder.addAnnotatedLeftParen();
2370+
23402371
addCallArgumentPatterns(Builder, AFT->getParams(), declParams,
23412372
includeDefaultArgs);
23422373

@@ -5363,9 +5394,15 @@ void CodeCompletionCallbacksImpl::doneParsing() {
53635394
if (ShouldCompleteCallPatternAfterParen &&
53645395
!ContextInfo.getPossibleCallees().empty()) {
53655396
Lookup.setHaveLParen(true);
5366-
for (auto &typeAndDecl : ContextInfo.getPossibleCallees())
5367-
Lookup.tryFunctionCallCompletions(typeAndDecl.first,
5368-
typeAndDecl.second);
5397+
for (auto &typeAndDecl : ContextInfo.getPossibleCallees()) {
5398+
if (auto SD = dyn_cast_or_null<SubscriptDecl>(typeAndDecl.second)) {
5399+
Lookup.addSubscriptCallPattern(typeAndDecl.first, SD);
5400+
} else {
5401+
Lookup.addFunctionCallPattern(
5402+
typeAndDecl.first,
5403+
dyn_cast_or_null<AbstractFunctionDecl>(typeAndDecl.second));
5404+
}
5405+
}
53695406
Lookup.setHaveLParen(false);
53705407

53715408
shouldPerformGlobalCompletion =

lib/IDE/CodeCompletionResultBuilder.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,21 @@ class CodeCompletionResultBuilder {
217217
CodeCompletionString::Chunk::ChunkKind::RightParen, ")");
218218
}
219219

220+
void addAnnotatedLeftBracket() {
221+
addLeftBracket();
222+
getLastChunk().setIsAnnotation();
223+
}
224+
220225
void addLeftBracket() {
221226
addChunkWithTextNoCopy(
222227
CodeCompletionString::Chunk::ChunkKind::LeftBracket, "[");
223228
}
224229

230+
void addAnnotatedRightBracket() {
231+
addRightBracket();
232+
getLastChunk().setIsAnnotation();
233+
}
234+
225235
void addRightBracket() {
226236
addChunkWithTextNoCopy(
227237
CodeCompletionString::Chunk::ChunkKind::RightBracket, "]");

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ static bool collectPossibleCalleesForSubscript(
404404
if (subscriptExpr->hasDecl()) {
405405
if (auto SD = dyn_cast<SubscriptDecl>(subscriptExpr->getDecl().getDecl())) {
406406
auto declType = SD->getInterfaceType();
407+
declType = declType.subst(subscriptExpr->getDecl().getSubstitutions());
407408
if (auto *funcType = declType->getAs<AnyFunctionType>())
408409
candidates.emplace_back(funcType, SD);
409410
}

lib/Parse/ParseExpr.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -925,12 +925,9 @@ ParserResult<Expr> Parser::parseExprSuper(bool isExprBasic) {
925925
rSquareLoc,
926926
trailingClosure,
927927
SyntaxKind::FunctionCallArgumentList);
928-
if (status.hasCodeCompletion())
929-
return makeParserCodeCompletionResult<Expr>();
930-
if (status.isError())
931-
return nullptr;
932928
SyntaxContext->createNodeInPlace(SyntaxKind::SubscriptExpr);
933929
return makeParserResult(
930+
status,
934931
SubscriptExpr::create(Context, superRef, lSquareLoc, indexArgs,
935932
indexArgLabels, indexArgLabelLocs, rSquareLoc,
936933
trailingClosure, ConcreteDeclRef(),

test/IDE/complete_subscript.swift

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_UNRESOLVED | %FileCheck %s -check-prefix=METATYPE_UNRESOLVED
2+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_UNRESOLVED_BRACKET | %FileCheck %s -check-prefix=METATYPE_UNRESOLVED_BRACKET
23
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_INT | %FileCheck %s -check-prefix=METATYPE_INT
4+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_INT_BRACKET | %FileCheck %s -check-prefix=METATYPE_INT_BRACKET
35
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_INT | %FileCheck %s -check-prefix=INSTANCE_INT
6+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_INT_BRACKET | %FileCheck %s -check-prefix=INSTANCE_INT_BRACKET
47
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_ARCHETYPE | %FileCheck %s -check-prefix=METATYPE_ARCHETYPE
8+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_ARCHETYPE_BRACKET | %FileCheck %s -check-prefix=METATYPE_ARCHETYPE_BRACKET
59
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_ARCHETYPE | %FileCheck %s -check-prefix=INSTANCE_ARCHETYPE
10+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_ARCHETYPE_BRACKET | %FileCheck %s -check-prefix=INSTANCE_ARCHETYPE_BRACKET
611
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=METATYPE_LABEL | %FileCheck %s -check-prefix=METATYPE_LABEL
7-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_LABEL | %FileCheck %s -check-prefix=INSTANCE_LABEL
12+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_LABEL | %FileCheck %s -check-prefix=INSTANCE_LABEL
13+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SELF_IN_INSTANCEMETHOD | %FileCheck %s -check-prefix=SELF_IN_INSTANCEMETHOD
14+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUPER_IN_INSTANCEMETHOD | %FileCheck %s -check-prefix=SUPER_IN_INSTANCEMETHOD
15+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SELF_IN_STATICMETHOD | %FileCheck %s -check-prefix=SELF_IN_STATICMETHOD
16+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUPER_IN_STATICMETHOD | %FileCheck %s -check-prefix=SUPER_IN_STATICMETHOD
17+
18+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LABELED_SUBSCRIPT | %FileCheck %s -check-prefix=LABELED_SUBSCRIPT
819

920
struct MyStruct<T> {
1021
static subscript(x: Int, static defValue: T) -> MyStruct<T> {
@@ -24,6 +35,10 @@ func test1() {
2435
// METATYPE_UNRESOLVED-DAG: Keyword/CurrNominal: .Type[#MyStruct<_>.Type#];
2536
// METATYPE_UNRESOLVED: End completions
2637

38+
let _ = MyStruct[#^METATYPE_UNRESOLVED_BRACKET^#
39+
// METATYPE_UNRESOLVED_BRACKET: Begin completions
40+
// METATYPE_UNRESOLVED_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#static: _#}[']'][#MyStruct<_>#];
41+
// METATYPE_UNRESOLVED_BRACKET: End completions
2742

2843
let _ = MyStruct<Int> #^METATYPE_INT^#
2944
// METATYPE_INT: Begin completions, 4 items
@@ -33,12 +48,21 @@ func test1() {
3348
// METATYPE_INT-DAG: Keyword/CurrNominal: .Type[#MyStruct<Int>.Type#];
3449
// METATYPE_INT: End completions
3550

51+
let _ = MyStruct<Int>[#^METATYPE_INT_BRACKET^#
52+
// METATYPE_INT_BRACKET: Begin completions
53+
// METATYPE_INT_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#static: Int#}[']'][#MyStruct<Int>#];
54+
// METATYPE_INT_BRACKET: End completions
55+
3656
let _ = MyStruct<Int>()#^INSTANCE_INT^#
3757
// INSTANCE_INT: Begin completions, 2 items
3858
// INSTANCE_INT-DAG: Decl[Subscript]/CurrNominal: [{#(x): Int#}, {#instance: Int#}][#Int#];
3959
// INSTANCE_INT-DAG: Keyword[self]/CurrNominal: .self[#MyStruct<Int>#];
4060
// INSTANCE_INT: End completions
4161

62+
let _ = MyStruct<Int>()[#^INSTANCE_INT_BRACKET^#
63+
// INSTANCE_INT_BRACKET: Begin completions
64+
// INSTANCE_INT_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#instance: Int#}[']'][#Int#];
65+
// INSTANCE_INT_BRACKET: End completions
4266
}
4367
func test2<U>(value: MyStruct<U>) {
4468
let _ = MyStruct<U>#^METATYPE_ARCHETYPE^#
@@ -49,12 +73,22 @@ func test2<U>(value: MyStruct<U>) {
4973
// METATYPE_ARCHETYPE-DAG: Keyword/CurrNominal: .Type[#MyStruct<U>.Type#];
5074
// METATYPE_ARCHETYPE: End completions
5175

76+
let _ = MyStruct<U>[#^METATYPE_ARCHETYPE_BRACKET^#
77+
// METATYPE_ARCHETYPE_BRACKET: Begin completions
78+
// METATYPE_ARCHETYPE_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#static: U#}[']'][#MyStruct<U>#];
79+
// METATYPE_ARCHETYPE_BRACKET: End completions
80+
5281
let _ = value #^INSTANCE_ARCHETYPE^#
5382
// INSTANCE_ARCHETYPE: Begin completions, 2 items
5483
// INSTANCE_ARCHETYPE-DAG: Decl[Subscript]/CurrNominal: [{#(x): Int#}, {#instance: U#}][#Int#];
5584
// INSTANCE_ARCHETYPE-DAG: Keyword[self]/CurrNominal: .self[#MyStruct<U>#];
5685
// INSTANCE_ARCHETYPE: End completions
5786

87+
let _ = value[#^INSTANCE_ARCHETYPE_BRACKET^#
88+
// INSTANCE_ARCHETYPE_BRACKET: Begin completions
89+
// INSTANCE_ARCHETYPE_BRACKET-DAG: Decl[Subscript]/CurrNominal: ['[']{#(x): Int#}, {#instance: U#}[']'][#Int#];
90+
// INSTANCE_ARCHETYPE_BRACKET: End completions
91+
5892
let _ = MyStruct<U>[42, #^METATYPE_LABEL^#
5993
// METATYPE_LABEL: Begin completions, 1 items
6094
// METATYPE_LABEL-DAG: Keyword/ExprSpecific: static: [#Argument name#];
@@ -65,3 +99,48 @@ func test2<U>(value: MyStruct<U>) {
6599
// INSTANCE_LABEL-DAG: Keyword/ExprSpecific: instance: [#Argument name#];
66100
// INSTANCE_LABEL: End completions
67101
}
102+
103+
class Base {
104+
static subscript(static x: Int) -> Int { return 1 }
105+
subscript(instance x: Int) -> Int { return 1 }
106+
}
107+
class Derived: Base {
108+
static subscript(derivedStatic x: Int) -> Int { return 1 }
109+
subscript(derivedInstance x: Int) -> Int { return 1 }
110+
111+
func testInstance() {
112+
let _ = self[#^SELF_IN_INSTANCEMETHOD^#]
113+
// SELF_IN_INSTANCEMETHOD: Begin completions, 2 items
114+
// SELF_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#derivedInstance: Int#}[']'][#Int#];
115+
// SELF_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#instance: Int#}[']'][#Int#];
116+
// SELF_IN_INSTANCEMETHOD: End completions
117+
118+
let _ = super[#^SUPER_IN_INSTANCEMETHOD^#]
119+
// SUPER_IN_INSTANCEMETHOD: Begin completions, 1 items
120+
// SUPER_IN_INSTANCEMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#instance: Int#}[']'][#Int#];
121+
// SUPER_IN_INSTANCEMETHOD: End completions
122+
}
123+
124+
static func testStatic() {
125+
let _ = self[#^SELF_IN_STATICMETHOD^#]
126+
// SELF_IN_STATICMETHOD: Begin completions, 2 items
127+
// SELF_IN_STATICMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#derivedStatic: Int#}[']'][#Int#];
128+
// SELF_IN_STATICMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#static: Int#}[']'][#Int#];
129+
// SELF_IN_STATICMETHOD: End completions
130+
131+
let _ = super[#^SUPER_IN_STATICMETHOD^#]
132+
// SUPER_IN_STATICMETHOD: Begin completions, 1 items
133+
// SUPER_IN_STATICMETHOD-DAG: Decl[Subscript]/CurrNominal: ['[']{#static: Int#}[']'][#Int#];
134+
// SUPER_IN_STATICMETHOD: End completions
135+
}
136+
}
137+
138+
struct MyStruct1<X: Comparable> {
139+
subscript(idx1 _: Int, idx2 _: X) -> Int! { return 1 }
140+
}
141+
func testSubscriptCallSig<T>(val: MyStruct1<T>) {
142+
val[#^LABELED_SUBSCRIPT^#
143+
// LABELED_SUBSCRIPT: Begin completions, 1 items
144+
// LABELED_SUBSCRIPT: Decl[Subscript]/CurrNominal: ['[']{#idx1: Int#}, {#idx2: Comparable#}[']'][#Int!#];
145+
// LABELED_SUBSCRIPT: End completions
146+
}

0 commit comments

Comments
 (0)