Skip to content

Commit bf4663b

Browse files
authored
Merge pull request #58550 from rintaro/ide-completion-rdar80489548
[CodeCompletion] Suggest 'in' after expression in closure
2 parents 2fa4bf8 + 1e01898 commit bf4663b

File tree

4 files changed

+70
-20
lines changed

4 files changed

+70
-20
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,12 @@ static void addStmtKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
816816
auto AddStmtKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind) {
817817
if (!MaybeFuncBody && Kind == CodeCompletionKeywordKind::kw_return)
818818
return;
819+
820+
// 'in' keyword is added in 'addClosureSignatureKeywordsIfApplicable' if
821+
// needed.
822+
if (Kind == CodeCompletionKeywordKind::kw_in)
823+
return;
824+
819825
addKeyword(Sink, Name, Kind, "", flair);
820826
};
821827
#define STMT_KEYWORD(kw) AddStmtKeyword(#kw, CodeCompletionKeywordKind::kw_##kw);
@@ -896,6 +902,18 @@ static void addAnyTypeKeyword(CodeCompletionResultSink &Sink, Type T) {
896902
Builder.addTypeAnnotation(T, PrintOptions());
897903
}
898904

905+
static void
906+
addClosureSignatureKeywordsIfApplicable(CodeCompletionResultSink &Sink,
907+
DeclContext *DC) {
908+
ClosureExpr *closure = dyn_cast<ClosureExpr>(DC);
909+
if (!closure)
910+
return;
911+
if (closure->getInLoc().isValid())
912+
return;
913+
914+
addKeyword(Sink, "in", CodeCompletionKeywordKind::kw_in);
915+
}
916+
899917
void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
900918
bool MaybeFuncBody) {
901919
switch (Kind) {
@@ -950,6 +968,8 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
950968
addDeclKeywords(Sink, CurDeclContext,
951969
Context.LangOpts.EnableExperimentalConcurrency);
952970
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
971+
addClosureSignatureKeywordsIfApplicable(Sink, CurDeclContext);
972+
953973
LLVM_FALLTHROUGH;
954974
case CompletionKind::ReturnStmtExpr:
955975
case CompletionKind::YieldStmtExpr:
@@ -974,6 +994,11 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
974994
break;
975995

976996
case CompletionKind::PostfixExpr:
997+
// Suggest 'in' for '{ value <HERE>'.
998+
if (HasSpace)
999+
addClosureSignatureKeywordsIfApplicable(Sink, CurDeclContext);
1000+
1001+
break;
9771002
case CompletionKind::CaseStmtBeginning:
9781003
case CompletionKind::TypeIdentifierWithDot:
9791004
case CompletionKind::TypeIdentifierWithoutDot:

test/IDE/complete_at_top_level_library.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ protocol MyProtocol {}
5656
// LIBRARY-DAG: Keyword[repeat]/None/Flair[ExprAtFileScope]: repeat; name=repeat
5757
// LIBRARY-DAG: Keyword[else]/None/Flair[ExprAtFileScope]: else; name=else
5858
// LIBRARY-DAG: Keyword[for]/None/Flair[ExprAtFileScope]: for; name=for
59-
// LIBRARY-DAG: Keyword[in]/None/Flair[ExprAtFileScope]: in; name=in
6059
// LIBRARY-DAG: Keyword[while]/None/Flair[ExprAtFileScope]: while; name=while
6160
// LIBRARY-DAG: Keyword[break]/None/Flair[ExprAtFileScope]: break; name=break
6261
// LIBRARY-DAG: Keyword[continue]/None/Flair[ExprAtFileScope]: continue; name=continue
@@ -133,7 +132,6 @@ protocol MyProtocol {}
133132
// SCRIPT-DAG: Keyword[repeat]/None: repeat; name=repeat
134133
// SCRIPT-DAG: Keyword[else]/None: else; name=else
135134
// SCRIPT-DAG: Keyword[for]/None: for; name=for
136-
// SCRIPT-DAG: Keyword[in]/None: in; name=in
137135
// SCRIPT-DAG: Keyword[while]/None: while; name=while
138136
// SCRIPT-DAG: Keyword[break]/None: break; name=break
139137
// SCRIPT-DAG: Keyword[continue]/None: continue; name=continue

test/IDE/complete_keywords.swift

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
// KW_RETURN: Keyword[return]/None: return{{; name=.+$}}
55
// KW_NO_RETURN-NOT: Keyword[return]
66

7+
// KW_IN: Keyword[in]/None: in{{; name=.+$}}
8+
// KW_NO_IN-NOT: Keyword[in]
9+
710
// KW_DECL: Begin completions
811
// KW_DECL-DAG: Keyword[class]/None: class{{; name=.+$}}
912
// KW_DECL-DAG: Keyword/None: actor{{; name=.+$}}
@@ -161,7 +164,6 @@
161164
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[do]/None: do{{; name=.+$}}
162165
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[else]/None: else{{; name=.+$}}
163166
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[for]/None: for{{; name=.+$}}
164-
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[in]/None: in{{; name=.+$}}
165167
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[while]/None: while{{; name=.+$}}
166168
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[break]/None: break{{; name=.+$}}
167169
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[continue]/None: continue{{; name=.+$}}
@@ -234,7 +236,6 @@
234236
// KW_DECL_STMT-DAG: Keyword[do]/None: do{{; name=.+$}}
235237
// KW_DECL_STMT-DAG: Keyword[else]/None: else{{; name=.+$}}
236238
// KW_DECL_STMT-DAG: Keyword[for]/None: for{{; name=.+$}}
237-
// KW_DECL_STMT-DAG: Keyword[in]/None: in{{; name=.+$}}
238239
// KW_DECL_STMT-DAG: Keyword[while]/None: while{{; name=.+$}}
239240
// KW_DECL_STMT-DAG: Keyword[break]/None: break{{; name=.+$}}
240241
// KW_DECL_STMT-DAG: Keyword[continue]/None: continue{{; name=.+$}}
@@ -306,15 +307,15 @@
306307
// KW_EXPR_NEG-NOT: Keyword{{.*}}break
307308
// KW_EXPR_NEG: End completions
308309

309-
#^TOP_LEVEL_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN^#
310+
#^TOP_LEVEL_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
310311

311312
for _ in 1...10 {
312-
#^TOP_LEVEL_2?check=KW_DECL_STMT;check=KW_NO_RETURN^#
313+
#^TOP_LEVEL_2?check=KW_DECL_STMT;check=KW_NO_RETURN;check=KW_NO_IN^#
313314
}
314315

315-
if true {} #^TOP_LEVEL_AFTER_IF_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN^#
316+
if true {} #^TOP_LEVEL_AFTER_IF_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
316317
if true {}
317-
#^TOP_LEVEL_AFTER_IF_2?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN^#
318+
#^TOP_LEVEL_AFTER_IF_2?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
318319

319320

320321
if true {} else #^TOP_LEVEL_AFTER_IF_ELSE_1?check=AFTER_IF_ELSE^# {}
@@ -323,60 +324,60 @@ if true {} else #^TOP_LEVEL_AFTER_IF_ELSE_1?check=AFTER_IF_ELSE^# {}
323324
// AFTER_IF_ELSE: Keyword[if]/None: if;
324325

325326
func testAfterIf1() {
326-
if true {} #^AFTER_IF_1?check=KW_DECL_STMT;check=KW_RETURN^#
327+
if true {} #^AFTER_IF_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
327328
}
328329
func testAfterIfElse1() {
329330
if true {} else #^AFTER_IF_ELSE_1?check=AFTER_IF_ELSE^# {}
330331
}
331332

332333
func testInFuncBody1() {
333-
#^IN_FUNC_BODY_1?check=KW_DECL_STMT;check=KW_RETURN^#
334+
#^IN_FUNC_BODY_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
334335
}
335336

336337
struct InStructFunc {
337338
func testInFuncBody2() {
338-
#^IN_FUNC_BODY_2?check=KW_DECL_STMT;check=KW_RETURN^#
339+
#^IN_FUNC_BODY_2?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
339340
}
340341
}
341342

342343
enum InEnumFunc {
343344
func testInFuncBody3() {
344-
#^IN_FUNC_BODY_3?check=KW_DECL_STMT;check=KW_RETURN^#
345+
#^IN_FUNC_BODY_3?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
345346
}
346347
}
347348

348349
class InClassFunc {
349350
func testInFuncBody4() {
350-
#^IN_FUNC_BODY_4?check=KW_DECL_STMT;check=KW_RETURN^#
351+
#^IN_FUNC_BODY_4?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
351352
}
352353
}
353354

354355
class InClassFunc {
355356
class Nested {
356357
func testInFuncBody5() {
357-
#^IN_FUNC_BODY_5?check=KW_DECL_STMT;check=KW_RETURN^#
358+
#^IN_FUNC_BODY_5?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
358359
}
359360
}
360361
}
361362

362363
func testInClosure1() {
363-
{ #^IN_CLOSURE_1?check=KW_DECL_STMT;check=KW_RETURN^# }
364+
{ #^IN_CLOSURE_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^# }
364365
}
365366
func testInClosure2() {
366-
{ #^IN_CLOSURE_2?check=KW_DECL_STMT;check=KW_RETURN^#
367+
{ #^IN_CLOSURE_2?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^#
367368
}
368369
struct InVarClosureInit {
369-
let x = { #^IN_CLOSURE_3?check=KW_DECL_STMT;check=KW_RETURN^# }()
370+
let x = { #^IN_CLOSURE_3?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^# }()
370371
}
371372

372-
{ #^IN_CLOSURE_4?check=KW_DECL_STMT;check=KW_RETURN^# }
373+
{ #^IN_CLOSURE_4?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^# }
373374

374375
struct InSubscript {
375-
subscript(x: Int) -> Int { #^IN_SUBSCRIPT_1?check=KW_DECL_STMT;check=KW_RETURN^# }
376+
subscript(x: Int) -> Int { #^IN_SUBSCRIPT_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^# }
376377
}
377378

378379
struct InInit {
379-
init?() { #^IN_INIT_1?check=KW_DECL_STMT;check=KW_RETURN^# }
380+
init?() { #^IN_INIT_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^# }
380381
}
381382

382383
struct InStruct {

test/IDE/complete_rdar80489548.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t.ccp)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
3+
4+
// KW_IN: Keyword[in]/None: in{{; name=.+$}}
5+
// KW_NO_IN-NOT: Keyword[in]
6+
7+
func test(value: [Int]) {
8+
value.map { #^NOIN_IMMEDIATE?check=KW_IN^# }
9+
10+
value.map { value#^NOIN_AFTER_EXPR_NOSPCACE?check=KW_NO_IN^# }
11+
value.map { value #^NOIN_AFTER_EXPR?check=KW_IN^# }
12+
value.map { value
13+
#^NOIN_NEWLINE?check=KW_IN^#
14+
}
15+
16+
value.map { value in #^IN_AFTER_IN?check=KW_NO_IN^# }
17+
value.map { value in
18+
#^IN_NEWLINE?check=KW_NO_IN^#
19+
}
20+
21+
#^FUNCBODY_STMT?check=KW_NO_IN^#
22+
value #^FUNCBODY_POSTFIX?check=KW_NO_IN^#
23+
}
24+
25+
#^GLOBAL_STMT?check=KW_NO_IN^#
26+
value #^GLOBAL_POSTFIX?check=KW_NO_IN^#

0 commit comments

Comments
 (0)