Skip to content

Commit fe59d99

Browse files
authored
Merge pull request #20013 from rintaro/ide-completion-overloadedmethod
[CodeCompletion] Improve context type analysis for overloaded method
2 parents 4964e2d + c84ea2b commit fe59d99

File tree

4 files changed

+104
-23
lines changed

4 files changed

+104
-23
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3887,6 +3887,53 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
38873887

38883888
using FunctionParams = ArrayRef<AnyFunctionType::Param>;
38893889

3890+
static void collectPossibleParamListByQualifiedLookup(
3891+
DeclContext &DC, Type baseTy, DeclBaseName name,
3892+
SmallVectorImpl<FunctionParams> &candidates) {
3893+
3894+
SmallVector<ValueDecl *, 2> decls;
3895+
auto resolver = DC.getASTContext().getLazyResolver();
3896+
if (!DC.lookupQualified(baseTy, name, NL_QualifiedDefault, resolver, decls))
3897+
return;
3898+
3899+
for (auto *VD : decls) {
3900+
if (!isa<AbstractFunctionDecl>(VD) ||
3901+
shouldHideDeclFromCompletionResults(VD))
3902+
continue;
3903+
resolver->resolveDeclSignature(VD);
3904+
if (!VD->hasInterfaceType())
3905+
continue;
3906+
Type declaredMemberType = VD->getInterfaceType();
3907+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD))
3908+
declaredMemberType = AFD->getMethodInterfaceType();
3909+
3910+
auto fnType =
3911+
baseTy->getTypeOfMember(DC.getParentModule(), VD, declaredMemberType);
3912+
3913+
if (!fnType || fnType->hasError())
3914+
continue;
3915+
if (auto *AFT = fnType->getAs<AnyFunctionType>()) {
3916+
candidates.push_back(AFT->getParams());
3917+
}
3918+
}
3919+
}
3920+
3921+
static void collectPossibleParamListByQualifiedLookup(
3922+
DeclContext &DC, Expr *baseExpr, DeclBaseName name,
3923+
SmallVectorImpl<FunctionParams> &candidates) {
3924+
ConcreteDeclRef ref = nullptr;
3925+
auto baseTyOpt = getTypeOfCompletionContextExpr(
3926+
DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr,
3927+
ref);
3928+
if (!baseTyOpt)
3929+
return;
3930+
auto baseTy = (*baseTyOpt)->getRValueType()->getMetatypeInstanceType();
3931+
if (!baseTy->mayHaveMembers())
3932+
return;
3933+
3934+
collectPossibleParamListByQualifiedLookup(DC, baseTy, name, candidates);
3935+
}
3936+
38903937
static bool
38913938
collectPossibleParamLists(DeclContext &DC, ApplyExpr *callExpr,
38923939
SmallVectorImpl<FunctionParams> &candidates) {
@@ -3907,17 +3954,27 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
39073954
if (auto *funcType = declType->getAs<AnyFunctionType>())
39083955
candidates.push_back(funcType->getParams());
39093956
}
3910-
} else {
3911-
ConcreteDeclRef ref = nullptr;
3912-
auto fnType = getTypeOfCompletionContextExpr(DC.getASTContext(),
3913-
&DC, CompletionTypeCheckKind::Normal,
3914-
fnExpr, ref);
3957+
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(fnExpr)) {
3958+
collectPossibleParamListByQualifiedLookup(
3959+
DC, UDE->getBase(), UDE->getName().getBaseName(), candidates);
3960+
}
39153961

3962+
if (candidates.empty()) {
3963+
ConcreteDeclRef ref = nullptr;
3964+
auto fnType = getTypeOfCompletionContextExpr(
3965+
DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, fnExpr,
3966+
ref);
39163967
if (!fnType)
39173968
return false;
39183969

3919-
if (auto *AFT = (*fnType)->getAs<AnyFunctionType>())
3970+
if (auto *AFT = (*fnType)->getAs<AnyFunctionType>()) {
39203971
candidates.push_back(AFT->getParams());
3972+
} else if (auto *AMT = (*fnType)->getAs<AnyMetatypeType>()) {
3973+
auto baseTy = AMT->getInstanceType();
3974+
if (baseTy->mayHaveMembers())
3975+
collectPossibleParamListByQualifiedLookup(
3976+
DC, baseTy, DeclBaseName::createConstructor(), candidates);
3977+
}
39213978
}
39223979

39233980
return !candidates.empty();
@@ -5165,30 +5222,30 @@ namespace {
51655222

51665223
public:
51675224
llvm::SmallVector<ParentTy, 5> Ancestors;
5168-
ParentTy ParentClosest;
5169-
ParentTy ParentFarthest;
51705225
ExprParentFinder(Expr* ChildExpr,
51715226
llvm::function_ref<bool(ParentTy, ParentTy)> Predicate) :
51725227
ChildExpr(ChildExpr), Predicate(Predicate) {}
51735228

51745229
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
5175-
if (E != ChildExpr && Predicate(E, Parent)) {
5230+
// Finish if we found the target.
5231+
if (E == ChildExpr)
5232+
return { false, nullptr };
5233+
5234+
if (Predicate(E, Parent))
51765235
Ancestors.push_back(E);
5177-
return { true, E };
5178-
}
5179-
if (E == ChildExpr || arePositionsSame(E, ChildExpr)) {
5180-
if (!Ancestors.empty()) {
5181-
ParentClosest = Ancestors.back();
5182-
ParentFarthest = Ancestors.front();
5183-
}
5184-
return {false, nullptr};
5185-
}
51865236
return { true, E };
51875237
}
51885238

