Skip to content

Commit 50e3b33

Browse files
committed
[ClangImporter] Implement importing of ObjC class properties.
For the most part this was just "check isInstanceProperty"; the one feature not yet implemented is the emission of ObjC metadata for class properties. rdar://problem/16830785
1 parent fa0d270 commit 50e3b33

File tree

22 files changed

+379
-19
lines changed

22 files changed

+379
-19
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5204,7 +5204,8 @@ namespace {
52045204
NL_QualifiedDefault | NL_KnownNoDependency,
52055205
Impl.getTypeResolver(), lookup);
52065206
for (auto result : lookup) {
5207-
if (isa<FuncDecl>(result) && result->isInstanceMember() &&
5207+
if (isa<FuncDecl>(result) &&
5208+
result->isInstanceMember() == decl->isInstanceProperty() &&
52085209
result->getFullName().getArgumentNames().empty())
52095210
return nullptr;
52105211

@@ -5257,7 +5258,7 @@ namespace {
52575258
}
52585259

52595260
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
5260-
/*static*/ false, /*IsLet*/ false,
5261+
decl->isClassProperty(), /*IsLet*/ false,
52615262
Impl.importSourceLoc(decl->getLocation()),
52625263
name, type, dc);
52635264
result->setInterfaceType(ArchetypeBuilder::mapTypeOutOfContext(dc, type));

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -566,17 +566,12 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
566566

567567
printDocumentationComment(VD);
568568

569-
if (VD->isStatic()) {
570-
// Objective-C doesn't have class properties. Just print the accessors.
571-
printAbstractFunctionAsMethod(VD->getGetter(), true);
572-
if (auto setter = VD->getSetter())
573-
printAbstractFunctionAsMethod(setter, true);
574-
return;
575-
}
576-
577569
// For now, never promise atomicity.
578570
os << "@property (nonatomic";
579571

572+
if (!VD->isInstanceMember())
573+
os << ", class";
574+
580575
ASTContext &ctx = M.getASTContext();
581576
bool isSettable = VD->isSettable(nullptr);
582577
if (isSettable && ctx.LangOpts.EnableAccessControl)

test/ClangModules/Inputs/SwiftPrivateAttr.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ protocol __PrivProto {
44
}
55
class Foo : NSObject, __PrivProto {
66
var __privValue: AnyObject!
7+
class var __privClassValue: AnyObject!
78
func __noArgs()
89
func __oneArg(arg: Int32)
910
func __twoArgs(arg: Int32, other arg2: Int32)

test/ClangModules/Inputs/custom-modules/ObjCIRExtras.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
- (void)methodInt:(NSInteger)value SWIFT_NAME(theMethod(number:));
3131

3232
@property (readonly) int someProp SWIFT_NAME(renamedSomeProp);
33+
@property (readonly, class) int classProp SWIFT_NAME(renamedClassProp);
3334
@end
3435

3536
@interface SwiftNameTestError : NSObject

test/ClangModules/Inputs/custom-modules/ObjCParseExtras.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,36 @@ __attribute__((objc_root_class))
88

99
@interface PropertyAndMethodCollisionBase
1010
- (void)object:(id)obj doSomething:(SEL)selector;
11+
+ (void)classRef:(id)obj doSomething:(SEL)selector;
1112
@end
1213

1314
@interface PropertyAndMethodCollision : PropertyAndMethodCollisionBase
1415
@property id object;
16+
@property (class) id classRef;
1517
@end
1618

1719
@interface PropertyAndMethodReverseCollisionBase
1820
@property id object;
21+
@property (class) id classRef;
1922
@end
2023

2124
@interface PropertyAndMethodReverseCollision : PropertyAndMethodReverseCollisionBase
2225
- (void)object:(id)obj doSomething:(SEL)selector;
26+
+ (void)classRef:(id)obj doSomething:(SEL)selector;
2327
@end
2428

2529
@protocol PropertyProto
2630
@property id protoProp;
2731
@property(readonly) id protoPropRO;
32+
@property(class) id protoClassProp;
33+
@property(class, readonly) id protoClassPropRO;
2834
@end
2935

3036
@interface PropertyAndMethodCollision () <PropertyProto>
3137
- (id)protoProp;
3238
- (id)protoPropRO;
39+
+ (id)protoClassProp;
40+
+ (id)protoClassPropRO;
3341
@end
3442

3543

test/ClangModules/Inputs/custom-modules/SwiftPrivateAttr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ NS_REFINED_FOR_SWIFT
88

99
@interface Foo : NSObject <PrivProto>
1010
@property id privValue NS_REFINED_FOR_SWIFT;
11+
@property (class) id privClassValue NS_REFINED_FOR_SWIFT;
1112

1213
- (void)noArgs NS_REFINED_FOR_SWIFT;
1314
- (void)oneArg:(int)arg NS_REFINED_FOR_SWIFT;

test/ClangModules/attr-swift_name.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ func test(i: Int) {
1212
t.theMethod(number: i)
1313

1414
_ = t.renamedSomeProp
15+
_ = t.dynamicType.renamedClassProp
1516

1617
// We only see these two warnings because Clang can catch the other invalid
1718
// cases, and marks the attribute as invalid ahead of time.
1819

1920
// CHECK: warning: too few parameters in swift_name attribute (expected 2; got 1)
2021
// CHECK: + (instancetype)g:(id)x outParam:(int *)foo SWIFT_NAME(init(g:));
21-
22+
23+
// CHECK-NOT: warning:
24+
2225
// CHECK: warning: too few parameters in swift_name attribute (expected 2; got 1)
2326
// CHECK: + (instancetype)testW:(id)x out:(id *)outObject SWIFT_NAME(ww(_:));
2427
}

test/ClangModules/attr-swift_private.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ public func testProperty(foo: Foo) {
2121
// CHECK: @"\01L_selector(setPrivValue:)"
2222
_ = foo.__privValue
2323
foo.__privValue = foo
24+
25+
// CHECK: @"\01L_selector(setPrivClassValue:)"
26+
_ = Foo.__privClassValue
27+
Foo.__privClassValue = foo
2428

2529
#if !IRGEN
2630
_ = foo.privValue // expected-error {{value of type 'Foo' has no member 'privValue'}}

test/ClangModules/objc_ir.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ func propertyAccess(b b: B) {
7070
// CHECK: load i8*, i8** @"\01L_selector(counter)"
7171
// CHECK: load i8*, i8** @"\01L_selector(setCounter:)"
7272
b.counter = b.counter + 1
73+
74+
// CHECK: call %swift.type* @_TMaCSo1B()
75+
// CHECK: bitcast %swift.type* {{%.+}} to %objc_class*
76+
// CHECK: load i8*, i8** @"\01L_selector(sharedCounter)"
77+
// CHECK: load i8*, i8** @"\01L_selector(setSharedCounter:)"
78+
B.sharedCounter = B.sharedCounter + 1
7379
}
7480

7581
// CHECK: define hidden [[B]]* @_TF7objc_ir8downcastFT1aCSo1A_CSo1B(

test/ClangModules/objc_parse.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,20 @@ func testPropertyAndMethodCollision(obj: PropertyAndMethodCollision,
379379
obj.object = nil
380380
obj.object(obj, doSomething:Selector("action"))
381381

382+
obj.dynamicType.classRef = nil
383+
obj.dynamicType.classRef(obj, doSomething:Selector("action"))
384+
382385
rev.object = nil
383386
rev.object(rev, doSomething:Selector("action"))
384387

385-
var value: AnyObject = obj.protoProp()
388+
rev.dynamicType.classRef = nil
389+
rev.dynamicType.classRef(rev, doSomething:Selector("action"))
390+
391+
var value: AnyObject
392+
value = obj.protoProp()
386393
value = obj.protoPropRO()
394+
value = obj.dynamicType.protoClassProp()
395+
value = obj.dynamicType.protoClassPropRO()
387396
_ = value
388397
}
389398

test/IDE/Inputs/mock-sdk/Foo.annotated.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,17 @@ class <loc>FooClassDerived</loc> : <ref:Class>FooClassBase</ref>, <ref:Protocol>
224224
<decl:Constructor><loc>init!()</loc></decl>
225225
<decl:Constructor>convenience <loc>init!(<decl:Param>float f: <ref:Struct>Float</ref></decl>)</loc></decl>
226226
}</decl>
227+
<decl:Class>class <loc>FooClassWithClassProperties</loc> : <ref:Class>FooClassBase</ref> {
228+
<decl:Var>unowned(unsafe) class var <loc>assignable</loc>: @sil_unmanaged <ref:Protocol>AnyObject</ref>!</decl>
229+
<decl:Var>unowned(unsafe) class var <loc>unsafeAssignable</loc>: @sil_unmanaged <ref:Protocol>AnyObject</ref>!</decl>
230+
<decl:Var>class var <loc>retainable</loc>: <ref:Protocol>AnyObject</ref>!</decl>
231+
<decl:Var>class var <loc>strongRef</loc>: <ref:Protocol>AnyObject</ref>!</decl>
232+
<decl:Var>@NSCopying class var <loc>copyable</loc>: <ref:Protocol>AnyObject</ref>!</decl>
233+
<decl:Var>weak class var <loc>weakRef</loc>: @sil_weak <ref:Protocol>AnyObject</ref>!</decl>
234+
<decl:Var>class var <loc>scalar</loc>: <ref:Struct>Int32</ref></decl>
235+
<decl:Constructor><loc>init!()</loc></decl>
236+
<decl:Constructor>convenience <loc>init!(<decl:Param>float f: <ref:Struct>Float</ref></decl>)</loc></decl>
237+
}</decl>
227238
<decl:Class>class <loc>FooUnavailableMembers</loc> : <ref:Class>FooClassBase</ref> {
228239
<decl:Constructor>convenience <loc>init!(<decl:Param>int i: <ref:Struct>Int32</ref></decl>)</loc></decl>
229240
<decl:Func>@available(*, unavailable, message: "use object construction 'FooUnavailableMembers(int:)'")

test/IDE/Inputs/mock-sdk/Foo.framework/Headers/Foo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ struct _InternalStruct {
238238
@property (assign) int scalar;
239239
@end
240240

241+
@interface FooClassWithClassProperties : FooClassBase
242+
@property (class, assign) id assignable;
243+
@property (class, unsafe_unretained) id unsafeAssignable;
244+
@property (class, retain) id retainable;
245+
@property (class, strong) id strongRef;
246+
@property (class, copy) id copyable;
247+
@property (class, weak) id weakRef;
248+
@property (class, assign) int scalar;
249+
@end
250+
241251
#define FOO_NIL ((id)0)
242252

243253
@interface FooUnavailableMembers : FooClassBase

test/IDE/Inputs/mock-sdk/Foo.printed.recursive.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,17 @@ class FooClassPropertyOwnership : FooClassBase {
224224
init!()
225225
convenience init!(float f: Float)
226226
}
227+
class FooClassWithClassProperties : FooClassBase {
228+
unowned(unsafe) class var assignable: @sil_unmanaged AnyObject!
229+
unowned(unsafe) class var unsafeAssignable: @sil_unmanaged AnyObject!
230+
class var retainable: AnyObject!
231+
class var strongRef: AnyObject!
232+
@NSCopying class var copyable: AnyObject!
233+
weak class var weakRef: @sil_weak AnyObject!
234+
class var scalar: Int32
235+
init!()
236+
convenience init!(float f: Float)
237+
}
227238
class FooUnavailableMembers : FooClassBase {
228239
convenience init!(int i: Int32)
229240
@available(*, unavailable, message: "use object construction 'FooUnavailableMembers(int:)'")

test/IDE/Inputs/mock-sdk/Foo.printed.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,18 @@ class FooClassPropertyOwnership : FooClassBase {
274274
convenience init!(float f: Float)
275275
}
276276

277+
class FooClassWithClassProperties : FooClassBase {
278+
unowned(unsafe) class var assignable: @sil_unmanaged AnyObject!
279+
unowned(unsafe) class var unsafeAssignable: @sil_unmanaged AnyObject!
280+
class var retainable: AnyObject!
281+
class var strongRef: AnyObject!
282+
@NSCopying class var copyable: AnyObject!
283+
weak class var weakRef: @sil_weak AnyObject!
284+
class var scalar: Int32
285+
init!()
286+
convenience init!(float f: Float)
287+
}
288+
277289
class FooUnavailableMembers : FooClassBase {
278290
convenience init!(int i: Int32)
279291
@available(*, unavailable, message: "use object construction 'FooUnavailableMembers(int:)'")

test/Inputs/clang-importer-sdk/usr/include/objc/NSObject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
- performMultiplyWithValue:(int)x value:(int)y;
6262
- moveFor:(int)x;
6363
@property (readonly) int readCounter;
64+
@property (class) int sharedCounter;
6465

6566
@property int informalMadeFormal;
6667

test/Interpreter/Inputs/ObjCClasses/ObjCClasses.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,35 @@ NS_ASSUME_NONNULL_BEGIN
5858
@interface AnimalContainer<C: Animal *> : Container<C>
5959
@end
6060

61+
#if __has_feature(objc_class_property)
62+
@protocol ProtoWithClassProperty
63+
+ (void)reset;
64+
@property (class) int value;
65+
66+
@optional
67+
@property (class, readonly) BOOL optionalClassProp;
68+
@end
69+
70+
@interface ClassWithClassProperty : NSObject <ProtoWithClassProperty>
71+
@end
72+
73+
@interface ObjCSubclassWithClassProperty : ClassWithClassProperty
74+
// Deliberately redeclared.
75+
@property (class) int value;
76+
@end
77+
78+
@protocol PropertyNamingConflictProto
79+
@property (nullable) id protoProp;
80+
@property (class, nullable) id protoProp;
81+
@end
82+
83+
@interface PropertyNamingConflict : NSObject
84+
@property (readonly, nullable) id prop;
85+
@property (class, readonly, nullable) id prop;
86+
@end
87+
88+
#endif // __has_feature(objc_class_property)
89+
6190
NS_ASSUME_NONNULL_END
6291

6392
#endif

test/Interpreter/Inputs/ObjCClasses/ObjCClasses.m

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,30 @@ - (NSString *)noise {
8181
@implementation AnimalContainer
8282
@end
8383

84+
#if __has_feature(objc_class_property)
85+
static int _value = 0;
86+
@implementation ClassWithClassProperty
87+
+ (int)value {
88+
return _value;
89+
}
90+
+ (void)setValue:(int)newValue {
91+
_value = newValue;
92+
}
93+
+ (void)reset {
94+
_value = 0;
95+
}
96+
@end
97+
98+
@implementation ObjCSubclassWithClassProperty
99+
+ (BOOL)optionalClassProp {
100+
return YES;
101+
}
102+
@end
103+
104+
@implementation PropertyNamingConflict
105+
- (id)prop { return self; }
106+
+ (id)prop { return nil; }
107+
@end
108+
109+
#endif
110+

0 commit comments

Comments
 (0)