Skip to content

Commit 2f8155d

Browse files
authored
Merge pull request #3868 from benlangmuir/unresolved-member-nonenumoptset
[CodeCompletion] Complete unresolved members that are not enums or Op…
2 parents 99dffd7 + 468e6d9 commit 2f8155d

File tree

2 files changed

+72
-32
lines changed

2 files changed

+72
-32
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
16551655
DeducedAssociatedTypeCache;
16561656

16571657
Optional<SemanticContextKind> ForcedSemanticContext = None;
1658+
bool IsUnresolvedMember = false;
16581659

16591660
std::unique_ptr<ArchetypeTransformer> TransformerPt = nullptr;
16601661

@@ -1885,6 +1886,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
18851886
if (ForcedSemanticContext)
18861887
return *ForcedSemanticContext;
18871888

1889+
if (IsUnresolvedMember) {
1890+
if (isa<EnumElementDecl>(D)) {
1891+
return SemanticContextKind::ExpressionSpecific;
1892+
}
1893+
}
1894+
18881895
switch (Reason) {
18891896
case DeclVisibilityKind::LocalVariable:
18901897
case DeclVisibilityKind::FunctionParameter:
@@ -3002,20 +3009,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
30023009
return false;
30033010
}
30043011

3005-
void handleOptionSet(Decl *D, DeclVisibilityKind Reason) {
3006-
if (auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
3007-
if (isOptionSetDecl(NTD)) {
3008-
for (auto M : NTD->getMembers()) {
3009-
if (auto *VD = dyn_cast<VarDecl>(M)) {
3010-
if (isOptionSet(VD->getType()) && VD->isStatic()) {
3011-
addVarDeclRef(VD, Reason);
3012-
}
3013-
}
3014-
}
3015-
}
3016-
}
3017-
}
3018-
30193012
bool isOptionSetDecl(NominalTypeDecl *D) {
30203013
auto optionSetType = dyn_cast<ProtocolDecl>(Ctx.getOptionSetDecl());
30213014
if (!optionSetType)
@@ -3659,13 +3652,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36593652
unboxType(FT->getInput());
36603653
unboxType(FT->getResult());
36613654
} else if (auto NTD = T->getNominalOrBoundGenericNominal()){
3662-
if (HandledDecls.count(NTD) == 0) {
3663-
auto Reason = DeclVisibilityKind::MemberOfCurrentNominal;
3664-
if (!Lookup.handleEnumElement(NTD, Reason)) {
3665-
Lookup.handleOptionSet(NTD, Reason);
3666-
}
3667-
HandledDecls.insert(NTD);
3668-
}
3655+
if (HandledDecls.insert(NTD).second)
3656+
Lookup.getUnresolvedMemberCompletions(T);
36693657
}
36703658
}
36713659

@@ -3699,20 +3687,39 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36993687
}
37003688
};
37013689

3702-
void getUnresolvedMemberCompletions(SourceLoc Loc, SmallVectorImpl<Type> &Types) {
3690+
void getUnresolvedMemberCompletions(ArrayRef<Type> Types) {
37033691
NeedLeadingDot = !HaveDot;
37043692
for (auto T : Types) {
37053693
if (T && T->getNominalOrBoundGenericNominal()) {
3706-
auto Reason = DeclVisibilityKind::MemberOfCurrentNominal;
3707-
if (!handleEnumElement(T->getNominalOrBoundGenericNominal(), Reason)) {
3708-
handleOptionSet(T->getNominalOrBoundGenericNominal(), Reason);
3709-
}
3694+
// We can only say .foo where foo is a static member of the contextual
3695+
// type and has the same type (or if the member is a function, then the
3696+
// same result type) as the contextual type.
3697+
auto contextCanT = T->getCanonicalType();
3698+
FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind reason) {
3699+
if (!VD->hasType()) {
3700+
TypeResolver->resolveDeclSignature(VD);
3701+
if (!VD->hasType())
3702+
return false;
3703+
}
3704+
3705+
auto T = VD->getType();
3706+
while (auto FT = T->getAs<AnyFunctionType>())
3707+
T = FT->getResult();
3708+
return T->getCanonicalType() == contextCanT;
3709+
});
3710+
3711+
auto baseType = MetatypeType::get(T);
3712+
llvm::SaveAndRestore<LookupKind> SaveLook(Kind, LookupKind::ValueExpr);
3713+
llvm::SaveAndRestore<Type> SaveType(ExprType, baseType);
3714+
llvm::SaveAndRestore<bool> SaveUnresolved(IsUnresolvedMember, true);
3715+
lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext,
3716+
TypeResolver.get(),
3717+
/*includeInstanceMembers=*/false);
37103718
}
37113719
}
37123720
}
37133721

