Skip to content

Commit b3453c1

Browse files
authored
[ClangImporter] Take isCompatibilityAlias() into account in interface printing (swiftlang#16625)
If the Clang declrations are *types*, canonical declaration in Swift is imported for newest version of Swift. In interface generation, if the declaration is versioned and it's imported as a member in either or both version of Swift, we have to take compatibility typealias into account. * Fixed 'ClangModuleUnit::getTopLevelDecls' to take isCompatibilityAlias() into account * Fixed bugs in ClangImporter where member-to-member versioned types aren't properly imported. * Fixed 'SwiftDeclConverter::importFullName' to check equality of getEffectiveContext() * Fixed 'importer::addEntryToLookupTable' to check equality of getEffectiveContext() (moved 'ClangImporter::Implementation::forEachDistinctName' to 'NameImporter')
1 parent 81ce77d commit b3453c1

17 files changed

+4600
-74
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,28 +2455,49 @@ void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl<Decl*> &results) const {
24552455
results.push_back(extension);
24562456
}
24572457

2458+
auto findEnclosingExtension = [](Decl *importedDecl) -> ExtensionDecl * {
2459+
for (auto importedDC = importedDecl->getDeclContext();
2460+
!importedDC->isModuleContext();
2461+
importedDC = importedDC->getParent()) {
2462+
if (auto ext = dyn_cast<ExtensionDecl>(importedDC))
2463+
return ext;
2464+
}
2465+
return nullptr;
2466+
};
24582467
// Retrieve all of the globals that will be mapped to members.
24592468

24602469
// FIXME: Since we don't represent Clang submodules as Swift
24612470
// modules, we're getting everything.
24622471
llvm::SmallPtrSet<ExtensionDecl *, 8> knownExtensions;
24632472
for (auto entry : lookupTable->allGlobalsAsMembers()) {
24642473
auto decl = entry.get<clang::NamedDecl *>();
2465-
auto importedDecl =
2466-
owner.importDecl(decl, owner.CurrentVersion);
2474+
auto importedDecl = owner.importDecl(decl, owner.CurrentVersion);
24672475
if (!importedDecl) continue;
24682476

24692477
// Find the enclosing extension, if there is one.
2470-
ExtensionDecl *ext = nullptr;
2471-
for (auto importedDC = importedDecl->getDeclContext();
2472-
!importedDC->isModuleContext();
2473-
importedDC = importedDC->getParent()) {
2474-
ext = dyn_cast<ExtensionDecl>(importedDC);
2475-
if (ext) break;
2476-
}
2477-
if (!ext) continue;
2478+
ExtensionDecl *ext = findEnclosingExtension(importedDecl);
2479+
if (ext && knownExtensions.insert(ext).second)
2480+
results.push_back(ext);
2481+
2482+
// If this is a compatibility typealias, the canonical type declaration
2483+
// may exist in another extension.
2484+
auto alias = dyn_cast<TypeAliasDecl>(importedDecl);
2485+
if (!alias || !alias->isCompatibilityAlias()) continue;
2486+
2487+
auto aliasedTy = alias->getUnderlyingTypeLoc().getType();
2488+
ext = nullptr;
2489+
importedDecl = nullptr;
2490+
2491+
// Note: We can't use getAnyGeneric() here because `aliasedTy`
2492+
// might be typealias.
2493+
if (auto Ty = dyn_cast<NameAliasType>(aliasedTy.getPointer()))
2494+
importedDecl = Ty->getDecl();
2495+
else if (auto Ty = dyn_cast<AnyGenericType>(aliasedTy.getPointer()))
2496+
importedDecl = Ty->getDecl();
2497+
if (!importedDecl) continue;
24782498

2479-
if (knownExtensions.insert(ext).second)
2499+
ext = findEnclosingExtension(importedDecl);
2500+
if (ext && knownExtensions.insert(ext).second)
24802501
results.push_back(ext);
24812502
}
24822503
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -386,35 +386,6 @@ static bool isNSDictionaryMethod(const clang::ObjCMethodDecl *MD,
386386
return true;
387387
}
388388

