Skip to content

Commit 5bbc06b

Browse files
committed
[CodeCompletion] Fix override completion parser lookback issues
This allows us to get override completions correct when * There are multiple decls on one line * The preceding attributes/keywords span multiple lines Resolving a longstanding FIXME.
1 parent fcb3a2c commit 5bbc06b

File tree

3 files changed

+84
-17
lines changed

3 files changed

+84
-17
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,10 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
19221922
ParserStatus Status;
19231923

19241924
while (1) {
1925+
// Save the original token, in case code-completion needs it.
1926+
auto OrigTok = Tok;
1927+
bool MayNeedOverrideCompletion = false;
1928+
19251929
switch (Tok.getKind()) {
19261930
// Modifiers
19271931
case tok::kw_static:
@@ -2079,6 +2083,7 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
20792083
Status = parseDeclVar(Flags, Attributes, Entries, StaticLoc,
20802084
StaticSpelling, tryLoc);
20812085
StaticLoc = SourceLoc(); // we handled static if present.
2086+
MayNeedOverrideCompletion = true;
20822087
break;
20832088
case tok::kw_typealias:
20842089
case tok::kw_associatedtype:
@@ -2140,6 +2145,7 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
21402145
DeclResult = parseDeclFunc(StaticLoc, StaticSpelling, Flags, Attributes);
21412146
Status = DeclResult;
21422147
StaticLoc = SourceLoc(); // we handled static if present.
2148+
MayNeedOverrideCompletion = true;
21432149
break;
21442150

21452151
case tok::kw_subscript:
@@ -2149,26 +2155,38 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
21492155
StaticLoc = SourceLoc();
21502156
}
21512157
Status = parseDeclSubscript(Flags, Attributes, Entries);
2158+
MayNeedOverrideCompletion = true;
21522159
break;
21532160

21542161
case tok::code_complete:
2162+
MayNeedOverrideCompletion = true;
2163+
Status.setIsParseError();
2164+
// Handled below.
2165+
break;
2166+
}
2167+
2168+
if (Status.isError() && MayNeedOverrideCompletion &&
2169+
Tok.is(tok::code_complete)) {
21552170
Status = makeParserCodeCompletionStatus();
21562171
if (CodeCompletion) {
2157-
// if we need to complete an override, we need to collect which keywords
2158-
// have already been specified by the developer; so that we do not
2159-
// duplicate them in code completion strings
2172+
// If we need to complete an override, collect the keywords already
2173+
// specifiedso that we do not duplicate them in code completion strings.
21602174
SmallVector<StringRef, 3> Keywords;
2161-
2162-
// FIXME: need to handle the case where this line contains multiple decls
2163-
backtrackToPosition(ParserPosition(L->getStateForBeginningOfTokenLoc(
2164-
Lexer::getLocForStartOfLine(SourceMgr, Tok.getLoc())), SourceLoc()));
2165-
while (!Tok.is(tok::code_complete)) {
2166-
Keywords.push_back(Tok.getText());
2167-
consumeToken();
2175+
switch (OrigTok.getKind()) {
2176+
case tok::kw_func:
2177+
case tok::kw_subscript:
2178+
case tok::kw_var:
2179+
Keywords.push_back(OrigTok.getText());
2180+
break;
2181+
default:
2182+
// Other tokens are already accounted for.
2183+
break;
2184+
}
2185+
for (auto attr : Attributes) {
2186+
Keywords.push_back(attr->getAttrName());
21682187
}
21692188
CodeCompletion->completeNominalMemberBeginning(Keywords);
21702189
}
2171-
break;
21722190
}
21732191

21742192
// If we 'break' out of the switch, break out of the loop too.

test/IDE/complete_override.swift

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@
8181
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NESTED_NOMINAL -code-completion-keywords=false > %t.txt
8282
// RUN: FileCheck %s -check-prefix=NESTED_NOMINAL < %t.txt
8383

84+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NESTED_CLOSURE_1 -code-completion-keywords=false | FileCheck %s -check-prefix=NESTED_CLOSURE_1
85+
8486
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD1 -code-completion-keywords=false > %t.txt
8587
// RUN: FileCheck %s -check-prefix=OMIT_KEYWORD1< %t.txt
8688

@@ -91,6 +93,12 @@
9193
// RUN: FileCheck %s -check-prefix=OMIT_KEYWORD3< %t.txt
9294

9395
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD4 -code-completion-keywords=false | FileCheck %s -check-prefix=OMIT_KEYWORD4
96+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD5 -code-completion-keywords=false | FileCheck %s -check-prefix=OMIT_KEYWORD1
97+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD6 -code-completion-keywords=false | FileCheck %s -check-prefix=OMIT_KEYWORD2
98+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD7 -code-completion-keywords=false | FileCheck %s -check-prefix=OMIT_KEYWORD3
99+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD8 -code-completion-keywords=false | FileCheck %s -check-prefix=OMIT_KEYWORD4
100+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD9 -code-completion-keywords=false | FileCheck %s -check-prefix=OMIT_KEYWORD4
101+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OMIT_KEYWORD10 -code-completion-keywords=false | FileCheck %s -check-prefix=WITH_PA
94102

95103
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=HAS_THROWING -code-completion-keywords=false | FileCheck %s -check-prefix=HAS_THROWING
96104

@@ -350,6 +358,12 @@ class OuterNominal : ProtocolA {
350358
// NESTED_NOMINAL: found code completion token
351359
// NESTED_NOMINAL-NOT: Begin completions
352360

361+
class OuterNominal2: ProtocolA {
362+
var f = { #^NESTED_CLOSURE_1^# }()
363+
}
364+
// NESTED_CLOSURE_1-NOT: Decl{{.*}}/Super
365+
// NESTED_CLOSURE_1-NOT: {|}
366+
353367
class OmitKW1 : ProtocolA {
354368
override#^OMIT_KEYWORD1^#
355369
}
@@ -378,11 +392,13 @@ class OmitKW3 : ProtocolA {
378392
func#^OMIT_KEYWORD3^#
379393
}
380394

381-
//OMIT_KEYWORD3: Begin completions
382-
//OMIT_KEYWORD3-DAG: Decl[Constructor]/Super: init(fromProtocolA: Int) {|}; name=init(fromProtocolA: Int){{$}}
383-
//OMIT_KEYWORD3-DAG: Decl[InstanceMethod]/Super: protoAFunc() {|}; name=protoAFunc(){{$}}
384-
//OMIT_KEYWORD3-DAG: Decl[InstanceMethod]/Super: protoAFuncOptional() {|}; name=protoAFuncOptional(){{$}}
385-
//OMIT_KEYWORD3-DAG: Decl[InstanceMethod]/Super: protoAFuncWithAttr() {|}; name=protoAFuncWithAttr(){{$}}
395+
// OMIT_KEYWORD3: Begin completions
396+
// FIXME: init() not valid after 'func'
397+
// OMIT_KEYWORD3-DAG: Decl[Constructor]/Super: init(fromProtocolA: Int) {|}; name=init(fromProtocolA: Int){{$}}
398+
// FIXME: missing 'override'
399+
// OMIT_KEYWORD3-DAG: Decl[InstanceMethod]/Super: protoAFunc() {|}; name=protoAFunc(){{$}}
400+
// OMIT_KEYWORD3-DAG: Decl[InstanceMethod]/Super: protoAFuncOptional() {|}; name=protoAFuncOptional(){{$}}
401+
// OMIT_KEYWORD3-DAG: Decl[InstanceMethod]/Super: protoAFuncWithAttr() {|}; name=protoAFuncWithAttr(){{$}}
386402
// OMIT_KEYWORD3-NOT: Decl[InstanceVar]/Super: var protoAVarRW: Int{{; name=.+$}}
387403
// OMIT_KEYWORD3: End completions
388404

@@ -394,6 +410,39 @@ class OmitKW4: ProtocolA {
394410
// OMIT_KEYWORD4: Decl[InstanceVar]/Super: protoAVarRW: Int{{; name=.+$}}
395411
// OMIT_KEYWORD4-NOT: Decl[InstanceMethod]
396412

413+
class OmitKW5: ProtocolA {
414+
override
415+
#^OMIT_KEYWORD5^#
416+
// Same as OMIT_KEYWORD1
417+
}
418+
class OmitKW6: ProtocolA {
419+
override
420+
func
421+
#^OMIT_KEYWORD6^#
422+
// Same as OMIT_KEYWORD2
423+
}
424+
class OmitKW7: ProtocolA {
425+
func
426+
#^OMIT_KEYWORD7^#
427+
// Same as OMIT_KEYWORD3
428+
}
429+
430+
class OmitKW8: ProtocolA {
431+
var
432+
#^OMIT_KEYWORD8^#
433+
// Same as OMIT_KEYWORD4
434+
}
435+
class OmitKW9: ProtocolA {
436+
override
437+
var
438+
#^OMIT_KEYWORD9^#
439+
// Same as OMIT_KEYWORD4
440+
}
441+
class OmitKW10: ProtocolA {
442+
override func protoAFunc() {}; #^OMIT_KEYWORD10^#
443+
// WITH_PA
444+
}
445+
397446
protocol HasThrowingProtocol {
398447
func foo() throws
399448
}

validation-test/IDE/crashers_fixed/009-swift-performdelayedparsing.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
enum b:a{var f={static#^A^#
33
// FIXME: we shouldn't back the parser to the beginning of the line, it leads
44
// to ridiculous override completions like this.
5-
// CHECK: Decl[InstanceVar]/Super: rawValue: Self.RawValue;
5+
// CHECK: Decl[InstanceVar]/Super: var rawValue: Self.RawValue;

0 commit comments

Comments
 (0)