Skip to content

Commit 974fbc1

Browse files
committed
[NFC] Move ObjC method support to NominalTypeDecl
This prepares us to generalize ObjC selector collision diagnostics to also include protocols. NFC in this commit because, even though Sema and ClangImporter now try to record ObjC methods on non-`ClassDecl`s, `NominalTypeDecl::createObjCMethodLookup()` still doesn’t create ObjC method tables for them, so the calls are no-ops.
1 parent 8484f39 commit 974fbc1

File tree

7 files changed

+76
-56
lines changed

7 files changed

+76
-56
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -988,11 +988,11 @@ class ASTContext final {
988988
/// one.
989989
void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration);
990990

991-
/// Load the methods within the given class that produce
991+
/// Load the methods within the given type that produce
992992
/// Objective-C class or instance methods with the given selector.
993993
///
994-
/// \param classDecl The class in which we are searching for @objc methods.
995-
/// The search only considers this class and its extensions; not any
994+
/// \param tyDecl The type in which we are searching for @objc methods.
995+
/// The search only considers this type and its extensions; not any
996996
/// superclasses.
997997
///
998998
/// \param selector The selector to search for.
@@ -1010,7 +1010,11 @@ class ASTContext final {
10101010
///
10111011
/// \param swiftOnly If true, only loads methods from imported Swift modules,
10121012
/// skipping the Clang importer.
1013-
void loadObjCMethods(ClassDecl *classDecl, ObjCSelector selector,
1013+
///
1014+
/// \note Passing a protocol is supported, but currently a no-op, because
1015+
/// Objective-C protocols cannot be extended in ways that make the ObjC method
1016+
/// lookup table relevant.
1017+
void loadObjCMethods(NominalTypeDecl *tyDecl, ObjCSelector selector,
10141018
bool isInstanceMethod, unsigned previousGeneration,
10151019
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods,
10161020
bool swiftOnly = false);

include/swift/AST/Decl.h

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3277,6 +3277,7 @@ class AssociatedTypeDecl : public AbstractTypeParamDecl {
32773277
};
32783278

32793279
class MemberLookupTable;
3280+
class ObjCMethodLookupTable;
32803281
class ConformanceLookupTable;
32813282

32823283
// Kinds of pointer types.
@@ -3382,6 +3383,12 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
33823383
getSatisfiedProtocolRequirementsForMember(const ValueDecl *Member,
33833384
bool Sorted) const;
33843385

3386+
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;
3387+
3388+
/// Create the Objective-C method lookup table, or return \c false if this
3389+
/// kind of type cannot have Objective-C methods.
3390+
bool createObjCMethodLookup();
3391+
33853392
friend class ASTContext;
33863393
friend class MemberLookupTable;
33873394
friend class ConformanceLookupTable;
@@ -3531,6 +3538,24 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
35313538

35323539
void setConformanceLoader(LazyMemberLoader *resolver, uint64_t contextData);
35333540

3541+
/// Look in this type and its extensions (but not any of its protocols or
3542+
/// superclasses) for declarations with a given Objective-C selector.
3543+
///
3544+
/// Note that this can find methods, initializers, deinitializers,
3545+
/// getters, and setters.
3546+
///
3547+
/// \param selector The Objective-C selector of the method we're
3548+
/// looking for.
3549+
///
3550+
/// \param isInstance Whether we are looking for an instance method
3551+
/// (vs. a class method).
3552+
TinyPtrVector<AbstractFunctionDecl *> lookupDirect(ObjCSelector selector,
3553+
bool isInstance);
3554+
3555+
/// Record the presence of an @objc method with the given selector. No-op if
3556+
/// the type is of a kind which cannot contain @objc methods.
3557+
void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector);
3558+
35343559
/// Is this the decl for Optional<T>?
35353560
bool isOptionalDecl() const;
35363561

@@ -3954,13 +3979,7 @@ using AncestryOptions = OptionSet<AncestryFlags>;
39543979
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
39553980
/// to get the declared type ("Complex" in the above example).
39563981
class ClassDecl final : public NominalTypeDecl {
3957-
class ObjCMethodLookupTable;
3958-
39593982
SourceLoc ClassLoc;
3960-
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;
3961-
3962-
/// Create the Objective-C member lookup table.
3963-
void createObjCMethodLookup();
39643983

39653984
struct {
39663985
/// The superclass decl and a bit to indicate whether the
@@ -4225,25 +4244,6 @@ class ClassDecl final : public NominalTypeDecl {
42254244
/// the Objective-C runtime.
42264245
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
42274246

4228-
using NominalTypeDecl::lookupDirect;
4229-
4230-
/// Look in this class and its extensions (but not any of its protocols or
4231-
/// superclasses) for declarations with a given Objective-C selector.
4232-
///
4233-
/// Note that this can find methods, initializers, deinitializers,
4234-
/// getters, and setters.
4235-
///
4236-
/// \param selector The Objective-C selector of the method we're
4237-
/// looking for.
4238-
///
4239-
/// \param isInstance Whether we are looking for an instance method
4240-
/// (vs. a class method).
4241-
TinyPtrVector<AbstractFunctionDecl *> lookupDirect(ObjCSelector selector,
4242-
bool isInstance);
4243-
4244-
/// Record the presence of an @objc method with the given selector.
4245-
void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector);
4246-
42474247
// Implement isa/cast/dyncast/etc.
42484248
static bool classof(const Decl *D) {
42494249
return D->getKind() == DeclKind::Class;

include/swift/AST/SourceFile.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ class SourceFile final : public FileUnit {
243243
std::vector<ObjCUnsatisfiedOptReq> ObjCUnsatisfiedOptReqs;
244244

245245
/// A selector that is used by two different declarations in the same class.
246-
/// Fields: classDecl, selector, isInstanceMethod.
247-
using ObjCMethodConflict = std::tuple<ClassDecl *, ObjCSelector, bool>;
246+
/// Fields: typeDecl, selector, isInstanceMethod.
247+
using ObjCMethodConflict = std::tuple<NominalTypeDecl *, ObjCSelector, bool>;
248248

249249
/// List of Objective-C member conflicts we have found during type checking.
250250
std::vector<ObjCMethodConflict> ObjCMethodConflicts;

lib/AST/ASTContext.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,11 +1906,24 @@ void ASTContext::loadExtensions(NominalTypeDecl *nominal,
19061906
}
19071907

19081908
void ASTContext::loadObjCMethods(
1909-
ClassDecl *classDecl, ObjCSelector selector, bool isInstanceMethod,
1909+
NominalTypeDecl *tyDecl, ObjCSelector selector, bool isInstanceMethod,
19101910
unsigned previousGeneration,
19111911
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods, bool swiftOnly) {
19121912
PrettyStackTraceSelector stackTraceSelector("looking for", selector);
1913-
PrettyStackTraceDecl stackTraceDecl("...in", classDecl);
1913+
PrettyStackTraceDecl stackTraceDecl("...in", tyDecl);
1914+
1915+
// @objc protocols cannot have @objc extension members, so if we've recorded
1916+
// everything in the protocol definition, we've recorded everything. And we
1917+
// only ever use the ObjCSelector version of `NominalTypeDecl::lookupDirect()`
1918+
// on protocols in primary file typechecking, so we don't care about protocols
1919+
// that need to be loaded from files.
1920+
// TODO: Rework `ModuleLoader::loadObjCMethods()` to support protocols too if
1921+
// selector-based `NominalTypeDecl::lookupDirect()` ever needs to work
1922+
// in more situations.
1923+
ClassDecl *classDecl = dyn_cast<ClassDecl>(tyDecl);
1924+
if (!classDecl)
1925+
return;
1926+
19141927
for (auto &loader : getImpl().ModuleLoaders) {
19151928
// Ignore the Clang importer if we've been asked for Swift-only results.
19161929
if (swiftOnly && loader.get() == getClangModuleLoader())

lib/AST/NameLookup.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,10 +1125,10 @@ namespace {
11251125

11261126
/// Class member lookup table, which is a member lookup table with a second
11271127
/// table for lookup based on Objective-C selector.
1128-
class ClassDecl::ObjCMethodLookupTable
1128+
class swift::ObjCMethodLookupTable
11291129
: public llvm::DenseMap<std::pair<ObjCSelector, char>,
11301130
StoredObjCMethods>,
1131-
public ASTAllocated<ClassDecl::ObjCMethodLookupTable>
1131+
public ASTAllocated<ObjCMethodLookupTable>
11321132
{};
11331133

11341134
MemberLookupTable::MemberLookupTable(ASTContext &ctx) {
@@ -1483,23 +1483,27 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
14831483
includeAttrImplements);
14841484
}
14851485

1486-
void ClassDecl::createObjCMethodLookup() {
1486+
bool NominalTypeDecl::createObjCMethodLookup() {
14871487
assert(!ObjCMethodLookup && "Already have an Objective-C member table");
1488+
1489+
// Most types cannot have ObjC methods.
1490+
if (!(isa<ClassDecl>(this)))
1491+
return false;
1492+
14881493
auto &ctx = getASTContext();
14891494
ObjCMethodLookup = new (ctx) ObjCMethodLookupTable();
14901495

14911496
// Register a cleanup with the ASTContext to call the lookup table
14921497
// destructor.
1493-
ctx.addCleanup([this]() {
1494-
this->ObjCMethodLookup->~ObjCMethodLookupTable();
1495-
});
1498+
ctx.addDestructorCleanup(*ObjCMethodLookup);
1499+
1500+
return true;
14961501
}
14971502

14981503
TinyPtrVector<AbstractFunctionDecl *>
1499-
ClassDecl::lookupDirect(ObjCSelector selector, bool isInstance) {
1500-
if (!ObjCMethodLookup) {
1501-
createObjCMethodLookup();
1502-
}
1504+
NominalTypeDecl::lookupDirect(ObjCSelector selector, bool isInstance) {
1505+
if (!ObjCMethodLookup && !createObjCMethodLookup())
1506+
return {};
15031507

15041508
// If any modules have been loaded since we did the search last (or if we
15051509
// hadn't searched before), look in those modules, too.
@@ -1514,11 +1518,10 @@ ClassDecl::lookupDirect(ObjCSelector selector, bool isInstance) {
15141518
return stored.Methods;
15151519
}
15161520

1517-
void ClassDecl::recordObjCMethod(AbstractFunctionDecl *method,
1518-
ObjCSelector selector) {
1519-
if (!ObjCMethodLookup) {
1520-
createObjCMethodLookup();
1521-
}
1521+
void NominalTypeDecl::recordObjCMethod(AbstractFunctionDecl *method,
1522+
ObjCSelector selector) {
1523+
if (!ObjCMethodLookup && !createObjCMethodLookup())
1524+
return;
15221525

15231526
// Record the method.
15241527
bool isInstanceMethod = method->isObjCInstanceMethod();

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4815,12 +4815,12 @@ namespace {
48154815
decl->setIsDynamic(true);
48164816

48174817
// If the declaration we attached the 'objc' attribute to is within a
4818-
// class, record it in the class.
4818+
// type, record it in the type.
48194819
if (auto contextTy = decl->getDeclContext()->getDeclaredInterfaceType()) {
4820-
if (auto classDecl = contextTy->getClassOrBoundGenericClass()) {
4820+
if (auto tyDecl = contextTy->getNominalOrBoundGenericNominal()) {
48214821
if (auto method = dyn_cast<AbstractFunctionDecl>(decl)) {
48224822
if (name)
4823-
classDecl->recordObjCMethod(method, *name);
4823+
tyDecl->recordObjCMethod(method, *name);
48244824
}
48254825
}
48264826
}

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,9 +2008,9 @@ void markAsObjC(ValueDecl *D, ObjCReason reason,
20082008
}
20092009
}
20102010

2011-
// Record the method in the class, if it's a member of one.
2012-
if (auto classDecl = D->getDeclContext()->getSelfClassDecl()) {
2013-
classDecl->recordObjCMethod(method, selector);
2011+
// Record the method in the type, if it's a member of one.
2012+
if (auto tyDecl = D->getDeclContext()->getSelfNominalTypeDecl()) {
2013+
tyDecl->recordObjCMethod(method, selector);
20142014
}
20152015

20162016
// Record the method in the source file.
@@ -2406,11 +2406,11 @@ bool swift::diagnoseUnintendedObjCMethodOverrides(SourceFile &sf) {
24062406
/// Retrieve the source file for the given Objective-C member conflict.
24072407
static TinyPtrVector<AbstractFunctionDecl *>
24082408
getObjCMethodConflictDecls(const SourceFile::ObjCMethodConflict &conflict) {
2409-
ClassDecl *classDecl = std::get<0>(conflict);
2409+
NominalTypeDecl *typeDecl = std::get<0>(conflict);
24102410
ObjCSelector selector = std::get<1>(conflict);
24112411
bool isInstanceMethod = std::get<2>(conflict);
24122412

2413-
return classDecl->lookupDirect(selector, isInstanceMethod);
2413+
return typeDecl->lookupDirect(selector, isInstanceMethod);
24142414
}
24152415

24162416
static ObjCAttr *getObjCAttrIfFromAccessNote(ValueDecl *VD) {

0 commit comments

Comments
 (0)