Skip to content

Commit d2e119e

Browse files
committed
fix(runtime): Add forgotten check for protocol availability
* Respect availability attribute in protocols * Add tests refs #1084
1 parent 86df289 commit d2e119e

File tree

4 files changed

+91
-6
lines changed

4 files changed

+91
-6
lines changed

src/NativeScript/Metadata/Metadata.mm

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,10 @@ void collectInheritanceChainMembers(const char* identifier, size_t length, Membe
186186
return result;
187187
}
188188

189-
// search in protcols
189+
// search in protocols
190190
if (includeProtocols) {
191191
for (Array<String>::iterator it = protocols->begin(); it != protocols->end(); ++it) {
192-
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr()));
192+
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr(), onlyIfAvailable));
193193
if (protocolMeta != nullptr) {
194194
const MembersCollection members = protocolMeta->members(identifier, length, type, onlyIfAvailable);
195195
if (members.size() > 0) {
@@ -205,7 +205,7 @@ void collectInheritanceChainMembers(const char* identifier, size_t length, Membe
205205
std::vector<const PropertyMeta*> BaseClassMeta::instancePropertiesWithProtocols(std::vector<const PropertyMeta*>& container, Class klass) const {
206206
this->instanceProperties(container, klass);
207207
for (Array<String>::iterator it = protocols->begin(); it != protocols->end(); ++it) {
208-
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr(), false));
208+
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr()));
209209
if (protocolMeta != nullptr)
210210
protocolMeta->instancePropertiesWithProtocols(container, klass);
211211
}
@@ -215,7 +215,7 @@ void collectInheritanceChainMembers(const char* identifier, size_t length, Membe
215215
std::vector<const PropertyMeta*> BaseClassMeta::staticPropertiesWithProtocols(std::vector<const PropertyMeta*>& container, Class klass) const {
216216
this->staticProperties(container, klass);
217217
for (Array<String>::iterator it = protocols->begin(); it != protocols->end(); ++it) {
218-
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr(), false));
218+
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr()));
219219
if (protocolMeta != nullptr)
220220
protocolMeta->staticPropertiesWithProtocols(container, klass);
221221
}
@@ -241,7 +241,7 @@ void collectInheritanceChainMembers(const char* identifier, size_t length, Membe
241241
vector<const MethodMeta*> BaseClassMeta::initializersWithProtocols(vector<const MethodMeta*>& container, Class klass) const {
242242
this->initializers(container, klass);
243243
for (Array<String>::iterator it = this->protocols->begin(); it != this->protocols->end(); it++) {
244-
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr(), false));
244+
const ProtocolMeta* protocolMeta = static_cast<const ProtocolMeta*>(MetaFile::instance()->globalTable()->findMeta((*it).valuePtr()));
245245
if (protocolMeta != nullptr)
246246
protocolMeta->initializersWithProtocols(container, klass);
247247
}

tests/TestFixtures/Api/TNSVersions.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,33 @@ generateMinors(15);
7575
// max availability version that can be currently represented in the binary metadata is 31.7 (major << 3 | minor) -> uint8_t
7676
#define MAX_AVAILABILITY 31.7
7777

78-
@interface TNSInterfaceAlwaysAvailable : NSObject
78+
__attribute__((availability(ios, introduced = MAX_AVAILABILITY)))
79+
@protocol TNSProtocolNeverAvailable<NSObject>
80+
81+
@property(class, readonly) int staticPropertyFromProtocolNeverAvailable;
82+
83+
+ (void)staticMethodFromProtocolNeverAvailable;
84+
85+
@property(readonly) int propertyFromProtocolNeverAvailable;
86+
87+
- (void)methodFromProtocolNeverAvailable;
88+
89+
@end
90+
91+
__attribute__((availability(ios, introduced = 1.0)))
92+
@protocol TNSProtocolAlwaysAvailable<NSObject>
93+
94+
@property(class, readonly) int staticPropertyFromProtocolAlwaysAvailable;
95+
96+
+ (void)staticMethodFromProtocolAlwaysAvailable;
97+
98+
@property(readonly) int propertyFromProtocolAlwaysAvailable;
99+
100+
- (void)methodFromProtocolAlwaysAvailable;
101+
102+
@end
103+
104+
@interface TNSInterfaceAlwaysAvailable : NSObject <TNSProtocolNeverAvailable, TNSProtocolAlwaysAvailable>
79105
@end
80106

81107
__attribute__((availability(ios, introduced = MAX_AVAILABILITY)))

tests/TestFixtures/Api/TNSVersions.m

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,36 @@
1111
#undef generateVersionImpl
1212

