Skip to content

Commit ec23dca

Browse files
committed
[ClangImporter] Find Swift 3 / 4 names via dynamic lookup too.
Finishes rdar://problem/29170671
1 parent 94d9d6a commit ec23dca

File tree

6 files changed

+91
-54
lines changed

6 files changed

+91
-54
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3041,37 +3041,30 @@ void ClangImporter::Implementation::lookupObjCMembers(
30413041
// If the entry is not visible, skip it.
30423042
if (!isVisibleClangEntry(clangCtx, clangDecl)) continue;
30433043

3044-
// Import the declaration.
3045-
auto decl =
3046-
cast_or_null<ValueDecl>(importDeclReal(clangDecl, CurrentVersion));
3047-
if (!decl)
3048-
continue;
3049-
3050-
// If the name we found matches, report the declaration.
3051-
bool matchedAny = false;
3052-
if (decl->getFullName().matchesRef(name)) {
3053-
consumer.foundDecl(decl, DeclVisibilityKind::DynamicLookup);
3054-
matchedAny = true;
3055-
}
3044+
forEachDistinctName(clangDecl,
3045+
[&](ImportedName importedName,
3046+
ImportNameVersion nameVersion) {
3047+
// Import the declaration.
3048+
auto decl =
3049+
cast_or_null<ValueDecl>(importDeclReal(clangDecl, nameVersion));
3050+
if (!decl)
3051+
return;
30563052

3057-
// Check for an alternate declaration; if it's name matches,
3058-
// report it.
3059-
for (auto alternate : getAlternateDecls(decl)) {
3060-
if (alternate->getFullName().matchesRef(name)) {
3061-
consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup);
3062-
matchedAny = true;
3053+
// If the name we found matches, report the declaration.
3054+
// FIXME: If we didn't need to check alternate decls here, we could avoid
3055+
// importing the member at all by checking importedName ahead of time.
3056+
if (decl->getFullName().matchesRef(name)) {
3057+
consumer.foundDecl(decl, DeclVisibilityKind::DynamicLookup);
30633058
}
3064-
}
30653059

3066-
// If we didn't find anything, try under the Swift 2 name.
3067-
if (!matchedAny) {
3068-
if (auto swift2Decl = cast_or_null<ValueDecl>(
3069-
importDeclReal(clangDecl, Version::Swift2))) {
3070-
if (swift2Decl->getFullName().matchesRef(name)) {
3071-
consumer.foundDecl(swift2Decl, DeclVisibilityKind::DynamicLookup);
3060+
// Check for an alternate declaration; if its name matches,
3061+
// report it.
3062+
for (auto alternate : getAlternateDecls(decl)) {
3063+
if (alternate->getFullName().matchesRef(name)) {
3064+
consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup);
30723065
}
30733066
}
3074-
}
3067+
});
30753068
}
30763069
}
30773070

lib/ClangImporter/ImportDecl.cpp

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -345,27 +345,15 @@ static bool isNSDictionaryMethod(const clang::ObjCMethodDecl *MD,
345345
return true;
346346
}
347347

