@@ -4244,7 +4244,9 @@ namespace {
4244
4244
4245
4245
template <typename T, typename U>
4246
4246
T *resolveSwiftDeclImpl (const U *decl, Identifier name,
4247
- bool hasKnownSwiftName, ModuleDecl *overlay) {
4247
+ bool hasKnownSwiftName, ModuleDecl *module ,
4248
+ bool allowObjCMismatchFallback,
4249
+ bool cacheResult) {
4248
4250
const auto &languageVersion =
4249
4251
Impl.SwiftContext .LangOpts .EffectiveLanguageVersion ;
4250
4252
@@ -4276,7 +4278,7 @@ namespace {
4276
4278
4277
4279
// First look at Swift types with the same name.
4278
4280
SmallVector<ValueDecl *, 4 > swiftDeclsByName;
4279
- overlay ->lookupValue (name, NLKind::QualifiedLookup, swiftDeclsByName);
4281
+ module ->lookupValue (name, NLKind::QualifiedLookup, swiftDeclsByName);
4280
4282
T *found = nullptr ;
4281
4283
for (auto result : swiftDeclsByName) {
4282
4284
if (auto singleResult = dyn_cast<T>(result)) {
@@ -4298,7 +4300,7 @@ namespace {
4298
4300
SmallVector<Decl *, 4 > matchingTopLevelDecls;
4299
4301
4300
4302
// Get decls with a matching @objc attribute
4301
- overlay ->getTopLevelDeclsWhereAttributesMatch (
4303
+ module ->getTopLevelDeclsWhereAttributesMatch (
4302
4304
matchingTopLevelDecls,
4303
4305
[&name](const DeclAttributes attrs) -> bool {
4304
4306
if (auto objcAttr = attrs.getAttribute <ObjCAttr>())
@@ -4317,7 +4319,7 @@ namespace {
4317
4319
}
4318
4320
}
4319
4321
4320
- if (!found) {
4322
+ if (!found && allowObjCMismatchFallback ) {
4321
4323
// Go back to the first list and find classes with matching Swift names
4322
4324
// *even if the ObjC name doesn't match.*
4323
4325
// This shouldn't be allowed but we need it for source compatibility;
@@ -4335,7 +4337,7 @@ namespace {
4335
4337
}
4336
4338
}
4337
4339
4338
- if (found)
4340
+ if (found && cacheResult )
4339
4341
Impl.ImportedDecls [{decl->getCanonicalDecl (),
4340
4342
getActiveSwiftVersion ()}] = found;
4341
4343
@@ -4346,27 +4348,81 @@ namespace {
4346
4348
T *resolveSwiftDecl (const U *decl, Identifier name,
4347
4349
bool hasKnownSwiftName, ClangModuleUnit *clangModule) {
4348
4350
if (auto overlay = clangModule->getOverlayModule ())
4349
- return resolveSwiftDeclImpl<T>(decl, name, hasKnownSwiftName, overlay);
4351
+ return resolveSwiftDeclImpl<T>(decl, name, hasKnownSwiftName, overlay,
4352
+ /* allowObjCMismatchFallback*/ true , /* cacheResult*/ true );
4350
4353
if (clangModule == Impl.ImportedHeaderUnit ) {
4351
4354
// Use an index-based loop because new owners can come in as we're
4352
4355
// iterating.
4353
4356
for (size_t i = 0 ; i < Impl.ImportedHeaderOwners .size (); ++i) {
4354
4357
ModuleDecl *owner = Impl.ImportedHeaderOwners [i];
4355
- if (T *result = resolveSwiftDeclImpl<T>(decl, name,
4356
- hasKnownSwiftName, owner))
4358
+ if (T *result =
4359
+ resolveSwiftDeclImpl<T>(decl, name, hasKnownSwiftName, owner,
4360
+ /* allowObjCMismatchFallback*/ true , /* cacheResult*/ true ))
4357
4361
return result;
4358
4362
}
4359
4363
}
4360
4364
return nullptr ;
4361
4365
}
4362
4366
4367
+ // / Given some forward declared Objective-C type `@class Foo` or `@protocol Bar`, this
4368
+ // / method attempts to find a matching @objc annotated Swift declaration `@objc class Foo {}`
4369
+ // / or `@objc protocol Bar {}`, in an imported Swift module. That is if the Clang node is in
4370
+ // / a Clang module, the Swift overlay for that module does not count as "non-local". Similarly,
4371
+ // / if the Clang node is in a bridging header, any owners of that header also do not count as
4372
+ // / "non-local". This is intended to find @objc exposed Swift declarations in a different module
4373
+ // / that share the name as the forward declaration.
4374
+ // /
4375
+ // / Pass \p hasKnownSwiftName when the Clang declaration is annotated with NS_SWIFT_NAME or similar,
4376
+ // / such that the @objc provided name is known.
4377
+ template <typename T, typename U>
4378
+ T* hasNonLocalNativeSwiftDecl (U *decl, Identifier name, bool hasKnownSwiftName) {
4379
+ assert (!decl->hasDefinition () && " This method is only intended to be used on incomplete Clang types" );
4380
+
4381
+ // We intentionally do not consider if the declaration has a clang::ExternalSourceSymbolAttr
4382
+ // attribute, since we can't know if the corresponding Swift definition is "local" (ie.
4383
+ // in the overlay or bridging header owner) or not.
4384
+
4385
+ // Check first if the Swift definition is "local"
4386
+ auto owningClangModule = Impl.getClangModuleForDecl (decl, /* allowForwardDeclaration*/ true );
4387
+ if (owningClangModule && resolveSwiftDecl<T>(decl, name, hasKnownSwiftName, owningClangModule))
4388
+ return nullptr ;
4389
+
4390
+ // If not, check all imported Swift modules for a definition
4391
+ if (auto mainModule = Impl.SwiftContext .MainModule ) {
4392
+ llvm::SmallVector<ValueDecl *> results;
4393
+ llvm::SmallVector<ImportedModule> importedModules;
4394
+
4395
+ ModuleDecl::ImportFilter moduleImportFilter = ModuleDecl::ImportFilterKind::Default;
4396
+ moduleImportFilter |= ModuleDecl::ImportFilterKind::Default;
4397
+ moduleImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
4398
+ moduleImportFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl;
4399
+ moduleImportFilter |= ModuleDecl::ImportFilterKind::SPIOnly;
4400
+ moduleImportFilter |= ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay;
4401
+
4402
+ mainModule->getImportedModules (importedModules, moduleImportFilter);
4403
+
4404
+ for (auto &import : importedModules) {
4405
+ if (import .importedModule ->isNonSwiftModule ())
4406
+ continue ;
4407
+
4408
+ if (T *result = resolveSwiftDeclImpl<T>(
4409
+ decl, name, hasKnownSwiftName, import .importedModule ,
4410
+ /* allowObjCMismatchFallback*/ false , /* cacheResult*/ false ))
4411
+ return result;
4412
+ }
4413
+ }
4414
+
4415
+ return nullptr ;
4416
+ }
4417
+
4363
4418
template <typename T, typename U>
4364
4419
bool hasNativeSwiftDecl (const U *decl, Identifier name,
4365
- const DeclContext *dc, T *&swiftDecl) {
4420
+ const DeclContext *dc, T *&swiftDecl,
4421
+ bool hasKnownSwiftName = true ) {
4366
4422
if (!importer::hasNativeSwiftDecl (decl))
4367
4423
return false ;
4368
4424
auto wrapperUnit = cast<ClangModuleUnit>(dc->getModuleScopeContext ());
4369
- swiftDecl = resolveSwiftDecl<T>(decl, name, /* hasCustomSwiftName= */ true ,
4425
+ swiftDecl = resolveSwiftDecl<T>(decl, name, hasKnownSwiftName ,
4370
4426
wrapperUnit);
4371
4427
return true ;
4372
4428
}
@@ -4413,6 +4469,39 @@ namespace {
4413
4469
decl, Diagnostic (diag::forward_declared_protocol_label, decl),
4414
4470
decl->getSourceRange ().getBegin ());
4415
4471
4472
+ if (Impl.ImportForwardDeclarations ) {
4473
+ if (auto native = hasNonLocalNativeSwiftDecl<ProtocolDecl>(decl, name, hasKnownSwiftName)) {
4474
+ const ModuleDecl* moduleForNativeDecl = native->getParentModule ();
4475
+ assert (moduleForNativeDecl);
4476
+ Impl.addImportDiagnostic (decl, Diagnostic (diag::forward_declared_protocol_shadows_imported_objc_Swift_protocol,
4477
+ decl, moduleForNativeDecl->getNameStr ()),
4478
+ decl->getSourceRange ().getBegin ());
4479
+ } else {
4480
+ auto result = Impl.createDeclWithClangNode <ProtocolDecl>(
4481
+ decl, AccessLevel::Public,
4482
+ Impl.getClangModuleForDecl (decl->getCanonicalDecl (),
4483
+ /* allowForwardDeclaration=*/ true ),
4484
+ Impl.importSourceLoc (decl->getBeginLoc ()),
4485
+ Impl.importSourceLoc (decl->getLocation ()), name,
4486
+ ArrayRef<PrimaryAssociatedTypeName>(), None,
4487
+ /* TrailingWhere=*/ nullptr );
4488
+
4489
+ Impl.ImportedDecls [{decl->getCanonicalDecl (), getVersion ()}] = result;
4490
+ result->setAddedImplicitInitializers (); // suppress all initializers
4491
+ addObjCAttribute (result,
4492
+ Impl.importIdentifier (decl->getIdentifier ()));
4493
+ result->setImplicit ();
4494
+ auto attr = AvailableAttr::createPlatformAgnostic (
4495
+ Impl.SwiftContext ,
4496
+ " This Objective-C protocol has only been forward-declared; "
4497
+ " import its owning module to use it" );
4498
+ result->getAttrs ().add (attr);
4499
+ result->getAttrs ().add (new (Impl.SwiftContext )
4500
+ ForbidSerializingReferenceAttr (true ));
4501
+ return result;
4502
+ }
4503
+ }
4504
+
4416
4505
forwardDeclaration = true ;
4417
4506
return nullptr ;
4418
4507
}
@@ -4466,7 +4555,9 @@ namespace {
4466
4555
}
4467
4556
4468
4557
Decl *VisitObjCInterfaceDecl (const clang::ObjCInterfaceDecl *decl) {
4469
- auto createFakeRootClass = [=](Identifier name,
4558
+
4559
+ auto createFakeRootClass = [=](Identifier name, bool cacheResult,
4560
+ bool inheritFromNSObject,
4470
4561
DeclContext *dc = nullptr ) -> ClassDecl * {
4471
4562
if (!dc) {
4472
4563
dc = Impl.getClangModuleForDecl (decl->getCanonicalDecl (),
@@ -4479,8 +4570,14 @@ namespace {
4479
4570
SourceLoc (), None,
4480
4571
nullptr , dc,
4481
4572
/* isActor*/ false );
4482
- Impl.ImportedDecls [{decl->getCanonicalDecl (), getVersion ()}] = result;
4483
- result->setSuperclass (Type ());
4573
+ if (cacheResult)
4574
+ Impl.ImportedDecls [{decl->getCanonicalDecl (), getVersion ()}] = result;
4575
+
4576
+ if (inheritFromNSObject)
4577
+ result->setSuperclass (Impl.getNSObjectType ());
4578
+ else
4579
+ result->setSuperclass (Type ());
4580
+
4484
4581
result->setAddedImplicitInitializers (); // suppress all initializers
4485
4582
result->setHasMissingVTableEntries (false );
4486
4583
addObjCAttribute (result, Impl.importIdentifier (decl->getIdentifier ()));
@@ -4501,7 +4598,9 @@ namespace {
4501
4598
nsObjectTy->getClassOrBoundGenericClass ();
4502
4599
4503
4600
auto result = createFakeRootClass (Impl.SwiftContext .Id_Protocol ,
4504
- nsObjectDecl->getDeclContext ());
4601
+ /* cacheResult */ false ,
4602
+ /* inheritFromNSObject */ false ,
4603
+ nsObjectDecl->getDeclContext ());
4505
4604
result->setForeignClassKind (ClassDecl::ForeignKind::RuntimeOnly);
4506
4605
return result;
4507
4606
}
@@ -4533,21 +4632,30 @@ namespace {
4533
4632
}
4534
4633
}
4535
4634
4635
+ Impl.addImportDiagnostic (
4636
+ decl, Diagnostic (diag::forward_declared_interface_label, decl),
4637
+ decl->getSourceRange ().getBegin ());
4638
+
4536
4639
if (Impl.ImportForwardDeclarations ) {
4537
- // Fake it by making an unavailable opaque @objc root class.
4538
- auto result = createFakeRootClass (name);
4539
- result->setImplicit ();
4540
- auto attr = AvailableAttr::createPlatformAgnostic (Impl.SwiftContext ,
4541
- " This Objective-C class has only been forward-declared; "
4542
- " import its owning module to use it" );
4543
- result->getAttrs ().add (attr);
4544
- result->getAttrs ().add (
4545
- new (Impl.SwiftContext ) ForbidSerializingReferenceAttr (true ));
4546
- return result;
4547
- } else {
4548
- Impl.addImportDiagnostic (
4549
- decl, Diagnostic (diag::forward_declared_interface_label, decl),
4550
- decl->getSourceRange ().getBegin ());
4640
+ if (auto native = hasNonLocalNativeSwiftDecl<ClassDecl>(decl, name, hasKnownSwiftName)) {
4641
+ const ModuleDecl* moduleForNativeDecl = native->getParentModule ();
4642
+ assert (moduleForNativeDecl);
4643
+ Impl.addImportDiagnostic (decl, Diagnostic (diag::forward_declared_interface_shadows_imported_objc_Swift_interface,
4644
+ decl, moduleForNativeDecl->getNameStr ()),
4645
+ decl->getSourceRange ().getBegin ());
4646
+ } else {
4647
+ // Fake it by making an unavailable opaque @objc root class.
4648
+ auto result = createFakeRootClass (name, /* cacheResult */ true ,
4649
+ /* inheritFromNSObject */ true );
4650
+ result->setImplicit ();
4651
+ auto attr = AvailableAttr::createPlatformAgnostic (Impl.SwiftContext ,
4652
+ " This Objective-C class has only been forward-declared; "
4653
+ " import its owning module to use it" );
4654
+ result->getAttrs ().add (attr);
4655
+ result->getAttrs ().add (
4656
+ new (Impl.SwiftContext ) ForbidSerializingReferenceAttr (true ));
4657
+ return result;
4658
+ }
4551
4659
}
4552
4660
4553
4661
forwardDeclaration = true ;
0 commit comments