Skip to content

Commit 6357412

Browse files
authored
Merge pull request swiftlang#28784 from CodaFi/wont-you-be-my-nearest-neighbor
Factor out and document the "nearest-overridden" algorithm
2 parents e4b1a85 + ddda178 commit 6357412

File tree

1 file changed

+60
-36
lines changed

1 file changed

+60
-36
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,6 +2149,63 @@ namespace {
21492149
}
21502150
};
21512151

2152+
/// Search the member tables for this class and its superclasses and try to identify the nearest VarDecl
2153+
/// that serves as a base for an override. We have to do this ourselves because Objective-C has no
2154+
/// semantic notion of overrides, and freely allows users to refine the type of any member property in a
2155+
/// derived class.
2156+
///
2157+
/// The override must be the nearest possible one so there are not breaks in the override chain. That is,
2158+
/// suppose C refines B refines A and each successively redeclares a member with a different type. It
2159+
/// should be the case that the nearest override from C is B and from B is A. If the override point from
2160+
/// C were A, then B would record an override on A as well and we would introduce a semantic ambiguity.
2161+
///
2162+
/// There is also a special case for finding a method that stomps over a getter. If this is the case and no
2163+
/// override point is identified, we will not import the property to force users to explicitly call the method.
2164+
static std::pair<VarDecl *, bool>
2165+
identifyNearestOverridenDecl(ClangImporter::Implementation &Impl,
2166+
DeclContext *dc,
2167+
const clang::ObjCPropertyDecl *decl,
2168+
Identifier name,
2169+
ClassDecl *subject) {
2170+
bool foundMethod = false;
2171+
for (; subject; (subject = subject->getSuperclassDecl())) {
2172+
llvm::SmallVector<ValueDecl *, 8> lookup;
2173+
auto found = Impl.MembersForNominal.find(subject);
2174+
if (found != Impl.MembersForNominal.end()) {
2175+
lookup.append(found->second.begin(), found->second.end());
2176+
namelookup::pruneLookupResultSet(dc, NL_QualifiedDefault, lookup);
2177+
}
2178+
2179+
for (auto *&result : lookup) {
2180+
// Skip declarations that don't match the name we're looking for.
2181+
if (result->getBaseName() != name)
2182+
continue;
2183+
2184+
if (auto *fd = dyn_cast<FuncDecl>(result)) {
2185+
if (fd->isInstanceMember() != decl->isInstanceProperty())
2186+
continue;
2187+
2188+
if (fd->getFullName().getArgumentNames().empty()) {
2189+
foundMethod = true;
2190+
}
2191+
} else {
2192+
auto *var = cast<VarDecl>(result);
2193+
if (var->isInstanceMember() != decl->isInstanceProperty())
2194+
continue;
2195+
2196+
// If the selectors of the getter match in Objective-C, we have an
2197+
// override.
2198+
if (var->getObjCGetterSelector() ==
2199+
Impl.importSelector(decl->getGetterName())) {
2200+
return {var, foundMethod};
2201+
}
2202+
}
2203+
}
2204+
}
2205+
2206+
return {nullptr, foundMethod};
2207+
}
2208+
21522209
/// Convert Clang declarations into the corresponding Swift
21532210
/// declarations.
21542211
class SwiftDeclConverter
@@ -5013,47 +5070,14 @@ namespace {
50135070
// property. If so, suppress the property; the user will have to use
50145071
// the methods directly, to avoid ambiguities.
50155072
if (auto *subject = dc->getSelfClassDecl()) {
5016-
bool foundMethod = false;
5017-
50185073
if (auto *classDecl = dyn_cast<ClassDecl>(dc)) {
50195074
// Start looking into the superclass.
50205075
subject = classDecl->getSuperclassDecl();
50215076
}
50225077

5023-
for (; subject; (subject = subject->getSuperclassDecl())) {
5024-
llvm::SmallVector<ValueDecl *, 8> lookup;
5025-
auto found = Impl.MembersForNominal.find(subject);
5026-
if (found != Impl.MembersForNominal.end()) {
5027-
lookup.append(found->second.begin(), found->second.end());
5028-
namelookup::pruneLookupResultSet(dc, NL_QualifiedDefault, lookup);
5029-
}
5030-
5031-
for (auto *&result : lookup) {
5032-
// Skip declarations that don't match the name we're looking for.
5033-
if (result->getBaseName() != name)
5034-
continue;
5035-
5036-
if (auto *fd = dyn_cast<FuncDecl>(result)) {
5037-
if (fd->isInstanceMember() != decl->isInstanceProperty())
5038-
continue;
5039-
5040-
if (fd->getFullName().getArgumentNames().empty()) {
5041-
foundMethod = true;
5042-
}
5043-
} else {
5044-
auto *var = cast<VarDecl>(result);
5045-
if (var->isInstanceMember() != decl->isInstanceProperty())
5046-
continue;
5047-
5048-
// If the selectors of the getter match in Objective-C, we have an
5049-
// override.
5050-
if (var->getObjCGetterSelector() ==
5051-
Impl.importSelector(decl->getGetterName())) {
5052-
overridden = var;
5053-
}
5054-
}
5055-
}
5056-
}
5078+
bool foundMethod = false;
5079+
std::tie(overridden, foundMethod)
5080+
= identifyNearestOverridenDecl(Impl, dc, decl, name, subject);
50575081

50585082
if (foundMethod && !overridden)
50595083
return nullptr;

0 commit comments

Comments
 (0)