51895239
Expr *walkToExprPost(Expr *E) override {
51905240
if (Predicate(E, Parent))
51915241
Ancestors.pop_back();
5242+
5243+
// 'ChildExpr' might have been replaced with typechecked expression. In
5244+
// that case, find deepest expression that position is the same as the
5245+
// target.
5246+
if (arePositionsSame(E, ChildExpr))
5247+
return nullptr;
5248+
51925249
return E;
51935250
}
51945251

test/IDE/complete_call_arg.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,9 @@ struct EmptyOverload {
398398
init(foo: Int) {}
399399
}
400400
_ = EmptyOverload(foo: #^EMPTY_OVERLOAD_2^#)
401-
// FIXME: we should have a TypeRelation[Identical] here for Ints. For now just
402-
// check it's not empty.
403401
// EMPTY_OVERLOAD: Begin completions
404-
// EMPTY_OVERLOAD-DAG: Decl[GlobalVar]/Local{{.*}}: i2[#Int#];
405-
// EMPTY_OVERLOAD-DAG: Decl[GlobalVar]/Local{{.*}}: i1[#Int#];
402+
// EMPTY_OVERLOAD-DAG: Decl[GlobalVar]/Local/TypeRelation[Identical]: i2[#Int#];
403+
// EMPTY_OVERLOAD-DAG: Decl[GlobalVar]/Local/TypeRelation[Identical]: i1[#Int#];
406404
// EMPTY_OVERLOAD: End completions
407405

408406
public func fopen() -> TestBoundGeneric1! { fatalError() }

test/IDE/complete_unresolved_members.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868

6969
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_CLOSURE_1 | %FileCheck %s -check-prefix=STATIC_CLOSURE_1
7070

71+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_METHOD_1 | %FileCheck %s -check-prefix=OVERLOADED_METHOD_1
72+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_INIT_1 | %FileCheck %s -check-prefix=OVERLOADED_METHOD_1
73+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERLOADED_INIT_2 | %FileCheck %s -check-prefix=OVERLOADED_METHOD_1
74+
7175
enum SomeEnum1 {
7276
case South
7377
case North
@@ -494,3 +498,25 @@ func testHasStaticClosure() {
494498
// STATIC_CLOSURE_1-DAG: Decl[StaticVar]/CurrNominal: create[#() -> HasCreator#];
495499
// STATIC_CLOSURE_1-NOT: create_curried
496500
// STATIC_CLOSURE_1: End completions
501+
502+
struct HasOverloaded {
503+
init(e: SomeEnum1) {}
504+
init(e: SomeEnum2) {}
505+
func takeEnum(_ e: SomeEnum1) -> Int { return 0 }
506+
func takeEnum(_ e: SomeEnum2) -> Int { return 0 }
507+
}
508+
func testOverload(val: HasOverloaded) {
509+
let _ = val.takeEnum(.#^OVERLOADED_METHOD_1^#)
510+
// OVERLOADED_METHOD_1: Begin completions, 4 items
511+
// OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; name=South
512+
// OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; name=North
513+
// OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/ExprSpecific: East[#SomeEnum2#]; name=East
514+
// OVERLOADED_METHOD_1-DAG: Decl[EnumElement]/ExprSpecific: West[#SomeEnum2#]; name=West
515+
// OVERLOADED_METHOD_1: End completions
516+
517+
let _ = HasOverloaded.init(e: .#^OVERLOADED_INIT_1^#)
518+
// Same as OVERLOADED_METHOD_1.
519+
520+
let _ = HasOverloaded(e: .#^OVERLOADED_INIT_2^#)
521+
// Same as OVERLOADED_METHOD_1.
522+
}

test/IDE/complete_value_expr.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ func testInsideFunctionCall4() {
741741
func testInsideFunctionCall5() {
742742
FooStruct().instanceFunc2(42, #^INSIDE_FUNCTION_CALL_5^#
743743
// INSIDE_FUNCTION_CALL_5: Begin completions
744-
// INSIDE_FUNCTION_CALL_5-DAG: Decl[GlobalVar]/CurrModule: fooObject[#FooStruct#]{{; name=.+$}}
744+
// INSIDE_FUNCTION_CALL_5-DAG: Keyword/ExprSpecific: b: [#Argument name#]; name=b:
745745
// INSIDE_FUNCTION_CALL_5: End completions
746746
}
747747

0 commit comments

Comments
 (0)