Skip to content

[C++-Interop] Teach omitNeedlessWords to handle raw integer C-enums in C++ #42412

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 1 commit into from
Apr 19, 2022

Conversation

plotfi
Copy link
Contributor

@plotfi plotfi commented Apr 16, 2022

As I understand it, enums in C++ do not allow for bitwise operations
that can also be assigned or returned as the same enum type. As a result
there are macros in (Core)Foundation like NS/CF_OPTIONS that produce
enums differently depending on #if __cplusplus or not.

Because of this, code in omitNeedlessWordsInFunctionName and
subsequently inferDefaultArgument in the ClangImporter that is in charge
of replacing "needless words" from method and enum names does not
trigger in the case of C++ because it is looking for EnumDecls that dont
exists because they are actually typedefs on wrap integers or
NSIntegers.

This change attempts to do the renaming off of the typedef alone when
such code exists. However at the moment it is somewhat of a work in
progress.

Special thanks to @bulbazord (Alex Langford) for taking the time to investigate this issue.

@plotfi plotfi added the c++ interop Feature: Interoperability with C++ label Apr 16, 2022
@plotfi plotfi requested a review from zoecarver April 16, 2022 08:03
@plotfi
Copy link
Contributor Author

plotfi commented Apr 16, 2022

@swift-ci please smoke test

@plotfi plotfi requested a review from beccadax April 16, 2022 08:23
@plotfi
Copy link
Contributor Author

plotfi commented Apr 16, 2022

Added @beccadax from review for #42223 as well.

@zoecarver
Copy link
Contributor

@swift-ci please smoke test.

@plotfi
Copy link
Contributor Author

plotfi commented Apr 16, 2022

@zoecarver does the way I am going about this seem reasonable? I worry there could be typedef names that we don’t want to necessarily always rename here.

@zoecarver
Copy link
Contributor

Generally it seems reasonable, but we will probably need to make the check more specific. We probably want to see if this typedef has been replaced with an enum. Not exactly sure what the best way to do that is... maybe with a lookup, or a "global" map, or maybe using canSkipOverTypedef (I'm worried this API doesn't work for this use case though, because we don't know about the enum yet).

@@ -2431,6 +2431,16 @@ DefaultArgumentKind ClangImporter::Implementation::inferDefaultArgument(
return DefaultArgumentKind::EmptyArray;
}
}
} else if (const clang::TypedefType *typedefType =
type->getAs<clang::TypedefType>()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is maybe another reason that we should try harder to link typedef -> enum with some clang attr (this will be hard without naming the enum 😕)

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 maybe another reason that we should try harder to link typedef -> enum with some clang attr (this will be hard without naming the enum 😕)

Yeah I was thinking something similar. Maybe we need another attr or something to link things. It would be potentially problematic though because it would assume folks are putting additional attrs on their enums (unless they just use CF_OPTIONS ).

@plotfi
Copy link
Contributor Author

plotfi commented Apr 16, 2022

Generally it seems reasonable, but we will probably need to make the check more specific. We probably want to see if this typedef has been replaced with an enum. Not exactly sure what the best way to do that is... maybe with a lookup, or a "global" map, or maybe using canSkipOverTypedef (I'm worried this API doesn't work for this use case though, because we don't know about the enum yet).

Yeah that’s exactly my thought. I was thinking either by using some global map or by just checking to make sure what’s being typedefed is something like a built in or an NSInteger (the most naive way imo). Ok sounds like we are on the same page.

@zoecarver
Copy link
Contributor

Surprised that this isn't breaking anything. I'd expect something like NSInteger would break it. Let's see if source compat succeeds.

@zoecarver
Copy link
Contributor

@swift-ci Please Test Source Compatibility

@plotfi
Copy link
Contributor Author

plotfi commented Apr 18, 2022

Surprised that this isn't breaking anything. I'd expect something like NSInteger would break it. Let's see if source compat succeeds.

Yeah, I was also surprised this didnt break things for me locally.

@zoecarver
Copy link
Contributor

For the record: the source compatibility test succeeded.

@plotfi plotfi force-pushed the c-enums-withOptions-omit branch from 3981849 to dfec3ec Compare April 19, 2022 01:05
Comment on lines 2437 to 2441
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
const clang::AvailabilityAttr *availabilityAttr =
typedefType->getDecl()->getAttr<clang::AvailabilityAttr>();

if (availabilityAttr && availabilityAttr->getUnavailable()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use isUnavailableInSwift instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Should I leave enableObjCInterop to true?

@plotfi plotfi force-pushed the c-enums-withOptions-omit branch from dfec3ec to 7307b38 Compare April 19, 2022 06:44
…n C++

As I understand it, enums in C++ do not allow for bitwise operations
that can also be assigned or returned as the same enum type. As a result
there are macros in (Core)Foundation like NS/CF_OPTIONS that produce
enums differently depending on #if __cplusplus or not.

Because of this, code in omitNeedlessWordsInFunctionName and
subsequently inferDefaultArgument in the ClangImporter that is in charge
of replacing "needless words" from method and enum names does not
trigger in the case of C++ because it is looking for EnumDecls that do
not exists because they are actually typedefs on wrap integers or
NSIntegers.

This change attempts to do the renaming off of the typedef alone when
such code exists.

Special thanks to @bulbazord (Alex Langford) for taking the time to
investigate this issue.
@plotfi plotfi force-pushed the c-enums-withOptions-omit branch from 7307b38 to a0985a0 Compare April 19, 2022 07:01
@plotfi
Copy link
Contributor Author

plotfi commented Apr 19, 2022

@swift-ci please smoke test.

} else if (const clang::TypedefType *typedefType =
type->getAs<clang::TypedefType>()) {
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You can actually use if (isUnavailableInSwift(typdefType->getDecl())) here because you're in the Implementation (in my patch I had to use this because of layering).

Copy link
Contributor

Choose a reason for hiding this comment

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

I see this is a static method, so never mind.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants