[ClangImporter] Classify enums using flag_enum and enum_extensibility (#8910)

These new Clang attributes identify whether an enum is intended to
represent an option set or not, and whether the set of cases listed in
the enum declaration is exhaustive. (Swift doesn't currently have a
closed/open distinction for enums, so treat any C enum with
enum_extensibility as a proper closed Swift enum, like we do with
NS_ENUM.)

Enums with neither attribute will continue to be imported as unique
types.

rdar://problem/28476618
This commit is contained in:
Jordan Rose
2017-04-21 08:57:27 -07:00
committed by GitHub
parent f6b8b7d233
commit a03c40cb2c
8 changed files with 45 additions and 15 deletions

View File

@@ -50,9 +50,20 @@ void EnumInfo::classifyEnum(ASTContext &ctx, const clang::EnumDecl *decl,
nsErrorDomain = ctx.AllocateCopy(domainAttr->getErrorDomain()->getName());
return;
}
if (decl->hasAttr<clang::FlagEnumAttr>()) {
kind = EnumKind::Options;
return;
}
if (decl->hasAttr<clang::EnumExtensibilityAttr>()) {
// FIXME: Distinguish between open and closed enums.
kind = EnumKind::Enum;
return;
}
// Was the enum declared using *_ENUM or *_OPTIONS?
// FIXME: Use Clang attributes instead of groveling the macro expansion loc.
// FIXME: Stop using these once flag_enum and enum_extensibility
// have been adopted everywhere, or at least relegate them to Swift 3 mode
// only.
auto loc = decl->getLocStart();
if (loc.isMacroID()) {
StringRef MacroName = pp.getImmediateMacroName(loc);

View File

@@ -2451,15 +2451,25 @@ public:
"# define OBJC_DESIGNATED_INITIALIZER\n"
"# endif\n"
"#endif\n"
"#if !defined(SWIFT_ENUM_ATTR)\n"
"# if defined(__has_attribute) && "
"__has_attribute(enum_extensibility)\n"
"# define SWIFT_ENUM_ATTR "
"__attribute__((enum_extensibility(open)))\n"
"# else\n"
"# define SWIFT_ENUM_ATTR\n"
"# endif\n"
"#endif\n"
"#if !defined(SWIFT_ENUM)\n"
"# define SWIFT_ENUM(_type, _name) "
"enum _name : _type _name; "
"enum SWIFT_ENUM_EXTRA _name : _type\n"
"enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type\n"
"# if defined(__has_feature) && "
"__has_feature(generalized_swift_name)\n"
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) "
"enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); "
"enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type\n"
"enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR "
"SWIFT_ENUM_EXTRA _name : _type\n"
"# else\n"
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) "
"SWIFT_ENUM(_type, _name)\n"

View File

@@ -1,6 +1,6 @@
#define SWIFT_NAME(X) __attribute__((swift_name(#X)))
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum __attribute__((enum_extensibility(open))) _name : _type
void drawString(const char *, int x, int y) SWIFT_NAME(drawString(_:x:y:));

View File

@@ -1,7 +1,7 @@
@import Foundation;
#define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type
#define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnum, "SwiftEnum") {
ObjCEnumOne = 1,

View File

@@ -148,6 +148,8 @@ var qualifiedName = NSRuncingMode.mince
var topLevelCaseName = RuncingMince // expected-error{{}}
#endif
let _: EnumViaAttribute = .first
// NS_OPTIONS
var withMince: NSRuncingOptions = .enableMince
var withQuince: NSRuncingOptions = .enableQuince
@@ -193,6 +195,7 @@ let audioComponentFlags2: FakeAudioComponentFlags = [.loadOutOfProcess]
let objcFlags: objc_flags = [.taggedPointer, .swiftRefcount]
let optionsWithSwiftName: NSOptionsAlsoGetSwiftName = .Case
let optionsViaAttribute: OptionsViaAttribute = [.first, .second]
// <rdar://problem/25168818> Don't import None members in NS_OPTIONS types
#if !IRGEN

View File

@@ -2,7 +2,7 @@
#define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
typedef SWIFT_ENUM(NSInteger, Normal) {
NormalOne = 0,
@@ -10,20 +10,15 @@ typedef SWIFT_ENUM(NSInteger, Normal) {
NormalThree
};
// FIXME (#618): Use SWIFT_ENUM_NAMED() when support for that lands
#undef SWIFT_ENUM
#define SWIFT_ENUM(_type, _name) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_ENUM_NAME); enum SWIFT_COMPILE_NAME(SWIFT_ENUM_NAME) SWIFT_ENUM_EXTRA _name : _type
#define SWIFT_ENUM_NAMED(_type, _name, _swiftName) enum _name : _type _name SWIFT_COMPILE_NAME(_swiftName); enum SWIFT_COMPILE_NAME(_swiftName) __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
#define SWIFT_ENUM_NAME "SwiftEnum"
typedef SWIFT_ENUM(NSInteger, ObjCEnum) {
typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnum, "SwiftEnum") {
ObjCEnumOne = 0,
ObjCEnumTwo,
ObjCEnumThree
};
#undef SWIFT_ENUM_NAME
#define SWIFT_ENUM_NAME "SwiftEnumTwo"
typedef SWIFT_ENUM(NSInteger, ObjCEnumTwo) {
typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnumTwo, "SwiftEnumTwo") {
// the following shouldn't have their prefixes stripped
SwiftEnumTwoA,
SwiftEnumTwoB,

View File

@@ -7,7 +7,7 @@
#ifndef SWIFT_ENUM
# define SWIFT_ENUM(_type, _name) \
enum _name : _type _name; \
enum SWIFT_ENUM_EXTRA _name : _type
enum __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
#endif
// Renaming global variables.

View File

@@ -29,6 +29,12 @@ typedef NS_ENUM(NSInteger, EnumWithAwkwardDeprecations) {
EnumWithAwkward2BitProblems __attribute__((deprecated)) = EnumWithAwkwardNormalCase1,
};
enum __attribute__((enum_extensibility(open))) EnumViaAttribute {
EnumViaAttributeFirst = 1,
EnumViaAttributeSecond = 2
};
// From <AudioUnit/AudioComponent.h>
// The interesting feature of this enum is that the common prefix before
// taking the enum name itself into account extends past the underscore.
@@ -68,3 +74,8 @@ typedef CF_OPTIONS(UInt32, EmptySet2) {
typedef CF_OPTIONS(UInt32, EmptySet3) {
kEmptySet3None __attribute__((swift_name("None")))
};
enum __attribute__((flag_enum)) OptionsViaAttribute {
OptionsViaAttributeFirst = 1,
OptionsViaAttributeSecond = 2
};