Skip to content

Commit 612297f

Browse files
committed
[CodeCompletion] Don't provide 'init(nilLiteral:)' et al in optional context
For unresolved member completion, member decls in `Optional` referenceable by implicit member expression are useless in most cases. - `init(_: <#Wrapped#>)` - `init(nilLiteral: ())` - `.some(<#Wrapped#>)` - `.none` Instead, provide `nil` with erasing `.` instruction. rdar://problem/47806831 (cherry picked from commit 7e3a5dc)
1 parent 1380650 commit 612297f

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2717,7 +2717,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27172717
void addKeyword(StringRef Name, Type TypeAnnotation = Type(),
27182718
SemanticContextKind SK = SemanticContextKind::None,
27192719
CodeCompletionKeywordKind KeyKind
2720-
= CodeCompletionKeywordKind::None) {
2720+
= CodeCompletionKeywordKind::None,
2721+
unsigned NumBytesToErase = 0) {
27212722
CodeCompletionResultBuilder Builder(
27222723
Sink,
27232724
CodeCompletionResult::ResultKind::Keyword, SK, ExpectedTypes);
@@ -2726,6 +2727,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
27262727
Builder.setKeywordKind(KeyKind);
27272728
if (TypeAnnotation)
27282729
addTypeAnnotation(Builder, TypeAnnotation);
2730+
if (NumBytesToErase > 0)
2731+
Builder.setNumBytesToErase(NumBytesToErase);
27292732
}
27302733

27312734
void addKeyword(StringRef Name, StringRef TypeAnnotation,
@@ -3612,6 +3615,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36123615
return false;
36133616
}
36143617

3618+
// In optional context, ignore '.init(<some>)', 'init(nilLiteral:)',
3619+
// '.some(<some>)' and '.none'. They are useless in most cases.
3620+
if (T->getOptionalObjectType() &&
3621+
VD->getModuleContext()->isStdlibModule() &&
3622+
(isa<EnumElementDecl>(VD) || isa<ConstructorDecl>(VD))) {
3623+
return false;
3624+
}
3625+
36153626
// Enum element decls can always be referenced by implicit member
36163627
// expression.
36173628
if (isa<EnumElementDecl>(VD))
@@ -3682,6 +3693,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36823693
// If this is optional type, perform completion for the object type.
36833694
// i.e. 'let _: Enum??? = .enumMember' is legal.
36843695
getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes());
3696+
3697+
// Add 'nil' keyword with erasing '.' instruction.
3698+
unsigned bytesToErase = 0;
3699+
auto &SM = CurrDeclContext->getASTContext().SourceMgr;
3700+
if (DotLoc.isValid())
3701+
bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc());
3702+
addKeyword("nil", T, SemanticContextKind::ExpressionSpecific,
3703+
CodeCompletionKeywordKind::kw_nil, bytesToErase);
36853704
}
36863705
getUnresolvedMemberCompletions(T);
36873706
}

test/IDE/complete_unresolved_members.swift

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT
1515
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT
1616
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPTOPTOPT
17+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_4 | %FileCheck %s -check-prefix=UNRESOLVED_OPT_4
1718

1819
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_12 | %FileCheck %s -check-prefix=UNRESOLVED_3
1920
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_13 | %FileCheck %s -check-prefix=UNRESOLVED_3
@@ -251,18 +252,42 @@ class C4 {
251252
// UNRESOLVED_3_OPT: Begin completions
252253
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#];
253254
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#];
254-
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<SomeEnum1>#]; name=none
255-
// UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1#})[#Optional<SomeEnum1>#];
256-
// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1#})[#Optional<SomeEnum1>#];
257-
// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional<SomeEnum1>#];
255+
// UNRESOLVED_3_OPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1?#]; name=nil
256+
// UNRESOLVED_3_OPT-NOT: none
257+
// UNRESOLVED_3_OPT-NOT: some
258+
// UNRESOLVED_3_OPT-NOT: init({#(some):
259+
// UNRESOLVED_3_OPT-NOT: init({#nilLiteral:
258260

259261
// UNRESOLVED_3_OPTOPTOPT: Begin completions
260262
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#];
261263
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#];
262-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional<SomeEnum1??>#]; name=none
263-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1??#})[#Optional<SomeEnum1??>#];
264-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1??#})[#Optional<SomeEnum1??>#];
265-
// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional<SomeEnum1??>#];
264+
// UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1???#]; name=nil
265+
// UNRESOLVED_3_OPTOPTOPT-NOT: none
266+
// UNRESOLVED_3_OPTOPTOPT-NOT: some
267+
// UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some):
268+
// UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral:
269+
270+
enum Somewhere {
271+
case earth, mars
272+
}
273+
extension Optional where Wrapped == Somewhere {
274+
init(str: String) { fatalError() }
275+
static var nowhere: Self { return nil }
276+
}
277+
func testOptionalWithCustomExtension() {
278+
var _: Somewhere? = .#^UNRESOLVED_OPT_4^#
279+
// UNRESOLVED_OPT_4: Begin completions
280+
// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: earth[#Somewhere#];
281+
// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: mars[#Somewhere#];
282+
// UNRESOLVED_OPT_4-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#Somewhere?#]; name=nil
283+
// UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional<Somewhere>#]; name=init(str: String)
284+
// UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional<Somewhere>#]; name=nowhere
285+
// UNRESOLVED_OPT_4-NOT: none
286+
// UNRESOLVED_OPT_4-NOT: some
287+
// UNRESOLVED_OPT_4-NOT: init({#(some):
288+
// UNRESOLVED_OPT_4-NOT: init({#nilLiteral:
289+
}
290+
266291

267292
class C5 {
268293
func f1() {

0 commit comments

Comments
 (0)