@@ -954,25 +954,56 @@ class swift::MemberLookupTable {
954
954
}
955
955
};
956
956
957
- namespace {
957
+ // / Class member lookup table, which is a member lookup table with a second
958
+ // / table for lookup based on Objective-C selector.
959
+ class ClassDecl ::ObjCMethodLookupTable {
960
+ using Key = std::pair<ObjCSelector, /* isInstanceMethod*/ char >;
961
+
958
962
// / Stores the set of Objective-C methods with a given selector within the
959
963
// / Objective-C method lookup table.
960
- struct StoredObjCMethods {
964
+ struct StoredMethods {
961
965
// / The generation count at which this list was last updated.
962
966
unsigned Generation = 0 ;
963
967
964
968
// / The set of methods with the given selector.
965
969
llvm::TinyPtrVector<AbstractFunctionDecl *> Methods;
966
970
};
967
- } // end anonymous namespace
968
971
969
- // / Class member lookup table, which is a member lookup table with a second
970
- // / table for lookup based on Objective-C selector.
971
- class ClassDecl ::ObjCMethodLookupTable
972
- : public llvm::DenseMap<std::pair<ObjCSelector, char >,
973
- StoredObjCMethods>
974
- {
972
+ llvm::DenseMap<Key, StoredMethods> Table;
973
+ llvm::DenseSet<Key> LazilyCompleteNames;
974
+
975
975
public:
976
+ // / Create a new Obj-C method lookup table.
977
+ explicit ObjCMethodLookupTable (ASTContext &ctx) {
978
+ // Make sure the destructor is called when the AST context is torn down.
979
+ ctx.addCleanup ([this ]() {
980
+ this ->~ObjCMethodLookupTable ();
981
+ });
982
+ }
983
+
984
+ // / Returns \c true if the lookup table has a complete accounting of the
985
+ // / given name.
986
+ bool isLazilyComplete (ObjCSelector selector, bool isInstanceMethod) const {
987
+ return LazilyCompleteNames.count ({selector, isInstanceMethod});
988
+ }
989
+
990
+ // / Mark a given lazily-loaded name as being complete.
991
+ void markLazilyComplete (ObjCSelector selector, bool isInstanceMethod) {
992
+ LazilyCompleteNames.insert ({selector, isInstanceMethod});
993
+ }
994
+
995
+ // / Clears the cache of lazily-complete names. This _must_ be called when
996
+ // / new extensions with lazy members are added to the type, or lookups will
997
+ // / return inconsistent or stale results.
998
+ void clearLazilyCompleteCache () {
999
+ LazilyCompleteNames.clear ();
1000
+ }
1001
+
1002
+ void addMember (Decl *member);
1003
+ void addMembers (DeclRange members);
1004
+
1005
+ StoredMethods &operator [](Key key) { return Table[key]; }
1006
+
976
1007
// Only allow allocation of member lookup tables using the allocator in
977
1008
// ASTContext or by doing a placement new.
978
1009
void *operator new (size_t Bytes, ASTContext &C,
@@ -1045,13 +1076,22 @@ void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) {
1045
1076
}
1046
1077
1047
1078
void NominalTypeDecl::addedExtension (ExtensionDecl *ext) {
1048
- if (!LookupTable) return ;
1079
+ ClassDecl::ObjCMethodLookupTable *ObjCLookupTable = nullptr ;
1080
+ if (auto *CD = dyn_cast<ClassDecl>(this ))
1081
+ ObjCLookupTable = CD->ObjCMethodLookup ;
1049
1082
1050
1083
if (ext->hasLazyMembers ()) {
1051
- LookupTable->addMembers (ext->getCurrentMembersWithoutLoading ());
1052
- LookupTable->clearLazilyCompleteCache ();
1084
+ if (LookupTable) {
1085
+ LookupTable->addMembers (ext->getCurrentMembersWithoutLoading ());
1086
+ LookupTable->clearLazilyCompleteCache ();
1087
+ }
1088
+ if (ObjCLookupTable)
1089
+ ObjCLookupTable->clearLazilyCompleteCache ();
1053
1090
} else {
1054
- LookupTable->addMembers (ext->getMembers ());
1091
+ if (LookupTable)
1092
+ LookupTable->addMembers (ext->getMembers ());
1093
+ if (ObjCLookupTable)
1094
+ ObjCLookupTable->addMembers (ext->getMembers ());
1055
1095
}
1056
1096
}
1057
1097
@@ -1297,63 +1337,80 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
1297
1337
includeAttrImplements);
1298
1338
}
1299
1339
1300
- void ClassDecl::createObjCMethodLookup () {
1301
- assert (!ObjCMethodLookup && " Already have an Objective-C member table" );
1302
- auto &ctx = getASTContext ();
1303
- ObjCMethodLookup = new (ctx) ObjCMethodLookupTable ();
1340
+ void ClassDecl::ObjCMethodLookupTable::addMember (Decl *member) {
1341
+ if (auto *storage = dyn_cast<AbstractStorageDecl>(member)) {
1342
+ // If this is an @objc var, make sure to add the necessary accessors.
1343
+ if (storage->isObjC ()) {
1344
+ storage->visitEmittedAccessors (
1345
+ [&](AccessorDecl *accessor) { addMember (accessor); });
1346
+ }
1347
+ return ;
1348
+ }
1304
1349
1305
- // Register a cleanup with the ASTContext to call the lookup table
1306
- // destructor.
1307
- ctx.addCleanup ([this ]() {
1308
- this ->ObjCMethodLookup ->~ObjCMethodLookupTable ();
1309
- });
1350
+ // We're only interested in tracking @objc functions.
1351
+ auto *afd = dyn_cast<AbstractFunctionDecl>(member);
1352
+ if (!afd || !afd->isObjC ())
1353
+ return ;
1354
+
1355
+ auto &stored = Table[{afd->getObjCSelector (), afd->isObjCInstanceMethod ()}];
1356
+ stored.Methods .push_back (afd);
1310
1357
}
1311
1358
1312
- MutableArrayRef<AbstractFunctionDecl *>
1313
- ClassDecl::lookupDirect (ObjCSelector selector, bool isInstance) {
1314
- if (!ObjCMethodLookup) {
1315
- createObjCMethodLookup ();
1316
- }
1359
+ void ClassDecl::ObjCMethodLookupTable::addMembers (DeclRange members) {
1360
+ for (auto *member : members)
1361
+ addMember (member);
1362
+ }
1317
1363
1318
- // If any modules have been loaded since we did the search last (or if we
1319
- // hadn't searched before), look in those modules, too.
1320
- auto &stored = (*ObjCMethodLookup)[{selector, isInstance}];
1321
- ASTContext &ctx = getASTContext ();
1322
- if (ctx.getCurrentGeneration () > stored.Generation ) {
1323
- ctx.loadObjCMethods (this , selector, isInstance, stored.Generation ,
1324
- stored.Methods );
1325
- stored.Generation = ctx.getCurrentGeneration ();
1364
+ void ClassDecl::prepareObjCMethodLookup () {
1365
+ if (ObjCMethodLookup) {
1366
+ // Make sure the list of extensions is up-to-date, which may trigger the
1367
+ // clearing of the lazily-complete cache.
1368
+ (void )getExtensions ();
1369
+ return ;
1326
1370
}
1327
1371
1328
- return { stored. Methods . begin (), stored. Methods . end () } ;
1329
- }
1372
+ auto &ctx = getASTContext () ;
1373
+ ObjCMethodLookup = new (ctx) ObjCMethodLookupTable (ctx);
1330
1374
1331
- void ClassDecl::recordObjCMethod (AbstractFunctionDecl *method,
1332
- ObjCSelector selector) {
1333
- if (!ObjCMethodLookup) {
1334
- createObjCMethodLookup ();
1335
- }
1375
+ // Pre-populate the table with any entries from the main module.
1376
+ if (!hasLazyMembers ())
1377
+ ObjCMethodLookup->addMembers (getMembers ());
1336
1378
1337
- // Record the method.
1338
- bool isInstanceMethod = method-> isObjCInstanceMethod ();
1339
- auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}]. Methods ;
1379
+ for ( auto *ext : getExtensions ()) {
1380
+ if (ext-> wasDeserialized () || ext-> hasClangNode ())
1381
+ continue ;
1340
1382
1341
- // Check whether we have a duplicate. This only checks more than one
1342
- // element in ill-formed code, so the linear search is acceptable.
1343
- if (std::find (vec.begin (), vec.end (), method) != vec.end ())
1344
- return ;
1383
+ ObjCMethodLookup->addMembers (ext->getMembers ());
1384
+ }
1385
+ }
1345
1386
1346
- if (auto *sf = method->getParentSourceFile ()) {
1347
- if (vec.size () == 1 ) {
1348
- // We have a conflict.
1349
- sf->ObjCMethodConflicts .push_back (std::make_tuple (this , selector,
1350
- isInstanceMethod));
1351
- } if (vec.empty ()) {
1352
- sf->ObjCMethodList .push_back (method);
1353
- }
1387
+ TinyPtrVector<AbstractFunctionDecl *>
1388
+ ObjCMethodDirectLookupRequest::evaluate (Evaluator &evaluator, ClassDecl *CD,
1389
+ ObjCSelector selector,
1390
+ bool isInstance) const {
1391
+ CD->prepareObjCMethodLookup ();
1392
+ auto &stored = (*CD->ObjCMethodLookup )[{selector, isInstance}];
1393
+
1394
+ // If we haven't seen this name before, or additional imported extensions have
1395
+ // been bound since we last did a lookup, ask the module loaders to update the
1396
+ // lookup table.
1397
+ if (!CD->ObjCMethodLookup ->isLazilyComplete (selector, isInstance)) {
1398
+ auto &ctx = CD->getASTContext ();
1399
+ ctx.loadObjCMethods (CD, selector, isInstance, /* ignoreClang*/ false ,
1400
+ stored.Generation , stored.Methods );
1401
+ stored.Generation = ctx.getCurrentGeneration ();
1402
+ CD->ObjCMethodLookup ->markLazilyComplete (selector, isInstance);
1354
1403
}
1404
+ return stored.Methods ;
1405
+ }
1355
1406
1356
- vec.push_back (method);
1407
+ TinyPtrVector<AbstractFunctionDecl *>
1408
+ ClassDecl::lookupDirect (ObjCSelector selector, bool isInstance) const {
1409
+ auto &ctx = getASTContext ();
1410
+ auto *mutableThis = const_cast <ClassDecl *>(this );
1411
+ return evaluateOrDefault (
1412
+ ctx.evaluator ,
1413
+ ObjCMethodDirectLookupRequest{mutableThis, selector, isInstance}, {});
1357
1414
}
1358
1415
1359
1416
// / Determine whether the given declaration is an acceptable lookup
0 commit comments