1313
@implementation TNSInterfaceAlwaysAvailable
14+
15+
+ (int)staticPropertyFromProtocolAlwaysAvailable {
16+
TNSLog([NSString stringWithFormat:@"%@ called", NSStringFromSelector(_cmd)]);
17+
return 12;
18+
}
19+
20+
+ (int)staticPropertyFromProtocolNeverAvailable {
21+
TNSLog([NSString stringWithFormat:@"%@ called", NSStringFromSelector(_cmd)]);
22+
return 23;
23+
}
24+
25+
+ (void)staticMethodFromProtocolAlwaysAvailable {
26+
TNSLog([NSString stringWithFormat:@"%@ called", NSStringFromSelector(_cmd)]);
27+
}
28+
29+
+ (void)staticMethodFromProtocolNeverAvailable {
30+
TNSLog([NSString stringWithFormat:@"%@ called", NSStringFromSelector(_cmd)]);
31+
}
32+
33+
@synthesize propertyFromProtocolAlwaysAvailable;
34+
@synthesize propertyFromProtocolNeverAvailable;
35+
36+
- (void)methodFromProtocolAlwaysAvailable {
37+
TNSLog([NSString stringWithFormat:@"%@ called", NSStringFromSelector(_cmd)]);
38+
}
39+
40+
- (void)methodFromProtocolNeverAvailable {
41+
TNSLog([NSString stringWithFormat:@"%@ called", NSStringFromSelector(_cmd)]);
42+
}
43+
1444
@end
1545

1646
@implementation TNSInterfaceNeverAvailable : TNSInterfaceAlwaysAvailable

tests/TestRunner/app/VersionDiffTests.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,33 @@ describe(module.id, function() {
7878
// TNSInterfaceNeverAvailableDescendant : TNSInterfaceNeverAvailable(API31.7 - skipped) : TNSInterfaceAlwaysAvailable
7979
expect(Object.getPrototypeOf(TNSInterfaceNeverAvailableDescendant).toString()).toBe(TNSInterfaceAlwaysAvailable.toString(), "TNSInterfaceNeverAvailable base class should be skipped as it is unavailable");
8080
});
81+
82+
it("Members of a protocol which is unavailable should be skipped", function() {
83+
expect(Object.getOwnPropertyNames(TNSInterfaceAlwaysAvailable)).not.toContain("staticPropertyFromProtocolNeverAvailable", "TNSProtocolNeverAvailable static properties should be skipped as it is unavailable");
84+
expect(TNSInterfaceAlwaysAvailable.staticMethodFromProtocolNeverAvailable).toBeUndefined("TNSProtocolNeverAvailable static methods should be skipped as it is unavailable");
85+
expect(Object.getOwnPropertyNames(TNSInterfaceAlwaysAvailable.prototype)).not.toContain("propertyFromProtocolNeverAvailable", "TNSProtocolNeverAvailable properties should be skipped as it is unavailable");
86+
expect(new TNSInterfaceAlwaysAvailable().methodFromProtocolNeverAvailable).toBeUndefined("TNSProtocolNeverAvailable methods should be skipped as it is unavailable");
87+
});
88+
89+
it("Members of a protocol which is available should be present", function() {
90+
const obj = new TNSInterfaceAlwaysAvailable();
91+
let expectedOutput = "";
92+
expect(Object.getOwnPropertyNames(TNSInterfaceAlwaysAvailable.prototype)).toContain("propertyFromProtocolAlwaysAvailable", "TNSProtocolAlwaysAvailable properties should be present as it is available");
93+
expect(obj.propertyFromProtocolAlwaysAvailable).toBe(0);
94+
95+
expect(obj.methodFromProtocolAlwaysAvailable).toBeDefined("TNSProtocolAlwaysAvailable methods should be present as it is available");
96+
obj.methodFromProtocolAlwaysAvailable(); expectedOutput += "methodFromProtocolAlwaysAvailable called";
97+
expect(TNSGetOutput()).toBe(expectedOutput);
98+
99+
TNSClearOutput();
100+
101+
expectedOutput = "";
102+
expect(Object.getOwnPropertyNames(TNSInterfaceAlwaysAvailable)).toContain("staticPropertyFromProtocolAlwaysAvailable", "TNSProtocolAlwaysAvailable static properties should be present as it is available");
103+
TNSInterfaceAlwaysAvailable.staticPropertyFromProtocolAlwaysAvailable; expectedOutput += "staticPropertyFromProtocolAlwaysAvailable called";
104+
105+
expect(TNSInterfaceAlwaysAvailable.staticMethodFromProtocolAlwaysAvailable).toBeDefined("TNSProtocolAlwaysAvailable static methods should be present as it is available");
106+
TNSInterfaceAlwaysAvailable.staticMethodFromProtocolAlwaysAvailable(); expectedOutput += "staticMethodFromProtocolAlwaysAvailable called";
107+
108+
expect(TNSGetOutput()).toBe(expectedOutput);
109+
});
81110
});

0 commit comments

Comments
 (0)