Skip to content

Commit 7b4db90

Browse files
committed
[CodeCompletion] Complete at the top of accessor block in body parsing
If a CC token is right after the '{' we still don't know it's an implicit getter or a start of a accessor block. Previously, the parser used to parse it as an accessor block, but it prevents fast-completion kicks in. Instead handle it as a part of function body parsing so the fast-completion works. rdar://problem/58851121
1 parent acbc913 commit 7b4db90

File tree

3 files changed

+62
-29
lines changed

3 files changed

+62
-29
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5457,35 +5457,18 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
54575457
AccessorCtx.reset();
54585458

54595459
if (Tok.is(tok::code_complete)) {
5460-
if (CodeCompletion) {
5461-
CodeCompletionExpr *CCE = nullptr;
5462-
if (IsFirstAccessor && !parsingLimitedSyntax) {
5463-
// If CC token is the first token after '{', it might be implicit
5464-
// getter. Set up dummy accessor as the decl context to populate
5465-
// 'self' decl.
5466-
5467-
// FIXME: if there is already code inside the body, we should fall
5468-
// through to parseImplicitGetter and handle the completion there so
5469-
// that we can differentiate a single-expression body from the first
5470-
// expression in a multi-statement body.
5471-
auto getter = createAccessorFunc(
5472-
accessors.LBLoc, /*ValueNamePattern*/ nullptr, GenericParams,
5473-
Indices, StaticLoc, Flags, AccessorKind::Get,
5474-
storage, this, /*AccessorKeywordLoc*/ SourceLoc());
5475-
CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
5476-
getter->setBodyParsed(BraceStmt::create(Context, Tok.getLoc(),
5477-
ASTNode(CCE), Tok.getLoc(),
5478-
/*implicit*/ true));
5479-
accessors.add(getter);
5480-
CodeCompletion->setParsedDecl(getter);
5481-
} else {
5460+
// Handle code completion here only if it's not the first accessor.
5461+
// If it's the first accessor, it's handled in function body parsing
5462+
// because it might be an implicit getter.
5463+
if (!IsFirstAccessor || parsingLimitedSyntax) {
5464+
if (CodeCompletion) {
54825465
CodeCompletion->setParsedDecl(storage);
5466+
CodeCompletion->completeAccessorBeginning(nullptr);
54835467
}
5484-
CodeCompletion->completeAccessorBeginning(CCE);
5468+
consumeToken(tok::code_complete);
5469+
accessorHasCodeCompletion = true;
5470+
break;
54855471
}
5486-
consumeToken(tok::code_complete);
5487-
accessorHasCodeCompletion = true;
5488-
break;
54895472
}
54905473

54915474
// parsingLimitedSyntax mode cannot have a body.
@@ -6348,6 +6331,23 @@ Parser::parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD) {
63486331
if (Context.Stats)
63496332
Context.Stats->getFrontendCounters().NumFunctionsParsed++;
63506333

6334+
// In implicit getter, if a CC token is the first token after '{', it might
6335+
// be a start of an accessor block. Perform special completion for that.
6336+
if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
6337+
if (peekToken().is(tok::code_complete) && accessor->isImplicitGetter()) {
6338+
SourceLoc LBraceLoc, RBraceLoc;
6339+
LBraceLoc = consumeToken(tok::l_brace);
6340+
auto *CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
6341+
CodeCompletion->setParsedDecl(accessor);
6342+
CodeCompletion->completeAccessorBeginning(CCE);
6343+
RBraceLoc = Tok.getLoc();
6344+
consumeToken(tok::code_complete);
6345+
return makeParserCodeCompletionResult(
6346+
BraceStmt::create(Context, LBraceLoc, ASTNode(CCE), RBraceLoc,
6347+
/*implicit*/ true));
6348+
}
6349+
}
6350+
63516351
return parseBraceItemList(diag::invalid_diagnostic);
63526352
}
63536353

test/IDE/complete_single_expression_return.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ struct TestSingleExprSubscriptGlobal {
555555
}
556556

557557
// TestSingleExprSubscriptGlobal: Begin completions
558-
// TestSingleExprSubscriptGlobal-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
559-
// TestSingleExprSubscriptGlobal-DAG: Decl[InstanceMethod]/CurrNominal: int()[#Int#];
558+
// TestSingleExprSubscriptGlobal-DAG: Decl[InstanceMethod]/CurrNominal: str()[#String#];
559+
// TestSingleExprSubscriptGlobal-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: int()[#Int#];
560560
// TestSingleExprSubscriptGlobal-DAG: Decl[InstanceMethod]/CurrNominal: void()[#Void#];
561561
// TestSingleExprSubscriptGlobal: End completions
562562
}

test/SourceKit/CodeComplete/complete_sequence_accessor.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ enum S {
4747
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=27:15 %s -- %s == \
4848
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=30:9 %s -- %s == \
4949
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=33:15 %s -- %s == \
50-
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=34:15 %s -- %s > %t.response
50+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=34:15 %s -- %s == \
51+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=12:1 %s -- %s == \
52+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=23:1 %s -- %s == \
53+
// RUN: -req=complete -req-opts=reuseastcontext=1 -pos=16:1 %s -- %s > %t.response
5154
// RUN: %FileCheck --check-prefix=RESULT %s < %t.response
5255
// RUN: %FileCheck --check-prefix=TRACE %s < %t.response
5356

@@ -114,6 +117,30 @@ enum S {
114117
// RESULT-DAG: key.name: "a"
115118
// RESULT-DAG: key.name: "b"
116119
// RESULT: ]
120+
// accessor top (global var)
121+
// RESULT-LABEL: key.results: [
122+
// RESULT-DAG: key.description: "get"
123+
// RESULT-DAG: key.description: "set"
124+
// RESULT-DAG: key.description: "willSet"
125+
// RESULT-DAG: key.description: "didSet"
126+
// RESULT-DAG: key.description: "Foo"
127+
// RESULT: ]
128+
// accessor top (property)
129+
// RESULT-LABEL: key.results: [
130+
// RESULT-DAG: key.description: "get"
131+
// RESULT-DAG: key.description: "set"
132+
// RESULT-DAG: key.description: "willSet"
133+
// RESULT-DAG: key.description: "didSet"
134+
// RESULT-DAG: key.description: "Foo"
135+
// RESULT: ]
136+
// accessor second (global var)
137+
// RESULT-LABEL: key.results: [
138+
// RESULT-NOT: key.description: "Foo"
139+
// RESULT-DAG: key.description: "get"
140+
// RESULT-DAG: key.description: "set"
141+
// RESULT-DAG: key.description: "willSet"
142+
// RESULT-DAG: key.description: "didSet"
143+
// RESULT: ]
117144

118145

119146
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
@@ -134,3 +161,9 @@ enum S {
134161
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
135162
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
136163
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
164+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
165+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
166+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
167+
// TRACE: key.description: "completion reusing previous ASTContext (benign diagnostic)"
168+
// TRACE-LABEL: key.notification: source.notification.compile-did-finish,
169+
// TRACE-NOT: key.description: "completion reusing previous ASTContext (benign diagnostic)"

0 commit comments

Comments
 (0)