Skip to content

Commit cb28676

Browse files
authored
Merge pull request #58874 from rintaro/5.7-ide-completion-rdar80489548
[5.7][CodeCompletion] Suggest 'in' after expression in closure
2 parents 74099ee + 2e89396 commit cb28676

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
@@ -824,6 +824,12 @@ static void addStmtKeywords(CodeCompletionResultSink &Sink, DeclContext *DC,
824824
auto AddStmtKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind) {
825825
if (!MaybeFuncBody && Kind == CodeCompletionKeywordKind::kw_return)
826826
return;
827+
828+
// 'in' keyword is added in 'addClosureSignatureKeywordsIfApplicable' if
829+
// needed.
830+
if (Kind == CodeCompletionKeywordKind::kw_in)
831+
return;
832+
827833
addKeyword(Sink, Name, Kind, "", flair);
828834
};
829835
#define STMT_KEYWORD(kw) AddStmtKeyword(#kw, CodeCompletionKeywordKind::kw_##kw);
@@ -904,6 +910,18 @@ static void addAnyTypeKeyword(CodeCompletionResultSink &Sink, Type T) {
904910
Builder.addTypeAnnotation(T, PrintOptions());
905911
}
906912

913+
static void
914+
addClosureSignatureKeywordsIfApplicable(CodeCompletionResultSink &Sink,
915+
DeclContext *DC) {
916+
ClosureExpr *closure = dyn_cast<ClosureExpr>(DC);
917+
if (!closure)
918+
return;
919+
if (closure->getInLoc().isValid())
920+
return;
921+
922+
addKeyword(Sink, "in", CodeCompletionKeywordKind::kw_in);
923+
}
924+
907925
void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
908926
bool MaybeFuncBody) {
909927
switch (Kind) {
@@ -958,6 +976,8 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
958976
addDeclKeywords(Sink, CurDeclContext,
959977
Context.LangOpts.EnableExperimentalConcurrency);
960978
addStmtKeywords(Sink, CurDeclContext, MaybeFuncBody);
979+
addClosureSignatureKeywordsIfApplicable(Sink, CurDeclContext);
980+
961981
LLVM_FALLTHROUGH;
962982
case CompletionKind::ReturnStmtExpr:
963983
case CompletionKind::YieldStmtExpr:
@@ -982,6 +1002,11 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
9821002
break;
9831003

9841004
case CompletionKind::PostfixExpr:
1005+
// Suggest 'in' for '{ value <HERE>'.
1006+
if (HasSpace)
1007+
addClosureSignatureKeywordsIfApplicable(Sink, CurDeclContext);
1008+
1009+
break;
9851010
case CompletionKind::CaseStmtBeginning:
9861011
case CompletionKind::TypeIdentifierWithDot:
9871012
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: convenience{{; name=.+$}}
@@ -157,7 +160,6 @@
157160
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[do]/None: do{{; name=.+$}}
158161
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[else]/None: else{{; name=.+$}}
159162
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[for]/None: for{{; name=.+$}}
160-
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[in]/None: in{{; name=.+$}}
161163
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[while]/None: while{{; name=.+$}}
162164
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[break]/None: break{{; name=.+$}}
163165
// KW_DECL_STMT_TOPLEVEL-DAG: Keyword[continue]/None: continue{{; name=.+$}}
@@ -230,7 +232,6 @@
230232
// KW_DECL_STMT-DAG: Keyword[do]/None: do{{; name=.+$}}
231233
// KW_DECL_STMT-DAG: Keyword[else]/None: else{{; name=.+$}}
232234
// KW_DECL_STMT-DAG: Keyword[for]/None: for{{; name=.+$}}
233-
// KW_DECL_STMT-DAG: Keyword[in]/None: in{{; name=.+$}}
234235
// KW_DECL_STMT-DAG: Keyword[while]/None: while{{; name=.+$}}
235236
// KW_DECL_STMT-DAG: Keyword[break]/None: break{{; name=.+$}}
236237
// KW_DECL_STMT-DAG: Keyword[continue]/None: continue{{; name=.+$}}
@@ -302,15 +303,15 @@
302303
// KW_EXPR_NEG-NOT: Keyword{{.*}}break
303304
// KW_EXPR_NEG: End completions
304305

305-
#^TOP_LEVEL_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN^#
306+
#^TOP_LEVEL_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
306307

307308
for _ in 1...10 {
308-
#^TOP_LEVEL_2?check=KW_DECL_STMT;check=KW_NO_RETURN^#
309+
#^TOP_LEVEL_2?check=KW_DECL_STMT;check=KW_NO_RETURN;check=KW_NO_IN^#
309310
}
310311

311-
if true {} #^TOP_LEVEL_AFTER_IF_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN^#
312+
if true {} #^TOP_LEVEL_AFTER_IF_1?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
312313
if true {}
313-
#^TOP_LEVEL_AFTER_IF_2?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN^#
314+
#^TOP_LEVEL_AFTER_IF_2?check=KW_DECL_STMT_TOPLEVEL;check=KW_NO_RETURN;check=KW_NO_IN^#
314315

315316

316317
if true {} else #^TOP_LEVEL_AFTER_IF_ELSE_1?check=AFTER_IF_ELSE^# {}
@@ -319,60 +320,60 @@ if true {} else #^TOP_LEVEL_AFTER_IF_ELSE_1?check=AFTER_IF_ELSE^# {}
319320
// AFTER_IF_ELSE: Keyword[if]/None: if;
320321

321322
func testAfterIf1() {
322-
if true {} #^AFTER_IF_1?check=KW_DECL_STMT;check=KW_RETURN^#
323+
if true {} #^AFTER_IF_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
323324
}
324325
func testAfterIfElse1() {
325326
if true {} else #^AFTER_IF_ELSE_1?check=AFTER_IF_ELSE^# {}
326327
}
327328

328329
func testInFuncBody1() {
329-
#^IN_FUNC_BODY_1?check=KW_DECL_STMT;check=KW_RETURN^#
330+
#^IN_FUNC_BODY_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
330331
}
331332

332333
struct InStructFunc {
333334
func testInFuncBody2() {
334-
#^IN_FUNC_BODY_2?check=KW_DECL_STMT;check=KW_RETURN^#
335+
#^IN_FUNC_BODY_2?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
335336
}
336337
}
337338

338339
enum InEnumFunc {
339340
func testInFuncBody3() {
340-
#^IN_FUNC_BODY_3?check=KW_DECL_STMT;check=KW_RETURN^#
341+
#^IN_FUNC_BODY_3?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
341342
}
342343
}
343344

344345
class InClassFunc {
345346
func testInFuncBody4() {
346-
#^IN_FUNC_BODY_4?check=KW_DECL_STMT;check=KW_RETURN^#
347+
#^IN_FUNC_BODY_4?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
347348
}
348349
}
349350

350351
class InClassFunc {
351352
class Nested {
352353
func testInFuncBody5() {
353-
#^IN_FUNC_BODY_5?check=KW_DECL_STMT;check=KW_RETURN^#
354+
#^IN_FUNC_BODY_5?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^#
354355
}
355356
}
356357
}
357358

358359
func testInClosure1() {
359-
{ #^IN_CLOSURE_1?check=KW_DECL_STMT;check=KW_RETURN^# }
360+
{ #^IN_CLOSURE_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^# }
360361
}
361362
func testInClosure2() {
362-
{ #^IN_CLOSURE_2?check=KW_DECL_STMT;check=KW_RETURN^#
363+
{ #^IN_CLOSURE_2?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^#
363364
}
364365
struct InVarClosureInit {
365-
let x = { #^IN_CLOSURE_3?check=KW_DECL_STMT;check=KW_RETURN^# }()
366+
let x = { #^IN_CLOSURE_3?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^# }()
366367
}
367368

368-
{ #^IN_CLOSURE_4?check=KW_DECL_STMT;check=KW_RETURN^# }
369+
{ #^IN_CLOSURE_4?check=KW_DECL_STMT;check=KW_RETURN;check=KW_IN^# }
369370

370371
struct InSubscript {
371-
subscript(x: Int) -> Int { #^IN_SUBSCRIPT_1?check=KW_DECL_STMT;check=KW_RETURN^# }
372+
subscript(x: Int) -> Int { #^IN_SUBSCRIPT_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^# }
372373
}
373374

374375
struct InInit {
375-
init?() { #^IN_INIT_1?check=KW_DECL_STMT;check=KW_RETURN^# }
376+
init?() { #^IN_INIT_1?check=KW_DECL_STMT;check=KW_RETURN;check=KW_NO_IN^# }
376377
}
377378

378379
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)