@@ -610,6 +610,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
610610 Bits.ModuleDecl .HasIncrementalInfo = 0 ;
611611 Bits.ModuleDecl .HasHermeticSealAtLink = 0 ;
612612 Bits.ModuleDecl .IsConcurrencyChecked = 0 ;
613+ Bits.ModuleDecl .ObjCNameLookupCachePopulated = 0 ;
613614}
614615
615616ImplicitImportList ModuleDecl::getImplicitImports () const {
@@ -1189,6 +1190,60 @@ void ModuleDecl::getTopLevelDeclsWhereAttributesMatch(
11891190 FORWARD (getTopLevelDeclsWhereAttributesMatch, (Results, matchAttributes));
11901191}
11911192
1193+ void ModuleDecl::lookupTopLevelDeclsByObjCName (SmallVectorImpl<Decl *> &Results,
1194+ DeclName name) {
1195+ if (!isObjCNameLookupCachePopulated ())
1196+ populateObjCNameLookupCache ();
1197+
1198+ // A top level decl can't be special anyways
1199+ if (name.isSpecial ())
1200+ return ;
1201+
1202+ auto resultsForFileUnit = ObjCNameLookupCache.find (name.getBaseIdentifier ());
1203+ if (resultsForFileUnit == ObjCNameLookupCache.end ())
1204+ return ;
1205+
1206+ Results.append (resultsForFileUnit->second .begin (),
1207+ resultsForFileUnit->second .end ());
1208+ }
1209+
1210+ void ModuleDecl::populateObjCNameLookupCache () {
1211+ SmallVector<Decl *> topLevelObjCExposedDeclsInFileUnit;
1212+ auto hasObjCAttrNamePredicate = [](const DeclAttributes &attrs) -> bool {
1213+ return attrs.hasAttribute <ObjCAttr>();
1214+ };
1215+
1216+ for (FileUnit *file : getFiles ()) {
1217+ file->getTopLevelDeclsWhereAttributesMatch (
1218+ topLevelObjCExposedDeclsInFileUnit, hasObjCAttrNamePredicate);
1219+ if (auto *synth = file->getSynthesizedFile ()) {
1220+ synth->getTopLevelDeclsWhereAttributesMatch (
1221+ topLevelObjCExposedDeclsInFileUnit, hasObjCAttrNamePredicate);
1222+ }
1223+ }
1224+
1225+ for (Decl *decl : topLevelObjCExposedDeclsInFileUnit) {
1226+ if (ValueDecl *VD = dyn_cast<ValueDecl>(decl); VD && VD->hasName ()) {
1227+ const auto &declObjCAttribute = VD->getAttrs ().getAttribute <ObjCAttr>();
1228+ // No top level decl (class, protocol, extension etc.) is allowed to have a
1229+ // compound name, @objc provided or otherwise. Global functions are allowed to
1230+ // have compound names, but not allowed to have @objc attributes. Thus we
1231+ // are sure to not hit asserts getting the simple name.
1232+ //
1233+ // Similarly, init, dealloc and subscript (the special names) can't be top
1234+ // level decls, so we won't hit asserts getting the base identifier out of the
1235+ // value decl.
1236+ const Identifier &declObjCName =
1237+ declObjCAttribute->hasName ()
1238+ ? declObjCAttribute->getName ()->getSimpleName ()
1239+ : VD->getName ().getBaseIdentifier ();
1240+ ObjCNameLookupCache[declObjCName].push_back (decl);
1241+ }
1242+ }
1243+
1244+ setIsObjCNameLookupCachePopulated (true );
1245+ }
1246+
11921247void SourceFile::getTopLevelDecls (SmallVectorImpl<Decl*> &Results) const {
11931248 auto decls = getTopLevelDecls ();
11941249 Results.append (decls.begin (), decls.end ());
@@ -3360,6 +3415,9 @@ bool SourceFile::shouldCrossImport() const {
33603415void ModuleDecl::clearLookupCache () {
33613416 getASTContext ().getImportCache ().clear ();
33623417
3418+ setIsObjCNameLookupCachePopulated (false );
3419+ ObjCNameLookupCache.clear ();
3420+
33633421 if (!Cache)
33643422 return ;
33653423
0 commit comments