[ClangImporter] Find Swift 3 / 4 names via dynamic lookup too.

Finishes rdar://problem/29170671
This commit is contained in:
Jordan Rose
2017-05-13 14:51:36 -07:00
parent 94d9d6a33a
commit ec23dcaaac
6 changed files with 91 additions and 54 deletions

View File

@@ -3041,37 +3041,30 @@ void ClangImporter::Implementation::lookupObjCMembers(
// If the entry is not visible, skip it. // If the entry is not visible, skip it.
if (!isVisibleClangEntry(clangCtx, clangDecl)) continue; if (!isVisibleClangEntry(clangCtx, clangDecl)) continue;
forEachDistinctName(clangDecl,
[&](ImportedName importedName,
ImportNameVersion nameVersion) {
// Import the declaration. // Import the declaration.
auto decl = auto decl =
cast_or_null<ValueDecl>(importDeclReal(clangDecl, CurrentVersion)); cast_or_null<ValueDecl>(importDeclReal(clangDecl, nameVersion));
if (!decl) if (!decl)
continue; return;
// If the name we found matches, report the declaration. // If the name we found matches, report the declaration.
bool matchedAny = false; // FIXME: If we didn't need to check alternate decls here, we could avoid
// importing the member at all by checking importedName ahead of time.
if (decl->getFullName().matchesRef(name)) { if (decl->getFullName().matchesRef(name)) {
consumer.foundDecl(decl, DeclVisibilityKind::DynamicLookup); consumer.foundDecl(decl, DeclVisibilityKind::DynamicLookup);
matchedAny = true;
} }
// Check for an alternate declaration; if it's name matches, // Check for an alternate declaration; if its name matches,
// report it. // report it.
for (auto alternate : getAlternateDecls(decl)) { for (auto alternate : getAlternateDecls(decl)) {
if (alternate->getFullName().matchesRef(name)) { if (alternate->getFullName().matchesRef(name)) {
consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup); consumer.foundDecl(alternate, DeclVisibilityKind::DynamicLookup);
matchedAny = true;
}
}
// If we didn't find anything, try under the Swift 2 name.
if (!matchedAny) {
if (auto swift2Decl = cast_or_null<ValueDecl>(
importDeclReal(clangDecl, Version::Swift2))) {
if (swift2Decl->getFullName().matchesRef(name)) {
consumer.foundDecl(swift2Decl, DeclVisibilityKind::DynamicLookup);
}
} }
} }
});
} }
} }

View File

