Skip to content

[CodeCompletion] Missing init completions for dotExpr #16868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 31 additions & 39 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2591,7 +2591,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

void addConstructorCall(const ConstructorDecl *CD, DeclVisibilityKind Reason,
Optional<Type> BaseType, Optional<Type> Result,
bool IsOnMetatype = true,
bool IsOnType = true,
Identifier addName = Identifier()) {
foundFunction(CD);
Type MemberType = getTypeOfMember(CD, BaseType);
Expand All @@ -2601,14 +2601,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
->castTo<AnyFunctionType>();

bool needInit = false;
if (!IsOnMetatype) {
if (!IsOnType) {
assert(addName.empty());
assert(isa<ConstructorDecl>(CurrDeclContext) &&
"can call super.init only inside a constructor");
needInit = true;
} else if (addName.empty() && HaveDot &&
Reason == DeclVisibilityKind::MemberOfCurrentNominal) {
// This case is querying the init function as member
} else if (addName.empty() && HaveDot) {
needInit = true;
}

Expand Down Expand Up @@ -2638,7 +2634,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
addTypeAnnotation(Builder, MemberType);
return;
}
assert(ConstructorType);

if (!HaveLParen)
Builder.addLeftParen();
Expand Down Expand Up @@ -2692,7 +2687,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
if (shouldHideDeclFromCompletionResults(init))
continue;
addConstructorCall(cast<ConstructorDecl>(init), Reason, type, None,
/*IsOnMetatype=*/true, name);
/*IsOnType=*/true, name);
}
}
}
Expand Down Expand Up @@ -2943,43 +2938,40 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
return;
}

if (auto MT = ExprType->getRValueType()->getAs<AnyMetatypeType>()) {
if (HaveDot) {
Type Ty;
for (Ty = MT; Ty && Ty->is<AnyMetatypeType>();
Ty = Ty->getAs<AnyMetatypeType>()->getInstanceType());
assert(Ty && "Cannot find instance type.");

// Add init() as member of the metatype.
if (Reason == DeclVisibilityKind::MemberOfCurrentNominal) {
if (IsStaticMetatype || CD->isRequired() ||
!Ty->is<ClassType>())
addConstructorCall(CD, Reason, None, None);
}
return;
}
}

