diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 313f244e573bd..fe3c3b1c4087b 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -2737,7 +2737,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { void addKeyword(StringRef Name, Type TypeAnnotation = Type(), SemanticContextKind SK = SemanticContextKind::None, CodeCompletionKeywordKind KeyKind - = CodeCompletionKeywordKind::None) { + = CodeCompletionKeywordKind::None, + unsigned NumBytesToErase = 0) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SK, expectedTypeContext); @@ -2746,6 +2747,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Builder.setKeywordKind(KeyKind); if (TypeAnnotation) addTypeAnnotation(Builder, TypeAnnotation); + if (NumBytesToErase > 0) + Builder.setNumBytesToErase(NumBytesToErase); } void addKeyword(StringRef Name, StringRef TypeAnnotation, @@ -3634,6 +3637,15 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { return false; } + if (T->getOptionalObjectType() && + VD->getModuleContext()->isStdlibModule()) { + // In optional context, ignore '.init()', 'init(nilLiteral:)', + if (isa(VD)) + return false; + // TODO: Ignore '.some()' and '.none' too *in expression + // context*. They are useful in pattern context though. + } + // Enum element decls can always be referenced by implicit member // expression. if (isa(VD)) @@ -3704,6 +3716,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // If this is optional type, perform completion for the object type. // i.e. 'let _: Enum??? = .enumMember' is legal. getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes()); + + // Add 'nil' keyword with erasing '.' instruction. + unsigned bytesToErase = 0; + auto &SM = CurrDeclContext->getASTContext().SourceMgr; + if (DotLoc.isValid()) + bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc()); + addKeyword("nil", T, SemanticContextKind::ExpressionSpecific, + CodeCompletionKeywordKind::kw_nil, bytesToErase); } getUnresolvedMemberCompletions(T); } diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index 1015870ad16e3..affa2a179eb66 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -14,6 +14,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPTOPTOPT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_4 | %FileCheck %s -check-prefix=UNRESOLVED_OPT_4 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_12 | %FileCheck %s -check-prefix=UNRESOLVED_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_13 | %FileCheck %s -check-prefix=UNRESOLVED_3 @@ -241,7 +242,7 @@ class C4 { var _: SomeEnum1??? = .#^UNRESOLVED_OPT_3^# } } -// UNRESOLVED_3: Begin completions +// UNRESOLVED_3: Begin completions, 2 items // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; name=North // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; name=South // UNRESOLVED_3-NOT: SomeOptions1 @@ -249,21 +250,46 @@ class C4 { // UNRESOLVED_3-NOT: none // UNRESOLVED_3-NOT: some( -// UNRESOLVED_3_OPT: Begin completions +// UNRESOLVED_3_OPT: Begin completions, 5 items // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; +// UNRESOLVED_3_OPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1?#]; name=nil // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional#]; name=none // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1#})[#Optional#]; -// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1#})[#Optional#]; -// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional#]; +// UNRESOLVED_3_OPT-NOT: init({#(some): +// UNRESOLVED_3_OPT-NOT: init({#nilLiteral: -// UNRESOLVED_3_OPTOPTOPT: Begin completions +// UNRESOLVED_3_OPTOPTOPT: Begin completions, 5 items // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1???#]; name=nil // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional#]; name=none // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1??#})[#Optional#]; -// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1??#})[#Optional#]; -// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional#]; +// UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some): +// UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral: + +enum Somewhere { + case earth, mars +} +extension Optional where Wrapped == Somewhere { + init(str: String) { fatalError() } + static var nowhere: Self { return nil } +} +func testOptionalWithCustomExtension() { + var _: Somewhere? = .#^UNRESOLVED_OPT_4^# +// UNRESOLVED_OPT_4: Begin completions, 7 items +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: earth[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: mars[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#Somewhere?#]; name=nil +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional#]; name=none +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: some({#Somewhere#})[#Optional#]; +// UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional#]; name=init(str: String) +// UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional#]; name=nowhere +// UNRESOLVED_OPT_4-NOT: init({#(some): +// UNRESOLVED_OPT_4-NOT: init({#nilLiteral: +// UNRESOLVED_OPT_4: End completions +} + class C5 { func f1() {