Skip to content

Commit ed756df

Browse files
committed
[PrintAsObjC] Fix handling of swift_name and swift_newtype (#2695)
Merge pull request #2695 from jrose-apple/newtype-printasobjc
2 parents cc90879 + 8547b54 commit ed756df

File tree

5 files changed

+147
-17
lines changed

5 files changed

+147
-17
lines changed

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
2626
#include "swift/IDE/CommentConversion.h"
2727
#include "clang/AST/ASTContext.h"
28+
#include "clang/AST/Attr.h"
2829
#include "clang/AST/Decl.h"
2930
#include "clang/AST/DeclObjC.h"
3031
#include "clang/Basic/Module.h"
@@ -73,18 +74,25 @@ namespace {
7374
};
7475
}
7576

76-
static Identifier getNameForObjC(const ValueDecl *VD,
77-
CustomNamesOnly_t customNamesOnly = Normal) {
78-
assert(isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD)
79-
|| isa<EnumDecl>(VD) || isa<EnumElementDecl>(VD));
77+
static StringRef getNameForObjC(const ValueDecl *VD,
78+
CustomNamesOnly_t customNamesOnly = Normal) {
79+
assert(isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD) || isa<StructDecl>(VD) ||
80+
isa<EnumDecl>(VD) || isa<EnumElementDecl>(VD));
8081
if (auto objc = VD->getAttrs().getAttribute<ObjCAttr>()) {
8182
if (auto name = objc->getName()) {
8283
assert(name->getNumSelectorPieces() == 1);
83-
return name->getSelectorPieces().front();
84+
return name->getSelectorPieces().front().str();
8485
}
8586
}
8687

87-
return customNamesOnly ? Identifier() : VD->getName();
88+
if (customNamesOnly)
89+
return StringRef();
90+
91+
if (auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(VD->getClangDecl()))
92+
if (const clang::IdentifierInfo *II = clangDecl->getIdentifier())
93+
return II->getName();
94+
95+
return VD->getName().str();
8896
}
8997

9098

