@@ -1679,6 +1679,67 @@ DeclName ClangImporter::Implementation::importFullName(
1679
1679
baseName = baseName.substr (removePrefix.size ());
1680
1680
}
1681
1681
1682
+ // Objective-C protocols may have the suffix "Protocol" appended if
1683
+ // the non-suffixed name would conflict with another entity in the
1684
+ // same top-level module.
1685
+ SmallString<16 > baseNameWithProtocolSuffix;
1686
+ if (auto objcProto = dyn_cast<clang::ObjCProtocolDecl>(D)) {
1687
+ if (objcProto->hasDefinition ()) {
1688
+ // Test to see if there is a value with the same name as the protocol
1689
+ // in the same module.
1690
+ // FIXME: This will miss macros.
1691
+ auto clangModule = getClangSubmoduleForDecl (objcProto);
1692
+ if (clangModule.hasValue () && clangModule.getValue ())
1693
+ clangModule = clangModule.getValue ()->getTopLevelModule ();
1694
+
1695
+ auto isInSameModule = [&](const clang::Decl *D) -> bool {
1696
+ auto declModule = getClangSubmoduleForDecl (D);
1697
+ if (!declModule.hasValue ())
1698
+ return false ;
1699
+ // Handle the bridging header case. This is pretty nasty since things
1700
+ // can get added to it *later*, but there's not much we can do.
1701
+ if (!declModule.getValue ())
1702
+ return *clangModule == nullptr ;
1703
+ return *clangModule == declModule.getValue ()->getTopLevelModule ();
1704
+ };
1705
+
1706
+ // Allow this lookup to find hidden names. We don't want the
1707
+ // decision about whether to rename the protocol to depend on
1708
+ // what exactly the user has imported. Indeed, if we're being
1709
+ // asked to resolve a serialization cross-reference, the user
1710
+ // may not have imported this module at all, which means a
1711
+ // normal lookup wouldn't even find the protocol!
1712
+ //
1713
+ // Meanwhile, we don't need to worry about finding unwanted
1714
+ // hidden declarations from different modules because we do a
1715
+ // module check before deciding that there's a conflict.
1716
+ bool hasConflict = false ;
1717
+ clang::LookupResult lookupResult (getClangSema (), D->getDeclName (),
1718
+ clang::SourceLocation (),
1719
+ clang::Sema::LookupOrdinaryName);
1720
+ lookupResult.setAllowHidden (true );
1721
+ lookupResult.suppressDiagnostics ();
1722
+
1723
+ if (getClangSema ().LookupName (lookupResult, /* scope=*/ nullptr )) {
1724
+ hasConflict = std::any_of (lookupResult.begin (), lookupResult.end (),
1725
+ isInSameModule);
1726
+ }
1727
+ if (!hasConflict) {
1728
+ lookupResult.clear (clang::Sema::LookupTagName);
1729
+ if (getClangSema ().LookupName (lookupResult, /* scope=*/ nullptr )) {
1730
+ hasConflict = std::any_of (lookupResult.begin (), lookupResult.end (),
1731
+ isInSameModule);
1732
+ }
1733
+ }
1734
+
1735
+ if (hasConflict) {
1736
+ baseNameWithProtocolSuffix = baseName;
1737
+ baseNameWithProtocolSuffix += SWIFT_PROTOCOL_SUFFIX;
1738
+ baseName = baseNameWithProtocolSuffix;
1739
+ }
1740
+ }
1741
+ }
1742
+
1682
1743
// Local function to determine whether the given declaration is subject to
1683
1744
// a swift_private attribute.
1684
1745
auto hasSwiftPrivate = [this ](const clang::NamedDecl *D) {
0 commit comments