3714-
void getUnresolvedMemberCompletions(SourceLoc Loc,
3715-
std::vector<std::string> &FuncNames,
3722+
void getUnresolvedMemberCompletions(std::vector<std::string> &FuncNames,
37163723
bool HasReturn) {
37173724
NeedLeadingDot = !HaveDot;
37183725
LookupByName Lookup(*this, FuncNames);
@@ -5186,12 +5193,10 @@ void CodeCompletionCallbacksImpl::doneParsing() {
51865193
eraseErrorTypes(PE);
51875194
Success = typeCheckUnresolvedExpr(*CurDeclContext, UnresolvedExpr, PE,
51885195
PossibleTypes);
5189-
Lookup.getUnresolvedMemberCompletions(
5190-
P.Context.SourceMgr.getCodeCompletionLoc(), PossibleTypes);
5196+
Lookup.getUnresolvedMemberCompletions(PossibleTypes);
51915197
}
51925198
if (!Success) {
51935199
Lookup.getUnresolvedMemberCompletions(
5194-
P.Context.SourceMgr.getCodeCompletionLoc(),
51955200
TokensBeforeUnresolvedExpr,
51965201
UnresolvedExprInReturn);
51975202
}

test/IDE/complete_unresolved_members.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646

4747
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OTHER_FILE_1 %S/Inputs/EnumFromOtherFile.swift | FileCheck %s -check-prefix=OTHER_FILE_1
4848

49+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NON_OPT_SET_1 | FileCheck %s -check-prefix=NON_OPT_SET_1
50+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NON_OPT_SET_2 | FileCheck %s -check-prefix=NON_OPT_SET_1
51+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=NON_OPT_SET_3 | FileCheck %s -check-prefix=NON_OPT_SET_1
52+
4953
enum SomeEnum1 {
5054
case South
5155
case North
@@ -271,10 +275,11 @@ func testAvail1(x: EnumAvail1) {
271275
func testAvail2(x: OptionsAvail1) {
272276
testAvail2(.#^OPTIONS_AVAIL_1^#)
273277
}
274-
// OPTIONS_AVAIL_1: Begin completions, 2 items
278+
// OPTIONS_AVAIL_1: Begin completions, 3 items
275279
// ENUM_AVAIL_1-NOT: AAA
276280
// OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/CurrNominal: aaa[#OptionsAvail1#];
277281
// OPTIONS_AVAIL_1-DAG: Decl[StaticVar]/CurrNominal/NotRecommended: BBB[#OptionsAvail1#];
282+
// OPTIONS_AVAIL_1-DAG: Decl[Constructor]/CurrNominal: init({#rawValue: Int#})[#OptionsAvail1#]
278283
// ENUM_AVAIL_1-NOT: AAA
279284
// OPTIONS_AVAIL_1: End completions
280285

@@ -329,3 +334,33 @@ func enumFromOtherFile() -> EnumFromOtherFile {
329334
// OTHER_FILE_1-DAG: Decl[EnumElement]/ExprSpecific: a({#Int#})[#(Int) -> EnumFromOtherFile#];
330335
// OTHER_FILE_1-DAG: Decl[EnumElement]/ExprSpecific: c[#EnumFromOtherFile#];
331336
// OTHER_FILE_1: End completions
337+
338+
struct NonOptSet {
339+
static let a = NonOptSet()
340+
static let wrongType = 1
341+
let notStatic = NonOptSet()
342+
init(x: Int, y: Int) {}
343+
init() {}
344+
static func b() -> NonOptSet { return NonOptSet() }
345+
static func wrongType() -> Int { return 0 }
346+
func notStatic() -> NonOptSet { return NonOptSet() }
347+
}
348+
349+
func testNonOptSet() {
350+
let x: NonOptSet
351+
x = .#^NON_OPT_SET_1^#
352+
}
353+
// NON_OPT_SET_1: Begin completions, 4 items
354+
// NON_OPT_SET_1-DAG: Decl[StaticVar]/CurrNominal: a[#NonOptSet#]
355+
// NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal: init({#x: Int#}, {#y: Int#})[#NonOptSet#]
356+
// NON_OPT_SET_1-DAG: Decl[Constructor]/CurrNominal: init()[#NonOptSet#]
357+
// NON_OPT_SET_1-DAG: Decl[StaticMethod]/CurrNominal: b()[#NonOptSet#]
358+
// NON_OPT_SET_1: End completions
359+
360+
func testNonOptSet() {
361+
let x: NonOptSet = .#^NON_OPT_SET_2^#
362+
}
363+
364+
func testNonOptSet() -> NonOptSet {
365+
return .#^NON_OPT_SET_3^#
366+
}

0 commit comments

Comments
 (0)