@@ -187,7 +195,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
187195
void visitClassDecl(ClassDecl *CD) {
188196
printDocumentationComment(CD);
189197

190-
Identifier customName = getNameForObjC(CD, CustomNamesOnly);
198+
StringRef customName = getNameForObjC(CD, CustomNamesOnly);
191199
if (customName.empty()) {
192200
llvm::SmallString<32> scratch;
193201
os << "SWIFT_CLASS(\"" << CD->getObjCRuntimeName(scratch) << "\")\n"
@@ -219,7 +227,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
219227
void visitProtocolDecl(ProtocolDecl *PD) {
220228
printDocumentationComment(PD);
221229

222-
Identifier customName = getNameForObjC(PD, CustomNamesOnly);
230+
StringRef customName = getNameForObjC(PD, CustomNamesOnly);
223231
if (customName.empty()) {
224232
llvm::SmallString<32> scratch;
225233
os << "SWIFT_PROTOCOL(\"" << PD->getObjCRuntimeName(scratch) << "\")\n"
@@ -240,7 +248,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
240248
void visitEnumDecl(EnumDecl *ED) {
241249
printDocumentationComment(ED);
242250
os << "typedef ";
243-
Identifier customName = getNameForObjC(ED, CustomNamesOnly);
251+
StringRef customName = getNameForObjC(ED, CustomNamesOnly);
244252
if (customName.empty()) {
245253
os << "SWIFT_ENUM(";
246254
} else {
@@ -260,7 +268,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
260268
// Print the cases as the concatenation of the enum name with the case
261269
// name.
262270
os << " ";
263-
Identifier customEltName = getNameForObjC(Elt, CustomNamesOnly);
271+
StringRef customEltName = getNameForObjC(Elt, CustomNamesOnly);
264272
if (customEltName.empty()) {
265273
if (customName.empty()) {
266274
os << ED->getName();
@@ -779,6 +787,10 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
779787
bool printIfObjCBridgeable(const NominalTypeDecl *nominal,
780788
ArrayRef<Type> typeArgs,
781789
Optional<OptionalTypeKind> optionalKind) {
790+
// Print imported bridgeable decls as their unbridged type.
791+
if (nominal->hasClangNode())
792+
return false;
793+
782794
auto &ctx = nominal->getASTContext();
783795

784796
// Dig out the ObjectiveCBridgeable protocol.
@@ -949,7 +961,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
949961
ASTContext &ctx = M.getASTContext();
950962
auto &clangASTContext = ctx.getClangModuleLoader()->getClangASTContext();
951963
clang::QualType clangTy = clangASTContext.getTypeDeclType(clangTypeDecl);
952-
return clangTy->isPointerType();
964+
return clangTy->isPointerType() || clangTy->isBlockPointerType() ||
965+
clangTy->isObjCObjectPointerType();
953966
}
954967

955968
void visitNameAliasType(NameAliasType *aliasTy,
@@ -964,10 +977,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
964977
auto *clangTypeDecl = cast<clang::TypeDecl>(alias->getClangDecl());
965978
os << clangTypeDecl->getName();
966979

967-
if (aliasTy->hasReferenceSemantics() ||
968-
isClangPointerType(clangTypeDecl)) {
980+
if (isClangPointerType(clangTypeDecl))
969981
printNullability(optionalKind);
970-
}
971982
return;
972983
}
973984

@@ -1014,7 +1025,12 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
10141025
return;
10151026

10161027
maybePrintTagKeyword(SD);
1017-
os << SD->getName();
1028+
os << getNameForObjC(SD);
1029+
1030+
// Handle swift_newtype applied to a pointer type.
1031+
if (auto *clangDecl = cast_or_null<clang::TypeDecl>(SD->getClangDecl()))
1032+
if (isClangPointerType(clangDecl))
1033+
printNullability(optionalKind);
10181034
}
10191035

10201036
/// Print a collection element type using Objective-C generics syntax.
@@ -1023,12 +1039,22 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
10231039
void printCollectionElement(Type ty) {
10241040
ASTContext &ctx = M.getASTContext();
10251041

1042+
auto isSwiftNewtype = [&ctx](const StructDecl *SD) -> bool {
1043+
if (!SD)
1044+
return false;
1045+
auto *clangDecl = SD->getClangDecl();
1046+
if (!clangDecl)
1047+
return false;
1048+
return clangDecl->hasAttr<clang::SwiftNewtypeAttr>();
1049+
};
1050+
10261051
// Use the type as bridged to Objective-C unless the element type is itself
1027-
// a collection.
1052+
// an imported type or a collection.
10281053
const StructDecl *SD = ty->getStructOrBoundGenericStruct();
10291054
if (SD != ctx.getArrayDecl() &&
10301055
SD != ctx.getDictionaryDecl() &&
1031-
SD != ctx.getSetDecl()) {
1056+
SD != ctx.getSetDecl() &&
1057+
!isSwiftNewtype(SD)) {
10321058
ty = *ctx.getBridgedToObjC(&M, ty, /*resolver*/nullptr);
10331059
}
10341060

test/PrintAsObjC/Inputs/newtype.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// This file is meant to be used with the mock SDK, not the real one.
2+
#import <Foundation.h>
3+
4+
typedef NSString *StructLikeStringWrapper __attribute__((swift_newtype(struct)));
5+
typedef NSString *EnumLikeStringWrapper __attribute__((swift_newtype(enum)));

test/PrintAsObjC/Inputs/swift_name.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
typedef NSString *ABCStringAlias SWIFT_NAME(ZZStringAlias);
7+
struct ABCPoint {
8+
int x;
9+
int y;
10+
} SWIFT_NAME(ZZPoint);
11+
enum ABCAlignment {
12+
ABCAlignmentLeft,
13+
ABCAlignmentRight
14+
} SWIFT_NAME(ZZAlignment);
15+
16+
SWIFT_NAME(ZZClass)
17+
@interface ABCClass : NSObject
18+
@end
19+
20+
SWIFT_NAME(ZZProto)
21+
@protocol ABCProto
22+
@end

test/PrintAsObjC/newtype.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Please keep this file in alphabetical order!
2+
3+
// REQUIRES: objc_interop
4+
5+
// RUN: rm -rf %t && mkdir %t
6+
7+
// FIXME: BEGIN -enable-source-import hackaround
8+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift
9+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift
10+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift
11+
// FIXME: END -enable-source-import hackaround
12+
13+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -import-objc-header %S/Inputs/newtype.h -enable-swift-newtype -emit-module -o %t %s
14+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -import-objc-header %S/Inputs/newtype.h -enable-swift-newtype -parse-as-library %t/newtype.swiftmodule -parse -emit-objc-header-path %t/newtype.h
15+
16+
// RUN: FileCheck %s < %t/newtype.h
17+
18+
// RUN: %check-in-clang %t/newtype.h
19+
// RUN: %check-in-clang -fno-modules -Qunused-arguments %t/newtype.h
20+
21+
import Foundation
22+
23+
// CHECK-LABEL: @interface TestEnumLike : NSObject
24+
class TestEnumLike : NSObject {
25+
// CHECK: - (void)takesNewtype:(EnumLikeStringWrapper _Nonnull)a;
26+
func takesNewtype(_ a: EnumLikeStringWrapper) {}
27+
// CHECK: - (void)takesNewtypeArray:(NSArray<EnumLikeStringWrapper> * _Nonnull)a;
28+
func takesNewtypeArray(_ a: [EnumLikeStringWrapper]) {}
29+
// CHECK: - (void)takesNewtypeDictionary:(NSDictionary<EnumLikeStringWrapper, EnumLikeStringWrapper> * _Nonnull)a;
30+
func takesNewtypeDictionary(_ a: [EnumLikeStringWrapper: EnumLikeStringWrapper]) {}
31+
}
32+
// CHECK: @end
33+
34+
// CHECK-LABEL: @interface TestStructLike : NSObject
35+
class TestStructLike : NSObject {
36+
// CHECK: - (void)takesNewtype:(StructLikeStringWrapper _Nonnull)a;
37+
func takesNewtype(_ a: StructLikeStringWrapper) {}
38+
// CHECK: - (void)takesNewtypeArray:(NSArray<StructLikeStringWrapper> * _Nonnull)a;
39+
func takesNewtypeArray(_ a: [StructLikeStringWrapper]) {}
40+
// CHECK: - (void)takesNewtypeDictionary:(NSDictionary<StructLikeStringWrapper, StructLikeStringWrapper> * _Nonnull)a;
41+
func takesNewtypeDictionary(_ a: [StructLikeStringWrapper: StructLikeStringWrapper]) {}
42+
}
43+
// CHECK: @end
44+

test/PrintAsObjC/swift_name.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Please keep this file in alphabetical order!
2+
3+
// REQUIRES: objc_interop
4+
5+
// RUN: rm -rf %t && mkdir %t
6+
7+
// FIXME: BEGIN -enable-source-import hackaround
8+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift
9+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift
10+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift
11+
// FIXME: END -enable-source-import hackaround
12+
13+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -import-objc-header %S/Inputs/swift_name.h -emit-module -o %t %s
14+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -import-objc-header %S/Inputs/swift_name.h -parse-as-library %t/swift_name.swiftmodule -parse -emit-objc-header-path %t/swift_name.h
15+
16+
// RUN: FileCheck %s < %t/swift_name.h
17+
// RUN: %check-in-clang %t/swift_name.h
18+
19+
import Foundation
20+
21+
// CHECK-LABEL: @interface Test : NSObject
22+
// CHECK-NEXT: - (NSArray<ABCStringAlias> * _Nonnull)makeArray:(ABCStringAlias _Nonnull)_;
23+
// CHECK-NEXT: - (void)usePoint:(struct ABCPoint)_;
24+
// CHECK-NEXT: - (void)useAlignment:(enum ABCAlignment)_;
25+
// CHECK-NEXT: - (NSArray<id <ABCProto>> * _Nonnull)useObjects:(ABCClass * _Nonnull)_;
26+
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
27+
// CHECK-NEXT: @end
28+
class Test : NSObject {
29+
func makeArray(_: ZZStringAlias) -> [ZZStringAlias] { return [] }
30+
func usePoint(_: ZZPoint) {}
31+
func useAlignment(_: ZZAlignment) {}
32+
func useObjects(_: ZZClass) -> [ZZProto] { return [] }
33+
}

0 commit comments

Comments
 (0)