Skip to content

[4.0] [ClangImporter] Classify enums using flag_enum and enum_extensibility #8998

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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion lib/ClangImporter/ImportEnumInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,32 @@ 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;
}

// If API notes have /removed/ a FlagEnum or EnumExtensibility attribute,
// then we don't need to check the macros.
for (auto *attr : decl->specific_attrs<clang::SwiftVersionedAttr>()) {
if (!attr->getVersion().empty())
continue;
if (isa<clang::FlagEnumAttr>(attr->getAttrToAdd()) ||
isa<clang::EnumExtensibilityAttr>(attr->getAttrToAdd())) {
kind = EnumKind::Unknown;
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);
Expand Down
14 changes: 12 additions & 2 deletions lib/PrintAsObjC/PrintAsObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2451,15 +2451,25 @@ class ModuleWriter {
"# 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"
Expand Down
2 changes: 1 addition & 1 deletion test/ClangImporter/Inputs/custom-modules/SwiftName.h
Original file line number Diff line number Diff line change
@@ -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:));

Expand Down
2 changes: 1 addition & 1 deletion test/ClangImporter/Inputs/enum-objc.h
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
13 changes: 13 additions & 0 deletions test/ClangImporter/enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import Foundation
import user_objc
import enums_using_attributes

// NS_ENUM
var mince = NSRuncingMode.mince
Expand Down Expand Up @@ -148,6 +149,9 @@ var qualifiedName = NSRuncingMode.mince
var topLevelCaseName = RuncingMince // expected-error{{}}
#endif

let _: EnumViaAttribute = .first
let _: CFEnumWithAttr = .first

// NS_OPTIONS
var withMince: NSRuncingOptions = .enableMince
var withQuince: NSRuncingOptions = .enableQuince
Expand Down Expand Up @@ -193,6 +197,8 @@ let audioComponentFlags2: FakeAudioComponentFlags = [.loadOutOfProcess]
let objcFlags: objc_flags = [.taggedPointer, .swiftRefcount]

let optionsWithSwiftName: NSOptionsAlsoGetSwiftName = .Case
let optionsViaAttribute: OptionsViaAttribute = [.first, .second]
let optionsViaAttribute2: CFOptionsWithAttr = [.first]

// <rdar://problem/25168818> Don't import None members in NS_OPTIONS types
#if !IRGEN
Expand All @@ -208,3 +214,10 @@ _ = EmptySet3.None
// Just use this type, making sure that its case alias doesn't cause problems.
// rdar://problem/30401506
_ = EnumWithAwkwardDeprecations.normalCase1

#if !IRGEN
let _: UnknownEnumThanksToAPINotes = .first // expected-error {{has no member 'first'}}
let _: UnknownOptionsThanksToAPINotes = .first // expected-error {{has no member 'first'}}
#endif
let _ = UnknownEnumThanksToAPINotesFirst
let _ = UnknownOptionsThanksToAPINotesFirst
13 changes: 4 additions & 9 deletions test/IDE/Inputs/print_clang_header_swift_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,23 @@

#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,
NormalTwo,
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,
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/Inputs/swift_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Name: enums_using_attributes
Tags:
- Name: UnknownEnumThanksToAPINotes
EnumKind: none
- Name: UnknownOptionsThanksToAPINotes
EnumKind: none
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#define CF_ENUM(_type, _name) enum _name : _type _name; \
enum __attribute__((enum_extensibility(open))) _name : _type
#define CF_OPTIONS(_type, _name) enum _name : _type _name; \
enum __attribute__((enum_extensibility(open), flag_enum)) _name : _type

typedef CF_ENUM(int, CFEnumWithAttr) {
CFEnumWithAttrFirst = 1,
};
typedef CF_ENUM(int, UnknownEnumThanksToAPINotes) {
UnknownEnumThanksToAPINotesFirst = 1,
};

typedef CF_OPTIONS(int, CFOptionsWithAttr) {
CFOptionsWithAttrFirst = 1,
};
typedef CF_OPTIONS(int, UnknownOptionsThanksToAPINotes) {
UnknownOptionsThanksToAPINotesFirst = 1,
};
4 changes: 4 additions & 0 deletions test/Inputs/clang-importer-sdk/usr/include/module.map
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ module objc_structs {
export *
}

module enums_using_attributes {
header "enums_using_attributes.h"
}

module errors {
header "errors.h"
export *
Expand Down
11 changes: 11 additions & 0 deletions test/Inputs/clang-importer-sdk/usr/include/user_objc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
};