Skip to content

[CodeCompletion] Don't show protocol extension only members in override #31316

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
1 change: 1 addition & 0 deletions include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ void lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer,
const DeclContext *CurrDC,
bool includeInstanceMembers,
bool includeDerivedRequirements,
bool includeProtocolExtensionMembers,
GenericSignatureBuilder *GSB = nullptr);

namespace namelookup {
Expand Down
21 changes: 14 additions & 7 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3531,7 +3531,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
if (Type Unwrapped = ExprType->getOptionalObjectType()) {
lookupVisibleMemberDecls(*this, Unwrapped, CurrDeclContext,
IncludeInstanceMembers,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
return true;
}
assert(IsUnwrappedOptional && "IUOs should be optional if not bound/forced");
Expand All @@ -3552,7 +3553,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
if (!tryTupleExprCompletions(Unwrapped)) {
lookupVisibleMemberDecls(*this, Unwrapped, CurrDeclContext,
IncludeInstanceMembers,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
}
}
return true;
Expand Down Expand Up @@ -3623,7 +3625,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

lookupVisibleMemberDecls(*this, ExprType, CurrDeclContext,
IncludeInstanceMembers,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
}

void collectOperators(SmallVectorImpl<OperatorDecl *> &results) {
Expand Down Expand Up @@ -4099,7 +4102,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
llvm::SaveAndRestore<bool> SaveUnresolved(IsUnresolvedMember, true);
lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext,
/*includeInstanceMembers=*/false,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
}

void getUnresolvedMemberCompletions(ArrayRef<Type> Types) {
Expand Down Expand Up @@ -4161,7 +4165,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
lookupVisibleMemberDecls(*this, MetatypeType::get(BaseType),
CurrDeclContext,
IncludeInstanceMembers,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/false);
if (BaseType->isAnyExistentialType()) {
addKeyword("Protocol", MetatypeType::get(BaseType));
addKeyword("Type", ExistentialMetatypeType::get(BaseType));
Expand Down Expand Up @@ -4195,7 +4200,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
NeedLeadingDot = false;
lookupVisibleMemberDecls(*this, MetatypeType::get(selfTy),
CurrDeclContext, IncludeInstanceMembers,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
}

static bool canUseAttributeOnDecl(DeclAttrKind DAK, bool IsInSil,
Expand Down Expand Up @@ -4864,7 +4870,8 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
Type Meta = MetatypeType::get(CurrTy);
lookupVisibleMemberDecls(*this, Meta, CurrDeclContext,
/*includeInstanceMembers=*/true,
/*includeDerivedRequirements*/true);
/*includeDerivedRequirements*/true,
/*includeProtocolExtensionMembers*/false);
addDesignatedInitializers(NTD);
addAssociatedTypes(NTD);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/IDE/ConformingMethodList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ void ConformingMethodListCallbacks::getMatchingMethods(

lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext,
/*includeInstanceMembers=*/false,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
}

} // anonymous namespace.
Expand Down
3 changes: 2 additions & 1 deletion lib/IDE/TypeContextInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ void ContextInfoCallbacks::getImplicitMembers(

lookupVisibleMemberDecls(LocalConsumer, MetatypeType::get(T), CurDeclContext,
/*includeInstanceMembers=*/false,
/*includeDerivedRequirements*/false);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true);
}

void PrintingTypeContextInfoConsumer::handleResults(
Expand Down
45 changes: 37 additions & 8 deletions lib/Sema/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,13 @@ struct LookupState {
/// This option is only for override completion lookup.
unsigned IncludeDerivedRequirements : 1;

/// Should protocol extension members be included?
unsigned IncludeProtocolExtensionMembers : 1;

LookupState()
: IsQualified(0), IsOnMetatype(0), IsOnSuperclass(0),
InheritsSuperclassInitializers(0), IncludeInstanceMembers(0),
IncludeDerivedRequirements(0) {}
IncludeDerivedRequirements(0), IncludeProtocolExtensionMembers(0) {}

public:
LookupState(const LookupState &) = default;
Expand All @@ -91,6 +94,9 @@ struct LookupState {
bool isIncludingDerivedRequirements() const {
return IncludeDerivedRequirements;
}
bool isIncludingProtocolExtensionMembers() const {
return IncludeProtocolExtensionMembers;
}

LookupState withOnMetatype() const {
auto Result = *this;
Expand Down Expand Up @@ -127,6 +133,12 @@ struct LookupState {
Result.IncludeDerivedRequirements = 1;
return Result;
}

LookupState withIncludeProtocolExtensionMembers() const {
auto Result = *this;
Result.IncludeProtocolExtensionMembers = 1;
return Result;
}
};
} // end anonymous namespace

Expand Down Expand Up @@ -463,13 +475,20 @@ static void lookupDeclsFromProtocolsBeingConformedTo(
};
DeclVisibilityKind ReasonForThisDecl = ReasonForThisProtocol;
if (const auto Witness = NormalConformance->getWitness(VD)) {
if (Witness.getDecl()->getName() == VD->getName()) {
auto *WD = Witness.getDecl();
if (WD->getName() == VD->getName()) {
if (LS.isIncludingDerivedRequirements() &&
Reason == DeclVisibilityKind::MemberOfCurrentNominal &&
isDerivedRequirement(Witness.getDecl())) {
isDerivedRequirement(WD)) {
ReasonForThisDecl =
DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal;
} else if (!LS.isIncludingProtocolExtensionMembers() &&
WD->getDeclContext()->getExtendedProtocolDecl()) {
// Don't skip this requiement.
// Witnesses in protocol extensions aren't reported.
} else {
// lookupVisibleMemberDecls() generally prefers witness members
// over requirements.
continue;
}
}
Expand All @@ -481,11 +500,13 @@ static void lookupDeclsFromProtocolsBeingConformedTo(
}

// Add members from any extensions.
SmallVector<ValueDecl *, 2> FoundDecls;
doGlobalExtensionLookup(BaseTy, Proto->getDeclaredType(), FoundDecls,
FromContext, LS, ReasonForThisProtocol);
for (auto *VD : FoundDecls)
Consumer.foundDecl(VD, ReasonForThisProtocol);
if (LS.isIncludingProtocolExtensionMembers()) {
SmallVector<ValueDecl *, 2> FoundDecls;
doGlobalExtensionLookup(BaseTy, Proto->getDeclaredType(), FoundDecls,
FromContext, LS, ReasonForThisProtocol);
for (auto *VD : FoundDecls)
Consumer.foundDecl(VD, ReasonForThisProtocol);
}
}
}

Expand Down Expand Up @@ -582,6 +603,9 @@ static void lookupVisibleMemberDeclsImpl(
if (LS.isIncludingDerivedRequirements()) {
subLS = subLS.withIncludedDerivedRequirements();
}
if (LS.isIncludingProtocolExtensionMembers()) {
subLS = subLS.withIncludeProtocolExtensionMembers();
}

// Just perform normal dot lookup on the type see if we find extensions or
// anything else. For example, type SomeTy.SomeMember can look up static
Expand Down Expand Up @@ -1111,6 +1135,7 @@ static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
GenericParamList *GenericParams = nullptr;
Type ExtendedType;
auto LS = LookupState::makeUnqualified();
LS = LS.withIncludeProtocolExtensionMembers();

// Skip initializer contexts, we will not find any declarations there.
if (isa<Initializer>(DC)) {
Expand Down Expand Up @@ -1308,6 +1333,7 @@ void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy,
const DeclContext *CurrDC,
bool includeInstanceMembers,
bool includeDerivedRequirements,
bool includeProtocolExtensionMembers,
GenericSignatureBuilder *GSB) {
assert(CurrDC);
LookupState ls = LookupState::makeQualified();
Expand All @@ -1317,6 +1343,9 @@ void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy,
if (includeDerivedRequirements) {
ls = ls.withIncludedDerivedRequirements();
}
if (includeProtocolExtensionMembers) {
ls = ls.withIncludeProtocolExtensionMembers();
}

::lookupVisibleMemberDecls(BaseTy, Consumer, CurrDC, ls,
DeclVisibilityKind::MemberOfCurrentNominal,
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/TypeCheckNameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,8 @@ void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind,
if (baseTypeOrNull) {
lookupVisibleMemberDecls(consumer, baseTypeOrNull, DC,
/*includeInstanceMembers*/true,
/*includeDerivedRequirements*/false, gsb);
/*includeDerivedRequirements*/false,
/*includeProtocolExtensionMembers*/true, gsb);
} else {
lookupVisibleDecls(consumer, DC, /*top level*/ true,
corrections.Loc.getBaseNameLoc());
Expand Down
8 changes: 0 additions & 8 deletions test/IDE/complete_from_stdlib.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@
// RUN: %FileCheck %s -check-prefix=PRIVATE_NOMINAL_MEMBERS_10 < %t.members10.txt
// RUN: %FileCheck %s -check-prefix=NO_STDLIB_PRIVATE < %t.members10.txt

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

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POSTFIX_INT_1 | %FileCheck %s -check-prefix=POSTFIX_RVALUE_INT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POSTFIX_INT_2 | %FileCheck %s -check-prefix=POSTFIX_LVALUE_INT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POSTFIX_OPTIONAL_1 | %FileCheck %s -check-prefix=POSTFIX_OPTIONAL
Expand Down Expand Up @@ -218,12 +216,6 @@ func testArchetypeReplacement6() {
// PRIVATE_NOMINAL_MEMBERS_10: Begin completions
// PRIVATE_NOMINAL_MEMBERS_10-DAG: Decl[InstanceMethod]/CurrNominal: foo({#(t): P1 & P2#})[#Void#]{{; name=.+}}

// rdar://problem/22334700
struct Test1000 : Sequence {
func #^RETURNS_DROPFIRST_SEQUENCE^#
}
// RETURNS_DROPFIRST_SEQUENCE: Decl[InstanceMethod]/Super: dropFirst(_ k: Int = 1) -> DropFirstSequence<Test1000>

func testPostfixOperator1(_ x: Int) {
x#^POSTFIX_INT_1^#
}
Expand Down
38 changes: 38 additions & 0 deletions test/IDE/complete_override_extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token CONFORMANCE_EXT | %FileCheck %s --check-prefix=CONFORMANCE_EXT

protocol P {
init(requirement: Int)
init(customizable: Int)

var requirementVar: Int { get }
var customizableVar: Int { get }

func requirementMethod()
func customizableMethod()
}

extension P {
init(customizable v: Int) { self.init(requirement: v) }
init(nonRequirement v: Int) { self.init(requirement: v) }

var customizableVar: Int { 1 }
var nonRequirementVar: Int { 1 }

func customizableMethod() {}
func nonRequirement() {}
}

struct S: P {
#^CONFORMANCE_EXT^#

// CONFORMANCE_EXT: Begin completions
// CONFORMANCE_EXT-NOT: nonRequirement
// CONFORMANCE_EXT-DAG: Decl[Constructor]/Super: init(requirement: Int) {|};
// CONFORMANCE_EXT-DAG: Decl[Constructor]/Super: init(customizable: Int) {|};
// CONFORMANCE_EXT-DAG: Decl[InstanceVar]/Super: var requirementVar: Int;
// CONFORMANCE_EXT-DAG: Decl[InstanceVar]/Super: var customizableVar: Int;
// CONFORMANCE_EXT-DAG: Decl[InstanceMethod]/Super: func requirementMethod() {|};
// CONFORMANCE_EXT-DAG: Decl[InstanceMethod]/Super: func customizableMethod() {|};
// CONFORMANCE_EXT-NOT: nonRequirement
// CONFORMANCE_EXT: End completions
}