@@ -345,27 +345,15 @@ static bool isNSDictionaryMethod(const clang::ObjCMethodDecl *MD,
return true; return true;
} }
/// Attempts to import the name of \p decl with each possible ImportNameVersion. void ClangImporter::Implementation::forEachDistinctName(
/// \p action will be called with each unique name. const clang::NamedDecl *decl,
///
/// In this case, "unique" means either the full name is distinct or the
/// effective context is distinct. This method does not attempt to handle
/// "unresolved" contexts in any special way---if one name references a
/// particular Clang declaration and the other has an unresolved context that
/// will eventually reference that declaration, the contexts will still be
/// considered distinct.
///
/// The names are generated in the same order as
/// forEachImportNameVersionFromCurrent. The current name is always first.
static void forEachDistinctName(
ClangImporter::Implementation &impl, const clang::NamedDecl *decl,
llvm::function_ref<void(ImportedName, ImportNameVersion)> action) { llvm::function_ref<void(ImportedName, ImportNameVersion)> action) {
using ImportNameKey = std::pair<DeclName, EffectiveClangContext>; using ImportNameKey = std::pair<DeclName, EffectiveClangContext>;
SmallVector<ImportNameKey, 8> seenNames; SmallVector<ImportNameKey, 8> seenNames;
forEachImportNameVersionFromCurrent(impl.CurrentVersion, forEachImportNameVersionFromCurrent(CurrentVersion,
[&](ImportNameVersion nameVersion) { [&](ImportNameVersion nameVersion) {
// Check to see if the name is different. // Check to see if the name is different.
ImportedName newName = impl.importFullName(decl, nameVersion); ImportedName newName = importFullName(decl, nameVersion);
ImportNameKey key(newName, newName.getEffectiveContext()); ImportNameKey key(newName, newName.getEffectiveContext());
bool seen = llvm::any_of(seenNames, bool seen = llvm::any_of(seenNames,
[&key](const ImportNameKey &existing) -> bool { [&key](const ImportNameKey &existing) -> bool {
@@ -2669,7 +2657,7 @@ namespace {
switch (enumKind) { switch (enumKind) {
case EnumKind::Constants: case EnumKind::Constants:
case EnumKind::Unknown: case EnumKind::Unknown:
forEachDistinctName(Impl, constant, Impl.forEachDistinctName(constant,
[&](ImportedName newName, [&](ImportedName newName,
ImportNameVersion nameVersion) { ImportNameVersion nameVersion) {
Decl *imported = Impl.importDecl(constant, nameVersion); Decl *imported = Impl.importDecl(constant, nameVersion);
@@ -2682,7 +2670,7 @@ namespace {
}); });
break; break;
case EnumKind::Options: case EnumKind::Options:
forEachDistinctName(Impl, constant, Impl.forEachDistinctName(constant,
[&](ImportedName newName, [&](ImportedName newName,
ImportNameVersion nameVersion) { ImportNameVersion nameVersion) {
if (!contextIsEnum(newName)) if (!contextIsEnum(newName))
@@ -2741,7 +2729,7 @@ namespace {
} }
} }
forEachDistinctName(Impl, constant, Impl.forEachDistinctName(constant,
[&](ImportedName newName, [&](ImportedName newName,
ImportNameVersion nameVersion) { ImportNameVersion nameVersion) {
if (nameVersion == getActiveSwiftVersion()) if (nameVersion == getActiveSwiftVersion())
@@ -7737,7 +7725,7 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
// Only continue members in the same submodule as this extension. // Only continue members in the same submodule as this extension.
if (decl->getImportedOwningModule() != submodule) continue; if (decl->getImportedOwningModule() != submodule) continue;
forEachDistinctName(*this, decl, [&](ImportedName newName, forEachDistinctName(decl, [&](ImportedName newName,
ImportNameVersion nameVersion) { ImportNameVersion nameVersion) {
// Quickly check the context and bail out if it obviously doesn't // Quickly check the context and bail out if it obviously doesn't
// belong here. // belong here.
@@ -7806,7 +7794,7 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
if (!nd || nd != nd->getCanonicalDecl()) if (!nd || nd != nd->getCanonicalDecl())
continue; continue;
forEachDistinctName(*this, nd, forEachDistinctName(nd,
[&](ImportedName name, ImportNameVersion nameVersion) { [&](ImportedName name, ImportNameVersion nameVersion) {
auto member = importDecl(nd, nameVersion); auto member = importDecl(nd, nameVersion);
if (!member) if (!member)

View File

@@ -1169,6 +1169,23 @@ public:
/// Determine the effective Clang context for the given Swift nominal type. /// Determine the effective Clang context for the given Swift nominal type.
EffectiveClangContext getEffectiveClangContext(NominalTypeDecl *nominal); EffectiveClangContext getEffectiveClangContext(NominalTypeDecl *nominal);
/// Attempts to import the name of \p decl with each possible
/// ImportNameVersion. \p action will be called with each unique name.
///
/// In this case, "unique" means either the full name is distinct or the
/// effective context is distinct. This method does not attempt to handle
/// "unresolved" contexts in any special way---if one name references a
/// particular Clang declaration and the other has an unresolved context that
/// will eventually reference that declaration, the contexts will still be
/// considered distinct.
///
/// The names are generated in the same order as
/// forEachImportNameVersionFromCurrent. The current name is always first.
void forEachDistinctName(
const clang::NamedDecl *decl,
llvm::function_ref<void(importer::ImportedName,
importer::ImportNameVersion)> action);
/// Dump the Swift-specific name lookup tables we generate. /// Dump the Swift-specific name lookup tables we generate.
void dumpSwiftLookupTables(); void dumpSwiftLookupTables();

View File

@@ -103,6 +103,9 @@ SwiftVersions:
- Name: "importantClassProperty" - Name: "importantClassProperty"
PropertyKind: Class PropertyKind: Class
SwiftName: "swift3ClassProperty" SwiftName: "swift3ClassProperty"
- Name: "importantInstanceProperty"
PropertyKind: Instance
SwiftName: "swift3InstanceProperty"
Protocols: Protocols:
- Name: ProtoWithVersionedUnavailableMember - Name: ProtoWithVersionedUnavailableMember
Methods: Methods:

View File

@@ -14,6 +14,7 @@
- (void)doImportantThings __attribute__((swift_name("finalDoImportantThings()"))); - (void)doImportantThings __attribute__((swift_name("finalDoImportantThings()")));
@property (class, nullable) id importantClassProperty __attribute__((swift_name("finalClassProperty"))); @property (class, nullable) id importantClassProperty __attribute__((swift_name("finalClassProperty")));
@property (nullable) id importantInstanceProperty __attribute__((swift_name("finalInstanceProperty")));
@end @end
#pragma clang assume_nonnull end #pragma clang assume_nonnull end

View File

@@ -0,0 +1,35 @@
// RUN: rm -rf %t && mkdir -p %t
// 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
// 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
// REQUIRES: objc_interop
import APINotesFrameworkTest
func testRenamedClassMembers(obj: AnyObject) {
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'doImportantThings()' has been renamed to 'swift3DoImportantThings()'
obj.doImportantThings()
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'doImportantThings()' has been renamed to 'finalDoImportantThings()'
// CHECK-DIAGS-3-NOT: :[[@LINE+1]]:{{[0-9]+}}:
obj.swift3DoImportantThings()
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'swift3DoImportantThings()' has been renamed to 'finalDoImportantThings()'
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'finalDoImportantThings()' has been renamed to 'swift3DoImportantThings()'
obj.finalDoImportantThings()
// CHECK-DIAGS-4-NOT: :[[@LINE-1]]:{{[0-9]+}}:
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'importantInstanceProperty' has been renamed to 'swift3InstanceProperty'
_ = obj.importantInstanceProperty
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'importantInstanceProperty' has been renamed to 'finalInstanceProperty'
// CHECK-DIAGS-3-NOT: :[[@LINE+1]]:{{[0-9]+}}:
_ = obj.swift3InstanceProperty
// CHECK-DIAGS-4: [[@LINE-1]]:{{[0-9]+}}: error: 'swift3InstanceProperty' has been renamed to 'finalInstanceProperty'
// CHECK-DIAGS-3: [[@LINE+1]]:{{[0-9]+}}: error: 'finalInstanceProperty' has been renamed to 'swift3InstanceProperty'
_ = obj.finalInstanceProperty
// CHECK-DIAGS-4-NOT: :[[@LINE-1]]:{{[0-9]+}}:
}