348-
/// Attempts to import the name of \p decl with each possible ImportNameVersion.
349-
/// \p action will be called with each unique name.
350-
///
351-
/// In this case, "unique" means either the full name is distinct or the
352-
/// effective context is distinct. This method does not attempt to handle
353-
/// "unresolved" contexts in any special way---if one name references a
354-
/// particular Clang declaration and the other has an unresolved context that
355-
/// will eventually reference that declaration, the contexts will still be
356-
/// considered distinct.
357-
///
358-
/// The names are generated in the same order as
359-
/// forEachImportNameVersionFromCurrent. The current name is always first.
360-
static void forEachDistinctName(
361-
ClangImporter::Implementation &impl, const clang::NamedDecl *decl,
348+
void ClangImporter::Implementation::forEachDistinctName(
349+
const clang::NamedDecl *decl,
362350
llvm::function_ref<void(ImportedName, ImportNameVersion)> action) {
363351
using ImportNameKey = std::pair<DeclName, EffectiveClangContext>;
364352
SmallVector<ImportNameKey, 8> seenNames;
365-
forEachImportNameVersionFromCurrent(impl.CurrentVersion,
353+
forEachImportNameVersionFromCurrent(CurrentVersion,
366354
[&](ImportNameVersion nameVersion) {
367355
// Check to see if the name is different.
368-
ImportedName newName = impl.importFullName(decl, nameVersion);
356+
ImportedName newName = importFullName(decl, nameVersion);
369357
ImportNameKey key(newName, newName.getEffectiveContext());
370358
bool seen = llvm::any_of(seenNames,
371359
[&key](const ImportNameKey &existing) -> bool {
@@ -2669,9 +2657,9 @@ namespace {
26692657
switch (enumKind) {
26702658
case EnumKind::Constants:
26712659
case EnumKind::Unknown:
2672-
forEachDistinctName(Impl, constant,
2673-
[&](ImportedName newName,
2674-
ImportNameVersion nameVersion) {
2660+
Impl.forEachDistinctName(constant,
2661+
[&](ImportedName newName,
2662+
ImportNameVersion nameVersion) {
26752663
Decl *imported = Impl.importDecl(constant, nameVersion);
26762664
if (!imported)
26772665
return;
@@ -2682,9 +2670,9 @@ namespace {
26822670
});
26832671
break;
26842672
case EnumKind::Options:
2685-
forEachDistinctName(Impl, constant,
2686-
[&](ImportedName newName,
2687-
ImportNameVersion nameVersion) {
2673+
Impl.forEachDistinctName(constant,
2674+
[&](ImportedName newName,
2675+
ImportNameVersion nameVersion) {
26882676
if (!contextIsEnum(newName))
26892677
return;
26902678
SwiftDeclConverter converter(Impl, nameVersion);
@@ -2741,9 +2729,9 @@ namespace {
27412729
}
27422730
}
27432731

2744-
forEachDistinctName(Impl, constant,
2745-
[&](ImportedName newName,
2746-
ImportNameVersion nameVersion) {
2732+
Impl.forEachDistinctName(constant,
2733+
[&](ImportedName newName,
2734+
ImportNameVersion nameVersion) {
27472735
if (nameVersion == getActiveSwiftVersion())
27482736
return;
27492737
if (!contextIsEnum(newName))
@@ -7737,8 +7725,8 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
77377725
// Only continue members in the same submodule as this extension.
77387726
if (decl->getImportedOwningModule() != submodule) continue;
77397727

7740-
forEachDistinctName(*this, decl, [&](ImportedName newName,
7741-
ImportNameVersion nameVersion) {
7728+
forEachDistinctName(decl, [&](ImportedName newName,
7729+
ImportNameVersion nameVersion) {
77427730
// Quickly check the context and bail out if it obviously doesn't
77437731
// belong here.
77447732
if (auto *importDC = newName.getEffectiveContext().getAsDeclContext())
@@ -7806,7 +7794,7 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
78067794
if (!nd || nd != nd->getCanonicalDecl())
78077795
continue;
78087796

7809-
forEachDistinctName(*this, nd,
7797+
forEachDistinctName(nd,
78107798
[&](ImportedName name, ImportNameVersion nameVersion) {
78117799
auto member = importDecl(nd, nameVersion);
78127800
if (!member)

lib/ClangImporter/ImporterImpl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,23 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
11691169
/// Determine the effective Clang context for the given Swift nominal type.
11701170
EffectiveClangContext getEffectiveClangContext(NominalTypeDecl *nominal);
11711171

1172+
/// Attempts to import the name of \p decl with each possible
1173+
/// ImportNameVersion. \p action will be called with each unique name.
1174+
///
1175+
/// In this case, "unique" means either the full name is distinct or the
1176+
/// effective context is distinct. This method does not attempt to handle
1177+
/// "unresolved" contexts in any special way---if one name references a
1178+
/// particular Clang declaration and the other has an unresolved context that
1179+
/// will eventually reference that declaration, the contexts will still be
1180+
/// considered distinct.
1181+
///
1182+
/// The names are generated in the same order as
1183+
/// forEachImportNameVersionFromCurrent. The current name is always first.
1184+
void forEachDistinctName(
1185+
const clang::NamedDecl *decl,
1186+
llvm::function_ref<void(importer::ImportedName,
1187+
importer::ImportNameVersion)> action);
1188+
11721189
/// Dump the Swift-specific name lookup tables we generate.
11731190
void dumpSwiftLookupTables();
11741191

test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/APINotesFrameworkTest.apinotes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ SwiftVersions:
103103
- Name: "importantClassProperty"
104104
PropertyKind: Class
105105
SwiftName: "swift3ClassProperty"
106+
- Name: "importantInstanceProperty"
107+
PropertyKind: Instance
108+
SwiftName: "swift3InstanceProperty"
106109
Protocols:
107110
- Name: ProtoWithVersionedUnavailableMember
108111
Methods:

test/APINotes/Inputs/custom-frameworks/APINotesFrameworkTest.framework/Headers/Classes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
- (void)doImportantThings __attribute__((swift_name("finalDoImportantThings()")));
1616
@property (class, nullable) id importantClassProperty __attribute__((swift_name("finalClassProperty")));
17+
@property (nullable) id importantInstanceProperty __attribute__((swift_name("finalInstanceProperty")));
1718
@end
1819

1920
#pragma clang assume_nonnull end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
3+
// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 4 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-4 %s
4+
// RUN: not %target-swift-frontend -typecheck -F %S/Inputs/custom-frameworks -swift-version 3 %s 2>&1 | %FileCheck -check-prefix=CHECK-DIAGS -check-prefix=CHECK-DIAGS-3 %s
5+
6+
// REQUIRES: objc_interop
7+
8+
import APINotesFrameworkTest
9+
10+
func testRenamedClassMembers(obj: AnyObject) {
11+
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'doImportantThings()' has been renamed to 'swift3DoImportantThings()'
12+
obj.doImportantThings()
13+
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'doImportantThings()' has been renamed to 'finalDoImportantThings()'
14+
15+
// CHECK-DIAGS-3-NOT: :[[@LINE+1]]:{{[0-9]+}}:
16+
obj.swift3DoImportantThings()
17+
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'swift3DoImportantThings()' has been renamed to 'finalDoImportantThings()'
18+
19+
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'finalDoImportantThings()' has been renamed to 'swift3DoImportantThings()'
20+
obj.finalDoImportantThings()
21+
// CHECK-DIAGS-4-NOT: :[[@LINE-1]]:{{[0-9]+}}:
22+
23+
24+
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'importantInstanceProperty' has been renamed to 'swift3InstanceProperty'
25+
_ = obj.importantInstanceProperty
26+
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'importantInstanceProperty' has been renamed to 'finalInstanceProperty'
27+
28+
// CHECK-DIAGS-3-NOT: :[[@LINE+1]]:{{[0-9]+}}:
29+
_ = obj.swift3InstanceProperty
30+
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'swift3InstanceProperty' has been renamed to 'finalInstanceProperty'
31+
32+
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'finalInstanceProperty' has been renamed to 'swift3InstanceProperty'
33+
_ = obj.finalInstanceProperty
34+
// CHECK-DIAGS-4-NOT: :[[@LINE-1]]:{{[0-9]+}}:
35+
}

0 commit comments

Comments
 (0)