if (auto MT = ExprType->getAs<AnyMetatypeType>()) {
if (HaveDot)
return;
Type Ty = MT->getInstanceType();
assert(Ty && "Cannot find instance type.");

// If instance type is type alias, showing users that the constructed
// If instance type is type alias, show users that the constructed
// type is the typealias instead of the underlying type of the alias.
Optional<Type> Result = None;
if (auto AT = MT->getInstanceType()) {
if (!CD->getInterfaceType()->is<ErrorType>() &&
(isa<NameAliasType>(AT.getPointer()) &&
AT->getDesugaredType() ==
CD->getResultInterfaceType().getPointer()))
Result = AT;
if (!CD->getInterfaceType()->is<ErrorType>() &&
isa<NameAliasType>(Ty.getPointer()) &&
Ty->getDesugaredType() ==
CD->getResultInterfaceType().getPointer()) {
Result = Ty;
}
addConstructorCall(CD, Reason, None, Result);
// If the expression type is not a static metatype or an archetype, the base
// is not a type. Direct call syntax is illegal on values, so we only add
// initializer completions if we do not have a left parenthesis and either
// the initializer is required, the base type's instance type is not a class,
// or this is a 'self' or 'super' reference.
if (IsStaticMetatype || Ty->is<ArchetypeType>())
addConstructorCall(CD, Reason, None, Result, /*isOnType*/true);
else if ((IsSelfRefExpr || IsSuperRefExpr || !Ty->is<ClassType>() ||
CD->isRequired()) && !HaveLParen)
addConstructorCall(CD, Reason, None, Result, /*isOnType*/false);
return;
}
if (IsSuperRefExpr || IsSelfRefExpr) {
if (!isa<ConstructorDecl>(CurrDeclContext))
if (!HaveLParen) {
auto CDC = dyn_cast<ConstructorDecl>(CurrDeclContext);
if (!CDC)
return;
addConstructorCall(CD, Reason, None, None, /*IsOnMetatype=*/false);
// We do not want 'init' completions for 'self' in non-convenience
// initializers and for 'super' in convenience initializers.
if ((IsSelfRefExpr && CDC->isConvenienceInit()) ||
((IsSuperRefExpr && !CDC->isConvenienceInit())))
addConstructorCall(CD, Reason, None, None, /*IsOnType=*/false);
}
return;
}
Expand Down
32 changes: 20 additions & 12 deletions test/IDE/complete_after_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
// RUN: %FileCheck %s -check-prefix=COMMON_SELF_NO_DOT_1 < %t.self.txt
// RUN: %FileCheck %s -check-prefix=NO_INIT < %t.self.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_SELF_PAREN > %t.self.txt
// RUN: %FileCheck %s -check-prefix=STATIC_SELF_PAREN < %t.self.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=FUNC_SELF_DOT_1 > %t.self.txt
// RUN: %FileCheck %s -check-prefix=FUNC_SELF_DOT_1 < %t.self.txt
// RUN: %FileCheck %s -check-prefix=COMMON_SELF_DOT_1 < %t.self.txt
Expand Down Expand Up @@ -166,9 +169,8 @@ class ThisDerived1 : ThisBase1 {

init() {
self#^CONSTRUCTOR_SELF_NO_DOT_1^#
// CONSTRUCTOR_SELF_NO_DOT_1: Begin completions, 24 items
// CONSTRUCTOR_SELF_NO_DOT_1-DAG: Decl[Constructor]/CurrNominal: .init()[#ThisDerived1#];
// CONSTRUCTOR_SELF_NO_DOT_1-DAG: Decl[Constructor]/CurrNominal: .init({#a: Int#})[#ThisDerived1#];
// CONSTRUCTOR_SELF_NO_DOT_1: Begin completions, 21 items
// CONSTRUCTOR_SELF_NO_DOT_1-NOT: Decl[Constructor]
// CONSTRUCTOR_SELF_NO_DOT_1: End completions
let d: ThisDerived1
d#^CONSTRUCTOR_NONSELF_NO_DOT_1^#
Expand All @@ -177,9 +179,8 @@ class ThisDerived1 : ThisBase1 {

init(a : Int) {
self.#^CONSTRUCTOR_SELF_DOT_1^#
// CONSTRUCTOR_SELF_DOT_1: Begin completions, 19 items
// CONSTRUCTOR_SELF_DOT_1-DAG: Decl[Constructor]/CurrNominal: init()[#ThisDerived1#];
// CONSTRUCTOR_SELF_DOT_1-DAG: Decl[Constructor]/CurrNominal: init({#a: Int#})[#ThisDerived1#];
// CONSTRUCTOR_SELF_DOT_1: Begin completions, 16 items
// CONSTRUCTOR_SELF_DOT_1-NOT: Decl[Constructor]

// CONSTRUCTOR_SELF_DOT_1: End completions
let d: ThisDerived1
Expand Down Expand Up @@ -214,8 +215,8 @@ class ThisDerived1 : ThisBase1 {
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[InstanceMethod]/CurrNominal: .derivedFunc0({#self: ThisDerived1#})[#() -> Void#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[StaticVar]/CurrNominal: .derivedStaticVar[#Int#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[StaticMethod]/CurrNominal: .derivedStaticFunc0()[#Void#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Constructor]/CurrNominal: ()[#ThisDerived1#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Constructor]/CurrNominal: ({#a: Int#})[#ThisDerived1#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Constructor]/CurrNominal: .init()[#ThisDerived1#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Constructor]/CurrNominal: .init({#a: Int#})[#ThisDerived1#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[InstanceMethod]/CurrNominal: .test1({#self: ThisDerived1#})[#() -> Void#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[InstanceMethod]/CurrNominal: .test2({#self: ThisDerived1#})[#() -> Void#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[StaticMethod]/CurrNominal: .staticTest1()[#Void#]
Expand All @@ -226,7 +227,7 @@ class ThisDerived1 : ThisBase1 {
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Class]/CurrNominal: .DerivedExtNestedClass[#ThisDerived1.DerivedExtNestedClass#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Enum]/CurrNominal: .DerivedExtNestedEnum[#ThisDerived1.DerivedExtNestedEnum#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[TypeAlias]/CurrNominal: .DerivedExtNestedTypealias[#Int#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Constructor]/CurrNominal: ({#someExtensionArg: Int#})[#ThisDerived1#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[Constructor]/CurrNominal: .init({#someExtensionArg: Int#})[#ThisDerived1#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[InstanceMethod]/Super: .baseFunc0({#self: ThisBase1#})[#() -> Void#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[InstanceMethod]/Super: .baseFunc1({#self: ThisBase1#})[#(Int) -> Void#]
// FUNC_STATIC_SELF_NO_DOT_1-NEXT: Decl[StaticVar]/Super: .baseStaticVar[#Int#]
Expand All @@ -248,6 +249,8 @@ class ThisDerived1 : ThisBase1 {
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[InstanceMethod]/CurrNominal: derivedFunc0({#self: ThisDerived1#})[#() -> Void#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[StaticVar]/CurrNominal: derivedStaticVar[#Int#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[StaticMethod]/CurrNominal: derivedStaticFunc0()[#Void#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[Constructor]/CurrNominal: init()[#ThisDerived1#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[Constructor]/CurrNominal: init({#a: Int#})[#ThisDerived1#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[InstanceMethod]/CurrNominal: test1({#self: ThisDerived1#})[#() -> Void#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[InstanceMethod]/CurrNominal: test2({#self: ThisDerived1#})[#() -> Void#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[StaticMethod]/CurrNominal: staticTest1()[#Void#]
Expand All @@ -258,6 +261,7 @@ class ThisDerived1 : ThisBase1 {
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[Class]/CurrNominal: DerivedExtNestedClass[#ThisDerived1.DerivedExtNestedClass#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[Enum]/CurrNominal: DerivedExtNestedEnum[#ThisDerived1.DerivedExtNestedEnum#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[TypeAlias]/CurrNominal: DerivedExtNestedTypealias[#Int#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[Constructor]/CurrNominal: init({#someExtensionArg: Int#})[#ThisDerived1#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[InstanceMethod]/Super: baseFunc0({#self: ThisBase1#})[#() -> Void#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[InstanceMethod]/Super: baseFunc1({#self: ThisBase1#})[#(Int) -> Void#]
// FUNC_STATIC_SELF_DOT_1-NEXT: Decl[StaticVar]/Super: baseStaticVar[#Int#]
Expand All @@ -272,6 +276,11 @@ class ThisDerived1 : ThisBase1 {
}
}

class func staticTest3() {
self(#^STATIC_SELF_PAREN^#
// STATIC_SELF_PAREN-NOT: Decl[Constructor]
}

extension ThisDerived1 {
var derivedExtProp : Int {
get {
Expand Down Expand Up @@ -310,10 +319,9 @@ struct S1 {
init() {}
init(x: Int) {
self.#^STRUCT_CONSTRUCTOR_SELF_DOT_1^#
// STRUCT_CONSTRUCTOR_SELF_DOT_1: Begin completions, 4 items
// STRUCT_CONSTRUCTOR_SELF_DOT_1: Begin completions, 2 items
// STRUCT_CONSTRUCTOR_SELF_DOT_1-DAG: Keyword[self]/CurrNominal: self[#S1#]; name=self
// STRUCT_CONSTRUCTOR_SELF_DOT_1-DAG: Decl[Constructor]/CurrNominal: init()[#S1#];
// STRUCT_CONSTRUCTOR_SELF_DOT_1-DAG: Decl[Constructor]/CurrNominal: init({#x: Int#})[#S1#];
// STRUCT_CONSTRUCTOR_SELF_DOT_1-NOT: Decl[Constructor]
// STRUCT_CONSTRUCTOR_SELF_DOT_1-DAG: Decl[InstanceMethod]/CurrNominal: f()[#Void#];
// STRUCT_CONSTRUCTOR_SELF_DOT_1: End completions
let s: S1
Expand Down
41 changes: 41 additions & 0 deletions test/IDE/complete_after_super.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@
// RUN: %FileCheck %s -check-prefix=COMMON_BASE_A_DOT < %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_DOT_1 < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONV_CONSTRUCTOR_SUPER_DOT > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_NOINIT < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONV_CONSTRUCTOR_SUPER_NO_DOT > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_NOINIT < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONV_CONSTRUCTOR_SUPER_PAREN > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_NOINIT < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONSTRUCTOR_SUPER_PAREN > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_NOINIT < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLASS_FUNC_SUPER_PAREN > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_NOINIT < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONSTRUCTOR_SUPER_INIT_1 > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CONSTRUCTOR_SUPER_INIT_1 < %t.super.txt

Expand Down Expand Up @@ -64,6 +79,11 @@
// RUN: %FileCheck %s -check-prefix=FUNC_SUPER_DOT_2 < %t.super.txt
// RUN: %FileCheck %s -check-prefix=NO_CONSTRUCTORS < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLASS_FUNC_SUPER_NODOT > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CLASS_FUNC_SUPER < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLASS_FUNC_SUPER_DOT > %t.super.txt
// RUN: %FileCheck %s -check-prefix=CLASS_FUNC_SUPER < %t.super.txt

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SEMANTIC_CONTEXT_OVERRIDDEN_DECL_1 > %t.super.txt
// RUN: %FileCheck %s -check-prefix=SEMANTIC_CONTEXT_OVERRIDDEN_DECL_1 < %t.super.txt
Expand Down Expand Up @@ -221,11 +241,19 @@ class SuperDerivedA : SuperBaseA {

init(a: Int) {
super.#^CONSTRUCTOR_SUPER_DOT_1^#
super(#^CONSTRUCTOR_SUPER_PAREN^#
// CONSTRUCTOR_SUPER_DOT_1: Begin completions, 7 items
// CONSTRUCTOR_SUPER_DOT_1-DAG: Decl[Constructor]/CurrNominal: init()[#SuperBaseA#]{{; name=.+$}}
// CONSTRUCTOR_SUPER_DOT_1: End completions
}

convenience init(foo1: Int) {
super.#^CONV_CONSTRUCTOR_SUPER_DOT^#
super#^CONV_CONSTRUCTOR_SUPER_NO_DOT^#
super(#^CONV_CONSTRUCTOR_SUPER_PAREN^#
// CONSTRUCTOR_SUPER_NOINIT-NOT: Decl[Constructor]
}

init (a: Float) {
super.init#^CONSTRUCTOR_SUPER_INIT_1^#
// CONSTRUCTOR_SUPER_INIT_1: Begin completions
Expand Down Expand Up @@ -411,6 +439,19 @@ class SuperDerivedB : SuperBaseB {
// FUNC_SUPER_DOT_2: Begin completions, 6 items
// FUNC_SUPER_DOT_2: End completions
}

class func test3() {
super#^CLASS_FUNC_SUPER_NODOT^#
}
class func test4() {
super.#^CLASS_FUNC_SUPER_DOT^#
}
class func test5() {
super(#^CLASS_FUNC_SUPER_PAREN^#
}
// CLASS_FUNC_SUPER: Decl[Constructor]/CurrNominal: {{.init|init}}()[#SuperBaseB#]
// CLASS_FUNC_SUPER: Decl[Constructor]/CurrNominal: {{.init|init}}({#a: Double#})[#SuperBaseB#]
// CLASS_FUNC_SUPER: Decl[Constructor]/CurrNominal: {{.init|init}}({#int: Int#})[#SuperBaseB#]
}

//===--- Check that we assign a special semantic context to the overridden decl.
Expand Down
Loading