389-
void ClangImporter::Implementation::forEachDistinctName(
390-
const clang::NamedDecl *decl,
391-
llvm::function_ref<bool(ImportedName, ImportNameVersion)> action) {
392-
using ImportNameKey = std::pair<DeclName, EffectiveClangContext>;
393-
SmallVector<ImportNameKey, 8> seenNames;
394-
395-
ImportedName newName = importFullName(decl, CurrentVersion);
396-
ImportNameKey key(newName, newName.getEffectiveContext());
397-
if (action(newName, CurrentVersion))
398-
seenNames.push_back(key);
399-
400-
CurrentVersion.forEachOtherImportNameVersion(
401-
[&](ImportNameVersion nameVersion) {
402-
// Check to see if the name is different.
403-
ImportedName newName = importFullName(decl, nameVersion);
404-
ImportNameKey key(newName, newName.getEffectiveContext());
405-
bool seen = llvm::any_of(seenNames,
406-
[&key](const ImportNameKey &existing) -> bool {
407-
if (key.first != existing.first)
408-
return false;
409-
return key.second.equalsWithoutResolving(existing.second);
410-
});
411-
if (seen)
412-
return;
413-
if (action(newName, nameVersion))
414-
seenNames.push_back(key);
415-
});
416-
}
417-
418389
// Build the init(rawValue:) initializer for an imported NS_ENUM.
419390
// enum NSSomeEnum: RawType {
420391
// init?(rawValue: RawType) {
@@ -2175,7 +2146,9 @@ namespace {
21752146
if (canonicalVersion != getActiveSwiftVersion()) {
21762147
auto activeName = Impl.importFullName(D, getActiveSwiftVersion());
21772148
if (activeName &&
2178-
activeName.getDeclName() == canonicalName.getDeclName()) {
2149+
activeName.getDeclName() == canonicalName.getDeclName() &&
2150+
activeName.getEffectiveContext().equalsWithoutResolving(
2151+
canonicalName.getEffectiveContext())) {
21792152
return ImportedName();
21802153
}
21812154
}
@@ -2192,7 +2165,9 @@ namespace {
21922165
if (!alternateName)
21932166
return ImportedName();
21942167

2195-
if (alternateName.getDeclName() == canonicalName.getDeclName()) {
2168+
if (alternateName.getDeclName() == canonicalName.getDeclName() &&
2169+
alternateName.getEffectiveContext().equalsWithoutResolving(
2170+
canonicalName.getEffectiveContext())) {
21962171
if (getVersion() == getActiveSwiftVersion()) {
21972172
assert(canonicalVersion != getActiveSwiftVersion());
21982173
return alternateName;

lib/ClangImporter/ImportName.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,40 @@ ImportedName NameImporter::importName(const clang::NamedDecl *decl,
17791779
return res;
17801780
}
17811781

1782+
bool NameImporter::forEachDistinctImportName(
1783+
const clang::NamedDecl *decl, ImportNameVersion activeVersion,
1784+
llvm::function_ref<bool(ImportedName, ImportNameVersion)> action) {
1785+
using ImportNameKey = std::pair<DeclName, EffectiveClangContext>;
1786+
SmallVector<ImportNameKey, 8> seenNames;
1787+
1788+
ImportedName newName = importName(decl, activeVersion);
1789+
if (!newName)
1790+
return true;
1791+
ImportNameKey key(newName.getDeclName(), newName.getEffectiveContext());
1792+
if (action(newName, activeVersion))
1793+
seenNames.push_back(key);
1794+
1795+
activeVersion.forEachOtherImportNameVersion(
1796+
[&](ImportNameVersion nameVersion) {
1797+
// Check to see if the name is different.
1798+
ImportedName newName = importName(decl, nameVersion);
1799+
if (!newName)
1800+
return;
1801+
ImportNameKey key(newName.getDeclName(), newName.getEffectiveContext());
1802+
1803+
bool seen = llvm::any_of(
1804+
seenNames, [&key](const ImportNameKey &existing) -> bool {
1805+
return key.first == existing.first &&
1806+
key.second.equalsWithoutResolving(existing.second);
1807+
});
1808+
if (seen)
1809+
return;
1810+
if (action(newName, nameVersion))
1811+
seenNames.push_back(key);
1812+
});
1813+
return false;
1814+
}
1815+
17821816
const InheritedNameSet *NameImporter::getAllPropertyNames(
17831817
clang::ObjCInterfaceDecl *classDecl,
17841818
bool forInstance) {
@@ -1846,4 +1880,3 @@ const InheritedNameSet *NameImporter::getAllPropertyNames(
18461880

18471881
return known->second.get();
18481882
}
1849-

lib/ClangImporter/ImportName.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,28 @@ class NameImporter {
334334
clang::DeclarationName preferredName =
335335
clang::DeclarationName());
336336

337+
/// Attempts to import the name of \p decl with each possible
338+
/// ImportNameVersion. \p action will be called with each unique name.
339+
///
340+
/// In this case, "unique" means either the full name is distinct or the
341+
/// effective context is distinct. This method does not attempt to handle
342+
/// "unresolved" contexts in any special way---if one name references a
343+
/// particular Clang declaration and the other has an unresolved context that
344+
/// will eventually reference that declaration, the contexts will still be
345+
/// considered distinct.
346+
///
347+
/// If \p action returns false, the current name will \e not be added to the
348+
/// set of seen names.
349+
///
350+
/// The active name for \p activeVerion is always first, followed by the
351+
/// other names in the order of
352+
/// ImportNameVersion::forEachOtherImportNameVersion.
353+
///
354+
/// Returns \c true if it fails to import name for the active version.
355+
bool forEachDistinctImportName(
356+
const clang::NamedDecl *decl, ImportNameVersion activeVersion,
357+
llvm::function_ref<bool(ImportedName, ImportNameVersion)> action);
358+
337359
/// Imports the name of the given Clang macro into Swift.
338360
Identifier importMacroName(const clang::IdentifierInfo *clangIdentifier,
339361
const clang::MacroInfo *macro);

lib/ClangImporter/ImporterImpl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1352,7 +1352,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
13521352
void forEachDistinctName(
13531353
const clang::NamedDecl *decl,
13541354
llvm::function_ref<bool(importer::ImportedName,
1355-
importer::ImportNameVersion)> action);
1355+
importer::ImportNameVersion)> action) {
1356+
getNameImporter().forEachDistinctImportName(decl, CurrentVersion, action);
1357+
}
13561358

13571359
/// Dump the Swift-specific name lookup tables we generate.
13581360
void dumpSwiftLookupTables();

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,37 +1633,30 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
16331633
// If we have a name to import as, add this entry to the table.
16341634
auto currentVersion =
16351635
ImportNameVersion::fromOptions(nameImporter.getLangOpts());
1636-
if (auto importedName = nameImporter.importName(named, currentVersion)) {
1637-
SmallPtrSet<DeclName, 8> distinctNames;
1638-
distinctNames.insert(importedName.getDeclName());
1639-
table.addEntry(importedName.getDeclName(), named,
1640-
importedName.getEffectiveContext());
1641-
1642-
// Also add the subscript entry, if needed.
1643-
if (importedName.isSubscriptAccessor())
1644-
table.addEntry(DeclName(nameImporter.getContext(),
1645-
DeclBaseName::createSubscript(),
1646-
ArrayRef<Identifier>()),
1647-
named, importedName.getEffectiveContext());
1648-
1649-
currentVersion.forEachOtherImportNameVersion(
1650-
[&](ImportNameVersion alternateVersion) {
1651-
auto alternateName = nameImporter.importName(named, alternateVersion);
1652-
if (!alternateName)
1636+
auto failed = nameImporter.forEachDistinctImportName(
1637+
named, currentVersion,
1638+
[&](ImportedName importedName, ImportNameVersion version) {
1639+
table.addEntry(importedName.getDeclName(), named,
1640+
importedName.getEffectiveContext());
1641+
1642+
// Also add the subscript entry, if needed.
1643+
if (version == currentVersion && importedName.isSubscriptAccessor()) {
1644+
table.addEntry(DeclName(nameImporter.getContext(),
1645+
DeclBaseName::createSubscript(),
1646+
{Identifier()}),
1647+
named, importedName.getEffectiveContext());
1648+
}
1649+
1650+
return true;
1651+
});
1652+
if (failed) {
1653+
if (auto category = dyn_cast<clang::ObjCCategoryDecl>(named)) {
1654+
// If the category is invalid, don't add it.
1655+
if (category->isInvalidDecl())
16531656
return;
1654-
// FIXME: What if the DeclNames are the same but the contexts are
1655-
// different?
1656-
if (distinctNames.insert(alternateName.getDeclName()).second) {
1657-
table.addEntry(alternateName.getDeclName(), named,
1658-
alternateName.getEffectiveContext());
1659-
}
1660-
});
1661-
} else if (auto category = dyn_cast<clang::ObjCCategoryDecl>(named)) {
1662-
// If the category is invalid, don't add it.
1663-
if (category->isInvalidDecl())
1664-
return;
16651657

1666-
table.addCategory(category);
1658+
table.addCategory(category);
1659+
}
16671660
}
16681661

16691662
// Walk the members of any context that can have nested members.
@@ -1864,4 +1857,3 @@ SwiftNameLookupExtension::createExtensionReader(
18641857
// Return the new reader.
18651858
return std::move(tableReader);
18661859
}
1867-

test/APINotes/Inputs/custom-modules/ObsoletedAPINotesTest.apinotes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ Name: M
22
Classes:
33
- Name: FooID
44
SwiftName: Foo_ID
5+
- Name: BarSub
6+
SwiftName: BarContainerCanonical.Sub
57

68
SwiftVersions:
79
- Version: 4
810
Classes:
911
- Name: FooID
1012
SwiftName: FooID
13+
- Name: BarSub
14+
SwiftName: BarContainerOld.Sub
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
@import Foundation;
22
@interface FooID: NSObject
33
@end
4+
5+
@interface BarContainerOld
6+
@end
7+
@interface BarContainerCanonical
8+
@end
9+
@interface BarSub
10+
@end

test/APINotes/obsoleted.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ import ObsoletedAPINotesTest
66

77
let _: FooID // expected-error{{'FooID' has been renamed to 'Foo_ID'}}
88
let _: Foo_ID
9+
10+
let _: BarContainerOld.Sub // expected-error{{'Sub' has been renamed to 'BarContainerCanonical.Sub'}}
11+
let _: BarContainerCanonical.Sub
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Name: APINotesTests
2+
Classes:
3+
- Name: GlobalToMember_Class_Payload
4+
SwiftName: GlobalToMember_Class_Container.Payload
5+
- Name: MemberToGlobal_Class_Payload
6+
SwiftName: MemberToGlobal_Class_Payload
7+
- Name: MemberToMember_Class_Payload
8+
SwiftName: MemberToMember_Class_Swift4.PayloadFor4
9+
- Name: MemberToMember_SameName_Class_Payload
10+
SwiftName: MemberToMember_SameName_Class_Swift4.Payload
11+
- Name: MemberToMember_SameContainer_Class_Payload
12+
SwiftName: MemberToMember_SameContainer_Class_Container.PayloadFor4
13+
Typedefs:
14+
- Name: GlobalToMember_Typedef_Payload
15+
SwiftName: GlobalToMember_Typedef_Container.Payload
16+
- Name: MemberToGlobal_Typedef_Payload
17+
SwiftName: MemberToGlobal_Typedef_Payload
18+
- Name: MemberToMember_Typedef_Payload
19+
SwiftName: MemberToMember_Typedef_Swift4.PayloadFor4
20+
- Name: MemberToMember_SameName_Typedef_Payload
21+
SwiftName: MemberToMember_SameName_Typedef_Swift4.Payload
22+
- Name: MemberToMember_SameContainer_Typedef_Payload
23+
SwiftName: MemberToMember_SameContainer_Typedef_Container.PayloadFor4
24+
SwiftVersions:
25+
- Version: 3
26+
Classes:
27+
- Name: GlobalToMember_Class_Payload
28+
SwiftName: GlobalToMember_Class_Payload
29+
- Name: MemberToGlobal_Class_Payload
30+
SwiftName: MemberToGlobal_Class_Container.Payload
31+
- Name: MemberToMember_Class_Payload
32+
SwiftName: MemberToMember_Class_Swift3.PayloadFor3
33+
- Name: MemberToMember_SameContainer_Class_Payload
34+
SwiftName: MemberToMember_SameContainer_Class_Container.PayloadFor3
35+
- Name: MemberToMember_SameName_Class_Payload
36+
SwiftName: MemberToMember_SameName_Class_Swift3.Payload
37+
Typedefs:
38+
- Name: GlobalToMember_Typedef_Payload
39+
SwiftName: GlobalToMember_Typedef_Payload
40+
- Name: MemberToGlobal_Typedef_Payload
41+
SwiftName: MemberToGlobal_Typedef_Container.Payload
42+
- Name: MemberToMember_Typedef_Payload
43+
SwiftName: MemberToMember_Typedef_Swift3.PayloadFor3
44+
- Name: MemberToMember_SameContainer_Typedef_Payload
45+
SwiftName: MemberToMember_SameContainer_Typedef_Container.PayloadFor3
46+
- Name: MemberToMember_SameName_Typedef_Payload
47+
SwiftName: MemberToMember_SameName_Typedef_Swift3.Payload

0 commit comments

Comments
 (0)