Skip to content

Commit f395524

Browse files
authored
[PrintAsObjC] Hack: Assume all option sets have typedefs. (#3961)
...because otherwise option sets that get imported as members using NS_SWIFT_NAME are printed with an 'enum' tag, and the definition of NS_OPTIONS only declares the typedef under C++. We should come back and figure out something more principled for this later, but for now this solves an issue with generated headers imported into C++ translation units. rdar://problem/27130343 (cherry picked from commit 02d2517)
1 parent 07e731d commit f395524

File tree

4 files changed

+39
-3
lines changed

4 files changed

+39
-3
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,10 @@ namespace {
24992499
if (!result)
25002500
return nullptr;
25012501

2502+
// HACK: Make sure PrintAsObjC always omits the 'enum' tag for
2503+
// option set enums.
2504+
Impl.DeclsWithSuperfluousTypedefs.insert(decl);
2505+
25022506
enumeratorContext = result;
25032507
break;
25042508
}

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,13 @@ static StringRef getNameForObjC(const ValueDecl *VD,
9797
if (customNamesOnly)
9898
return StringRef();
9999

100-
if (auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(VD->getClangDecl()))
100+
if (auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(VD->getClangDecl())) {
101101
if (const clang::IdentifierInfo *II = clangDecl->getIdentifier())
102102
return II->getName();
103+
if (auto *anonDecl = dyn_cast<clang::TagDecl>(clangDecl))
104+
if (auto *anonTypedef = anonDecl->getTypedefNameForAnonDecl())
105+
return anonTypedef->getIdentifier()->getName();
106+
}
103107

104108
return VD->getName().str();
105109
}

test/PrintAsObjC/Inputs/enums.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// This file is meant to be used with the mock SDK, not the real one.
2+
#import <Foundation.h>
3+
4+
#define SWIFT_NAME(X) __attribute__((swift_name(#X)))
5+
6+
@interface Wrapper : NSObject
7+
@end
8+
9+
enum TopLevelRaw { TopLevelRawA };
10+
enum MemberRaw { MemberRawA } SWIFT_NAME(Wrapper.Raw);
11+
12+
typedef enum { TopLevelAnonA } TopLevelAnon;
13+
typedef enum { MemberAnonA } MemberAnon SWIFT_NAME(Wrapper.Anon);
14+
typedef enum SWIFT_NAME(Wrapper.Anon2) { MemberAnon2A } MemberAnon2;
15+
16+
typedef enum TopLevelTypedef { TopLevelTypedefA } TopLevelTypedef;
17+
typedef enum SWIFT_NAME(Wrapper.Typedef) MemberTypedef { MemberTypedefA } MemberTypedef;
18+
19+
typedef NS_ENUM(long, TopLevelEnum) { TopLevelEnumA };
20+
typedef NS_ENUM(long, MemberEnum) { MemberEnumA } SWIFT_NAME(Wrapper.Enum);
21+
22+
typedef NS_OPTIONS(long, TopLevelOptions) { TopLevelOptionsA = 1 };
23+
typedef NS_OPTIONS(long, MemberOptions) { MemberOptionsA = 1} SWIFT_NAME(Wrapper.Options);

test/PrintAsObjC/enums.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: rm -rf %t
22
// RUN: mkdir %t
3-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-source-import -emit-module -emit-module-doc -o %t %s -disable-objc-attr-requires-foundation-module
4-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %t/enums.swiftmodule -parse -emit-objc-header-path %t/enums.h -import-objc-header %S/../Inputs/empty.h -disable-objc-attr-requires-foundation-module
3+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-source-import -emit-module -emit-module-doc -o %t %s -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %t/enums.swiftmodule -parse -emit-objc-header-path %t/enums.h -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module
55
// RUN: FileCheck %s < %t/enums.h
66
// RUN: FileCheck -check-prefix=NEGATIVE %s < %t/enums.h
77
// RUN: %check-in-clang %t/enums.h
@@ -21,6 +21,8 @@ import Foundation
2121
// CHECK-NEXT: - (enum NegativeValues)takeAndReturnEnum:(enum FooComments)foo;
2222
// CHECK-NEXT: - (void)acceptPlainEnum:(enum NSMalformedEnumMissingTypedef)_;
2323
// CHECK-NEXT: - (enum ObjcEnumNamed)takeAndReturnRenamedEnum:(enum ObjcEnumNamed)foo;
24+
// CHECK-NEXT: - (void)acceptTopLevelImportedWithA:(enum TopLevelRaw)a b:(TopLevelEnum)b c:(TopLevelOptions)c d:(TopLevelTypedef)d e:(TopLevelAnon)e;
25+
// CHECK-NEXT: - (void)acceptMemberImportedWithA:(enum MemberRaw)a b:(enum MemberEnum)b c:(MemberOptions)c d:(enum MemberTypedef)d e:(MemberAnon)e ee:(MemberAnon2)ee;
2426
// CHECK: @end
2527
@objc class AnEnumMethod {
2628
@objc func takeAndReturnEnum(_ foo: FooComments) -> NegativeValues {
@@ -30,6 +32,9 @@ import Foundation
3032
@objc func takeAndReturnRenamedEnum(_ foo: EnumNamed) -> EnumNamed {
3133
return .A
3234
}
35+
36+
@objc func acceptTopLevelImported(a: TopLevelRaw, b: TopLevelEnum, c: TopLevelOptions, d: TopLevelTypedef, e: TopLevelAnon) {}
37+
@objc func acceptMemberImported(a: Wrapper.Raw, b: Wrapper.Enum, c: Wrapper.Options, d: Wrapper.Typedef, e: Wrapper.Anon, ee: Wrapper.Anon2) {}
3338
}
3439

3540
// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(NSInteger, ObjcEnumNamed, "EnumNamed") {

0 commit comments

Comments
 (0)