From 18e75099087b08ff01fdf630c7924c340e937a79 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 3 Aug 2016 13:03:50 -0700 Subject: [PATCH] [PrintAsObjC] Hack: Assume all option sets have typedefs. (#3851) ...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 02d25178669dc2dee3dd17ad024cc91d531822d3) --- lib/ClangImporter/ImportDecl.cpp | 4 ++++ lib/PrintAsObjC/PrintAsObjC.cpp | 6 +++++- test/PrintAsObjC/Inputs/enums.h | 23 +++++++++++++++++++++++ test/PrintAsObjC/enums.swift | 9 +++++++-- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 test/PrintAsObjC/Inputs/enums.h diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 1398d706c8b85..de55096fe546a 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2499,6 +2499,10 @@ namespace { if (!result) return nullptr; + // HACK: Make sure PrintAsObjC always omits the 'enum' tag for + // option set enums. + Impl.DeclsWithSuperfluousTypedefs.insert(decl); + enumeratorContext = result; break; } diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp index 3665d6cc5bf47..7c11609f87abe 100644 --- a/lib/PrintAsObjC/PrintAsObjC.cpp +++ b/lib/PrintAsObjC/PrintAsObjC.cpp @@ -97,9 +97,13 @@ static StringRef getNameForObjC(const ValueDecl *VD, if (customNamesOnly) return StringRef(); - if (auto clangDecl = dyn_cast_or_null(VD->getClangDecl())) + if (auto clangDecl = dyn_cast_or_null(VD->getClangDecl())) { if (const clang::IdentifierInfo *II = clangDecl->getIdentifier()) return II->getName(); + if (auto *anonDecl = dyn_cast(clangDecl)) + if (auto *anonTypedef = anonDecl->getTypedefNameForAnonDecl()) + return anonTypedef->getIdentifier()->getName(); + } return VD->getName().str(); } diff --git a/test/PrintAsObjC/Inputs/enums.h b/test/PrintAsObjC/Inputs/enums.h new file mode 100644 index 0000000000000..492cb8addb3e1 --- /dev/null +++ b/test/PrintAsObjC/Inputs/enums.h @@ -0,0 +1,23 @@ +// This file is meant to be used with the mock SDK, not the real one. +#import + +#define SWIFT_NAME(X) __attribute__((swift_name(#X))) + +@interface Wrapper : NSObject +@end + +enum TopLevelRaw { TopLevelRawA }; +enum MemberRaw { MemberRawA } SWIFT_NAME(Wrapper.Raw); + +typedef enum { TopLevelAnonA } TopLevelAnon; +typedef enum { MemberAnonA } MemberAnon SWIFT_NAME(Wrapper.Anon); +typedef enum SWIFT_NAME(Wrapper.Anon2) { MemberAnon2A } MemberAnon2; + +typedef enum TopLevelTypedef { TopLevelTypedefA } TopLevelTypedef; +typedef enum SWIFT_NAME(Wrapper.Typedef) MemberTypedef { MemberTypedefA } MemberTypedef; + +typedef NS_ENUM(long, TopLevelEnum) { TopLevelEnumA }; +typedef NS_ENUM(long, MemberEnum) { MemberEnumA } SWIFT_NAME(Wrapper.Enum); + +typedef NS_OPTIONS(long, TopLevelOptions) { TopLevelOptionsA = 1 }; +typedef NS_OPTIONS(long, MemberOptions) { MemberOptionsA = 1} SWIFT_NAME(Wrapper.Options); diff --git a/test/PrintAsObjC/enums.swift b/test/PrintAsObjC/enums.swift index b574dd16a9f78..cd532c6eef730 100644 --- a/test/PrintAsObjC/enums.swift +++ b/test/PrintAsObjC/enums.swift @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: mkdir %t -// 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 -// 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 +// 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 +// 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 // RUN: FileCheck %s < %t/enums.h // RUN: FileCheck -check-prefix=NEGATIVE %s < %t/enums.h // RUN: %check-in-clang %t/enums.h @@ -21,6 +21,8 @@ import Foundation // CHECK-NEXT: - (enum NegativeValues)takeAndReturnEnum:(enum FooComments)foo; // CHECK-NEXT: - (void)acceptPlainEnum:(enum NSMalformedEnumMissingTypedef)_; // CHECK-NEXT: - (enum ObjcEnumNamed)takeAndReturnRenamedEnum:(enum ObjcEnumNamed)foo; +// CHECK-NEXT: - (void)acceptTopLevelImportedWithA:(enum TopLevelRaw)a b:(TopLevelEnum)b c:(TopLevelOptions)c d:(TopLevelTypedef)d e:(TopLevelAnon)e; +// CHECK-NEXT: - (void)acceptMemberImportedWithA:(enum MemberRaw)a b:(enum MemberEnum)b c:(MemberOptions)c d:(enum MemberTypedef)d e:(MemberAnon)e ee:(MemberAnon2)ee; // CHECK: @end @objc class AnEnumMethod { @objc func takeAndReturnEnum(_ foo: FooComments) -> NegativeValues { @@ -30,6 +32,9 @@ import Foundation @objc func takeAndReturnRenamedEnum(_ foo: EnumNamed) -> EnumNamed { return .A } + + @objc func acceptTopLevelImported(a: TopLevelRaw, b: TopLevelEnum, c: TopLevelOptions, d: TopLevelTypedef, e: TopLevelAnon) {} + @objc func acceptMemberImported(a: Wrapper.Raw, b: Wrapper.Enum, c: Wrapper.Options, d: Wrapper.Typedef, e: Wrapper.Anon, ee: Wrapper.Anon2) {} } // CHECK-LABEL: typedef SWIFT_ENUM_NAMED(NSInteger, ObjcEnumNamed, "EnumNamed") {