Skip to content

[ClangImporter] Fix edge cases where custom name matches native name #27682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 23, 2019

Conversation

ChristopherRogers
Copy link
Contributor

@ChristopherRogers ChristopherRogers commented Oct 15, 2019

The code does naive lookup of Swift types using the type name, but sometimes the Swift type we're looking for only has that name in its @objc attribute. This change makes the compiler exclude certain Swift declarations from matching even if the Swift name is the same (namely, not being available in Obj-C or having a mismatched @objc name) and continue to find the correct declaration without using lookup by name.

I'm not quite sure how some cases worked before this, so some modifications may be necessary.

The main change is in the first commit. The other commits are some other changes I had sitting around. I don't have any tests for the Obj-C name commit (for the FIXME) and am not quite sure if it helps (tests still pass if I revert those changes), so I can drop that commit.

On a personal note, this also removes the need for a workaround I’ve had in my codebase at work to get Swift to associate a forward declaration to its Swift declaration (which involves creating a Clang module of the same name containing the generated Obj-C interface of the problematic class). 🎉

Resolves SR-4827.

Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking this up, and nice job on the test cases. A few thoughts…


// If Clang decl has a custom Swift name, then `name` is that name.
if (hasCustomName)
return None;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain more what this special case is about?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in order to bypass comparing the custom Objective-C name with the known custom Swift name.

if (auto objcName = objcAttr->getName())
return objcName->getSimpleName() == name;

return None;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…and this one? If there's no explicit ObjC attribute, can't we assume we know enough about the name to make a definitive statement?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning a tristate, how about passing in another argument saying whether the class's basename is already known to match? Or even just checking that up front?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve gotten rid of the tristate so the code should make a lot more sense now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Types need to be skipped over where the name matches but the type isn’t exposed to Objective-C. That was happening from the caller side before.

@@ -4586,7 +4634,8 @@ namespace {
if (!importer::hasNativeSwiftDecl(decl))
return false;
auto wrapperUnit = cast<ClangModuleUnit>(dc->getModuleScopeContext());
swiftDecl = resolveSwiftDecl<T>(decl, name, wrapperUnit);
swiftDecl = resolveSwiftDecl<T>(decl, name, /*hasCustomName=*/true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this suggests that "hasKnownSwiftName" would be a better name for the parameter?

The code does naive lookup of Swift types using the type name, but sometimes the Swift type we're looking for only has that name in its @objc attribute. This change makes the compiler exclude certain Swift declarations from matching even if the Swift name is the same (namely, not being available in Obj-C or having a mismatched `@objc` name) and continue to find the correct declaration without using lookup by name.

Fixes SR-4827
Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I like this version a lot better. Thank you!

@jrose-apple
Copy link
Contributor

@swift-ci Please test

@jrose-apple
Copy link
Contributor

@swift-ci Please test source compatibility

@jrose-apple jrose-apple self-assigned this Oct 23, 2019
@jrose-apple jrose-apple merged commit 49fd5ac into swiftlang:master Oct 23, 2019
@jrose-apple
Copy link
Contributor

Reverting this for now; we found a case where people were relying on the old behavior (NS_SWIFT_NAME with nested names). I'll follow up with a test case shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants