Skip to content

Commit 8f3d48f

Browse files
committed
CodeCompletion: Complete member types with non-identifier qualifiers
1 parent c46b7c1 commit 8f3d48f

File tree

5 files changed

+226
-73
lines changed

5 files changed

+226
-73
lines changed

include/swift/IDE/CodeCompletionResult.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ enum class CompletionKind : uint8_t {
200200
KeyPathExprSwift,
201201
TypeDeclResultBeginning,
202202
TypeSimpleBeginning,
203-
TypeIdentifierWithDot,
204-
TypeIdentifierWithoutDot,
203+
TypeSimpleWithDot,
204+
TypeSimpleWithoutDot,
205205
CaseStmtKeyword,
206206
CaseStmtBeginning,
207207
NominalMemberBeginning,

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ class IDEInspectionCallbacks {
162162
/// by user.
163163
virtual void completeTypeSimpleBeginning() {};
164164

165-
/// Complete a given type identifier after we have consumed the dot.
166-
virtual void completeTypeIdentifierWithDot(DeclRefTypeRepr *TR){};
165+
/// Complete a given \c type-simple after we have consumed the dot.
166+
virtual void completeTypeSimpleWithDot(TypeRepr *TR){};
167167

168-
/// Complete a given type identifier when there is no trailing dot.
169-
virtual void completeTypeIdentifierWithoutDot(DeclRefTypeRepr *TR){};
168+
/// Complete a given \c type-simple when there is no trailing dot.
169+
virtual void completeTypeSimpleWithoutDot(TypeRepr *TR){};
170170

171171
/// Complete the beginning of a case statement at the top of switch stmt.
172172
virtual void completeCaseStmtKeyword() {};

lib/IDE/CodeCompletion.cpp

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,8 @@ class CodeCompletionCallbacksImpl : public IDEInspectionCallbacks {
266266

267267
void completeTypeDeclResultBeginning() override;
268268
void completeTypeSimpleBeginning() override;
269-
void completeTypeIdentifierWithDot(DeclRefTypeRepr *TR) override;
270-
void completeTypeIdentifierWithoutDot(DeclRefTypeRepr *TR) override;
269+
void completeTypeSimpleWithDot(TypeRepr *TR) override;
270+
void completeTypeSimpleWithoutDot(TypeRepr *TR) override;
271271

272272
void completeCaseStmtKeyword() override;
273273
void completeCaseStmtBeginning(CodeCompletionExpr *E) override;
@@ -494,21 +494,16 @@ void CodeCompletionCallbacksImpl::completeInPrecedenceGroup(
494494
CurDeclContext = P.CurDeclContext;
495495
}
496496

497-
void CodeCompletionCallbacksImpl::completeTypeIdentifierWithDot(
498-
DeclRefTypeRepr *TR) {
499-
if (!TR) {
500-
completeTypeSimpleBeginning();
501-
return;
502-
}
503-
Kind = CompletionKind::TypeIdentifierWithDot;
497+
void CodeCompletionCallbacksImpl::completeTypeSimpleWithDot(TypeRepr *TR) {
498+
assert(TR);
499+
Kind = CompletionKind::TypeSimpleWithDot;
504500
ParsedTypeLoc = TypeLoc(TR);
505501
CurDeclContext = P.CurDeclContext;
506502
}
507503

508-
void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot(
509-
DeclRefTypeRepr *TR) {
504+
void CodeCompletionCallbacksImpl::completeTypeSimpleWithoutDot(TypeRepr *TR) {
510505
assert(TR);
511-
Kind = CompletionKind::TypeIdentifierWithoutDot;
506+
Kind = CompletionKind::TypeSimpleWithoutDot;
512507
ParsedTypeLoc = TypeLoc(TR);
513508
CurDeclContext = P.CurDeclContext;
514509
}
@@ -953,6 +948,13 @@ addClosureSignatureKeywordsIfApplicable(CodeCompletionResultSink &Sink,
953948

954949
void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
955950
bool MaybeFuncBody) {
951+
auto addEffectsSpecifierKeywords = [&] {
952+
if (!llvm::is_contained(ParsedKeywords, "async"))
953+
addKeyword(Sink, "async", CodeCompletionKeywordKind::None);
954+
if (!llvm::is_contained(ParsedKeywords, "throws"))
955+
addKeyword(Sink, "throws", CodeCompletionKeywordKind::kw_throws);
956+
};
957+
956958
switch (Kind) {
957959
case CompletionKind::None:
958960
case CompletionKind::DotExpr:
@@ -974,13 +976,9 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
974976
case CompletionKind::OptionalBinding:
975977
break;
976978

977-
case CompletionKind::EffectsSpecifier: {
978-
if (!llvm::is_contained(ParsedKeywords, "async"))
979-
addKeyword(Sink, "async", CodeCompletionKeywordKind::None);
980-
if (!llvm::is_contained(ParsedKeywords, "throws"))
981-
addKeyword(Sink, "throws", CodeCompletionKeywordKind::kw_throws);
979+
case CompletionKind::EffectsSpecifier:
980+
addEffectsSpecifierKeywords();
982981
break;
983-
}
984982

985983
case CompletionKind::AccessorBeginning: {
986984
// TODO: Omit already declared or mutally exclusive accessors.
@@ -1037,8 +1035,15 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10371035

10381036
break;
10391037
case CompletionKind::CaseStmtBeginning:
1040-
case CompletionKind::TypeIdentifierWithDot:
1041-
case CompletionKind::TypeIdentifierWithoutDot:
1038+
case CompletionKind::TypeSimpleWithDot:
1039+
break;
1040+
1041+
case CompletionKind::TypeSimpleWithoutDot:
1042+
// Suggest effects specifiers after a tuple type because it may be
1043+
// intended as a parameter list.
1044+
if (isa_and_nonnull<TupleTypeRepr>(ParsedTypeLoc.getTypeRepr())) {
1045+
addEffectsSpecifierKeywords();
1046+
}
10421047
break;
10431048

10441049
case CompletionKind::TypeDeclResultBeginning: {
@@ -1241,8 +1246,8 @@ void swift::ide::postProcessCompletionResults(
12411246
if (result->getKind() == CodeCompletionResultKind::Declaration &&
12421247
result->getAssociatedDeclKind() == CodeCompletionDeclKind::Protocol &&
12431248
Kind != CompletionKind::TypeSimpleBeginning &&
1244-
Kind != CompletionKind::TypeIdentifierWithoutDot &&
1245-
Kind != CompletionKind::TypeIdentifierWithDot &&
1249+
Kind != CompletionKind::TypeSimpleWithoutDot &&
1250+
Kind != CompletionKind::TypeSimpleWithDot &&
12461251
Kind != CompletionKind::TypeDeclResultBeginning &&
12471252
Kind != CompletionKind::GenericRequirement) {
12481253
flair |= CodeCompletionFlairBit::RareTypeAtCurrentPosition;
@@ -1597,7 +1602,7 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
15971602
return;
15981603

15991604
undoSingleExpressionReturn(CurDeclContext);
1600-
if (Kind != CompletionKind::TypeIdentifierWithDot) {
1605+
if (Kind != CompletionKind::TypeSimpleWithDot) {
16011606
// Type member completion does not need a type-checked AST.
16021607
typeCheckContextAt(
16031608
TypeCheckASTNodeAtLocContext::declContext(CurDeclContext),
@@ -1753,13 +1758,13 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17531758
break;
17541759
}
17551760

1756-
case CompletionKind::TypeIdentifierWithDot: {
1761+
case CompletionKind::TypeSimpleWithDot: {
17571762
Lookup.setHaveDot(SourceLoc());
17581763
Lookup.getTypeCompletions(ParsedTypeLoc.getType());
17591764
break;
17601765
}
17611766

1762-
case CompletionKind::TypeIdentifierWithoutDot: {
1767+
case CompletionKind::TypeSimpleWithoutDot: {
17631768
Lookup.getTypeCompletions(ParsedTypeLoc.getType());
17641769
break;
17651770
}

lib/Parse/ParseType.cpp

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
208208
if (auto *ITR = cast_or_null<IdentTypeRepr>(ty.getPtrOrNull())) {
209209
if (Tok.is(tok::code_complete) && !Tok.isAtStartOfLine()) {
210210
if (IDECallbacks)
211-
IDECallbacks->completeTypeIdentifierWithoutDot(ITR);
211+
IDECallbacks->completeTypeSimpleWithoutDot(ITR);
212212

213213
ty.setHasCodeCompletionAndIsError();
214214
consumeToken(tok::code_complete);
@@ -219,7 +219,6 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
219219
break;
220220
case tok::kw_Any:
221221
ty = parseAnyType();
222-
// FIXME: Offer completions in 'Any<#HERE#>' and 'Any.<#HERE#>'.
223222
break;
224223
case tok::l_paren:
225224
ty = parseTypeTupleBody();
@@ -262,6 +261,18 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
262261
// '.X', '.Type', '.Protocol', '?', '!', '[]'.
263262
while (ty.isNonNull()) {
264263
if (Tok.isAny(tok::period, tok::period_prefix)) {
264+
if (peekToken().is(tok::code_complete)) {
265+
consumeToken();
266+
267+
if (IDECallbacks) {
268+
IDECallbacks->completeTypeSimpleWithDot(ty.get());
269+
}
270+
271+
ty.setHasCodeCompletionAndIsError();
272+
consumeToken(tok::code_complete);
273+
break;
274+
}
275+
265276
ty = parseTypeDotted(ty);
266277
continue;
267278
}
@@ -281,6 +292,15 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
281292
continue;
282293
}
283294
}
295+
296+
if (Tok.is(tok::code_complete) && !Tok.isAtStartOfLine()) {
297+
if (IDECallbacks) {
298+
IDECallbacks->completeTypeSimpleWithoutDot(ty.get());
299+
}
300+
301+
ty.setHasCodeCompletionAndIsError();
302+
consumeToken(tok::code_complete);
303+
}
284304
break;
285305
}
286306

@@ -807,10 +827,10 @@ Parser::parseTypeIdentifier(bool isParsingQualifiedDeclBaseType) {
807827
// We have a dot.
808828
consumeToken();
809829
if (IDECallbacks)
810-
IDECallbacks->completeTypeIdentifierWithDot(DeclRefTR);
830+
IDECallbacks->completeTypeSimpleWithDot(DeclRefTR);
811831
} else {
812832
if (IDECallbacks)
813-
IDECallbacks->completeTypeIdentifierWithoutDot(DeclRefTR);
833+
IDECallbacks->completeTypeSimpleWithoutDot(DeclRefTR);
814834
}
815835
// Eat the code completion token because we handled it.
816836
consumeToken(tok::code_complete);
@@ -853,9 +873,9 @@ ParserResult<TypeRepr> Parser::parseTypeDotted(ParserResult<TypeRepr> Base) {
853873

854874
SmallVector<IdentTypeRepr *, 4> MemberComponents;
855875

856-
while (true) {
857-
if (Tok.isNot(tok::period, tok::period_prefix) ||
858-
peekToken().is(tok::code_complete)) {
876+
while (Tok.isAny(tok::period, tok::period_prefix)) {
877+
if (peekToken().is(tok::code_complete)) {
878+
// Code completion for "type-simple '.'" is handled in 'parseTypeSimple'.
859879
break;
860880
}
861881

@@ -888,32 +908,8 @@ ParserResult<TypeRepr> Parser::parseTypeDotted(ParserResult<TypeRepr> Base) {
888908
MemberComponents.push_back(cast<IdentTypeRepr>(IdentResult.get()));
889909
}
890910

891-
TypeRepr *TR = MemberTypeRepr::create(Context, Base.get(), MemberComponents);
892-
893-
// FIXME: Offer completions in 'X.Type<#HERE#>' and 'X.Type.<#HERE#>'.
894-
if (Tok.is(tok::code_complete)) {
895-
if (!Tok.isAtStartOfLine()) {
896-
Base.setHasCodeCompletionAndIsError();
897-
898-
if (IDECallbacks) {
899-
if (auto *DeclRefTR = dyn_cast<DeclRefTypeRepr>(TR))
900-
IDECallbacks->completeTypeIdentifierWithoutDot(DeclRefTR);
901-
}
902-
903-
consumeToken(tok::code_complete);
904-
}
905-
} else if (Tok.isAny(tok::period, tok::period_prefix)) {
906-
Base.setHasCodeCompletionAndIsError();
907-
consumeToken();
908-
909-
if (IDECallbacks) {
910-
if (auto *DeclRefTR = dyn_cast<DeclRefTypeRepr>(TR))
911-
IDECallbacks->completeTypeIdentifierWithDot(DeclRefTR);
912-
}
913-
consumeToken(tok::code_complete);
914-
}
915-
916-
return makeParserResult(Base, TR);
911+
return makeParserResult(
912+
Base, MemberTypeRepr::create(Context, Base.get(), MemberComponents));
917913
}
918914

919915
/// parseTypeSimpleOrComposition

0 commit comments

Comments
 (0)