Skip to content

Commit cc88c41

Browse files
authored
Merge pull request #1086 from NativeScript/bektchiev/respect-availability-attributes-for-protocols
fix(runtime): Respect availability attributes for protocols and base classes
2 parents 9e982f7 + 13c0457 commit cc88c41

24 files changed

+711
-270
lines changed

src/NativeScript/GlobalObject.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989

9090
static Strong<ObjCProtocolWrapper> createProtocolWrapper(GlobalObject* globalObject, const ProtocolMeta* protocolMeta, Protocol* aProtocol) {
9191
Structure* prototypeStructure = ObjCPrototype::createStructure(globalObject->vm(), globalObject, globalObject->objectPrototype());
92-
auto prototype = ObjCPrototype::create(globalObject->vm(), globalObject, prototypeStructure, protocolMeta);
92+
auto prototype = ObjCPrototype::create(globalObject->vm(), globalObject, prototypeStructure, protocolMeta, /*klass*/ nullptr);
9393
Structure* protocolWrapperStructure = ObjCProtocolWrapper::createStructure(globalObject->vm(), globalObject, globalObject->objectPrototype());
9494
auto protocolWrapper = ObjCProtocolWrapper::create(globalObject->vm(), protocolWrapperStructure, prototype.get(), protocolMeta, aProtocol);
9595
prototype->materializeProperties(globalObject->vm(), globalObject);

src/NativeScript/Metadata/Metadata.h

Lines changed: 100 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ static const V& getProperFunctionFromContainer(const std::vector<V>& container,
4646
return *callee;
4747
}
4848

49+
inline UInt8 encodeVersion(UInt8 majorVersion, UInt8 minorVersion) {
50+
return (majorVersion << 3) | minorVersion;
51+
}
52+
53+
inline UInt8 getMajorVersion(UInt8 encodedVersion) {
54+
return encodedVersion >> 3;
55+
}
56+
57+
inline UInt8 getMinorVersion(UInt8 encodedVersion) {
58+
return encodedVersion & 0b111;
59+
}
60+
4961
// Bit indices in flags section
5062
enum MetaFlags {
5163
HasName = 7,
@@ -126,6 +138,7 @@ enum BinaryTypeEncodingType : Byte {
126138
template <typename T>
127139
struct PtrTo;
128140
struct Meta;
141+
struct InterfaceMeta;
129142
struct ProtocolMeta;
130143
struct ModuleMeta;
131144
struct LibraryMeta;
@@ -273,6 +286,18 @@ struct GlobalTable {
273286

274287
ArrayOfPtrTo<ArrayOfPtrTo<Meta>> buckets;
275288

289+
const InterfaceMeta* findInterfaceMeta(WTF::StringImpl* identifier) const;
290+
291+
const InterfaceMeta* findInterfaceMeta(const char* identifierString) const;
292+
293+
const InterfaceMeta* findInterfaceMeta(const char* identifierString, size_t length, unsigned hash) const;
294+
295+
const ProtocolMeta* findProtocol(WTF::StringImpl* identifier) const;
296+
297+
const ProtocolMeta* findProtocol(const char* identifierString) const;
298+
299+
const ProtocolMeta* findProtocol(const char* identifierString, size_t length, unsigned hash) const;
300+
276301
const Meta* findMeta(WTF::StringImpl* identifier, bool onlyIfAvailable = true) const;
277302

278303
const Meta* findMeta(const char* identifierString, bool onlyIfAvailable = true) const;
@@ -667,9 +692,16 @@ struct MethodMeta : MemberMeta {
667692
const char* constructorTokens() const {
668693
return this->_constructorTokens.valuePtr();
669694
}
695+
696+
bool isImplementedInClass(Class klass, bool isStatic) const;
697+
bool isAvailableInClass(Class klass, bool isStatic) const {
698+
return this->isAvailable() && this->isImplementedInClass(klass, isStatic);
699+
}
670700
};
671701

672-
std::unordered_map<std::string, std::vector<const MemberMeta*>> getMetasByJSNames(std::vector<const MemberMeta*> methods);
702+
typedef HashSet<const MemberMeta*> MembersCollection;
703+
704+
std::unordered_map<std::string, MembersCollection> getMetasByJSNames(MembersCollection methods);
673705

674706
struct PropertyMeta : MemberMeta {
675707
PtrTo<MethodMeta> method1;
@@ -691,6 +723,16 @@ struct PropertyMeta : MemberMeta {
691723
const MethodMeta* setter() const {
692724
return (this->hasSetter()) ? (this->hasGetter() ? method2.valuePtr() : method1.valuePtr()) : nullptr;
693725
}
726+
727+
bool isImplementedInClass(Class klass, bool isStatic) const {
728+
bool getterAvailable = this->hasGetter() && this->getter()->isImplementedInClass(klass, isStatic);
729+
bool setterAvailable = this->hasSetter() && this->setter()->isImplementedInClass(klass, isStatic);
730+
return getterAvailable || setterAvailable;
731+
}
732+
733+
bool isAvailableInClass(Class klass, bool isStatic) const {
734+
return this->isAvailable() && this->isImplementedInClass(klass, isStatic);
735+
}
694736
};
695737

696738
struct BaseClassMeta : Meta {
@@ -706,7 +748,7 @@ struct BaseClassMeta : Meta {
706748

707749
const MethodMeta* member(const char* identifier, size_t length, MemberType type, size_t paramsCount, bool includeProtocols = true, bool onlyIfAvailable = true) const;
708750

709-
const std::vector<const MemberMeta*> members(const char* identifier, size_t length, MemberType type, bool includeProtocols = true, bool onlyIfAvailable = true) const;
751+
const MembersCollection members(const char* identifier, size_t length, MemberType type, bool includeProtocols = true, bool onlyIfAvailable = true) const;
710752

711753
const MemberMeta* member(StringImpl* identifier, MemberType type, bool includeProtocols = true) const {
712754
const char* identif = reinterpret_cast<const char*>(identifier->characters8());
@@ -720,7 +762,7 @@ struct BaseClassMeta : Meta {
720762
return this->member(identif, length, type, paramsCount, includeProtocols);
721763
}
722764

723-
const std::vector<const MemberMeta*> members(StringImpl* identifier, MemberType type, bool includeProtocols = true) const {
765+
const MembersCollection members(StringImpl* identifier, MemberType type, bool includeProtocols = true) const {
724766
const char* identif = reinterpret_cast<const char*>(identifier->characters8());
725767
size_t length = (size_t)identifier->length();
726768
return this->members(identif, length, type, includeProtocols);
@@ -731,101 +773,110 @@ struct BaseClassMeta : Meta {
731773
}
732774

733775
/// instance methods
734-
const MethodMeta* instanceMethod(const char* identifier, size_t paramsCount, bool includeProtocols = true) const {
735-
return this->member(identifier, strlen(identifier), MemberType::InstanceMethod, paramsCount, includeProtocols);
736-
}
737776

738-
const MethodMeta* instanceMethod(StringImpl* identifier, size_t paramsCount, bool includeProtocols = true) const {
739-
return this->member(identifier, MemberType::InstanceMethod, paramsCount, includeProtocols);
777+
// Remove all optional methods/properties which are not implemented in the class
778+
template <typename TMemberMeta>
779+
static void filterUnavailableMembers(MembersCollection& members, Class klass, bool isStatic) {
780+
members.removeIf([klass, isStatic](const MemberMeta* memberMeta) {
781+
return !static_cast<const TMemberMeta*>(memberMeta)->isAvailableInClass(klass, isStatic);
782+
});
740783
}
741784

742-
const std::vector<const MemberMeta*> getInstanceMethods(StringImpl* identifier, bool includeProtocols = true) const {
743-
return this->members(identifier, MemberType::InstanceMethod, includeProtocols);
785+
const MembersCollection getInstanceMethods(StringImpl* identifier, Class klass, bool includeProtocols = true) const {
786+
MembersCollection methods = this->members(identifier, MemberType::InstanceMethod, includeProtocols);
787+
788+
filterUnavailableMembers<MethodMeta>(methods, klass, false);
789+
790+
return methods;
744791
}
745792

746793
/// static methods
747-
const MethodMeta* staticMethod(const char* identifier, size_t paramsCount, bool includeProtocols = true) const {
748-
return this->member(identifier, strlen(identifier), MemberType::StaticMethod, paramsCount, includeProtocols);
749-
}
794+
const MembersCollection getStaticMethods(StringImpl* identifier, Class klass, bool includeProtocols = true) const {
795+
MembersCollection methods = this->members(identifier, MemberType::StaticMethod, includeProtocols);
750796

751-
const std::vector<const MemberMeta*> getStaticMethods(StringImpl* identifier, bool includeProtocols = true) const {
752-
return this->members(identifier, MemberType::StaticMethod, includeProtocols);
753-
}
797+
filterUnavailableMembers<MethodMeta>(methods, klass, true);
754798

755-
const MethodMeta* staticMethod(StringImpl* identifier, size_t paramsCount, bool includeProtocols = true) const {
756-
return this->member(identifier, MemberType::StaticMethod, paramsCount, includeProtocols);
799+
return methods;
757800
}
758801

759802
/// instance properties
760-
const PropertyMeta* instanceProperty(const char* identifier, bool includeProtocols = true) const {
761-
return reinterpret_cast<const PropertyMeta*>(this->member(identifier, MemberType::InstanceProperty, includeProtocols));
803+
const PropertyMeta* instanceProperty(const char* identifier, Class klass, bool includeProtocols = true) const {
804+
auto propMeta = static_cast<const PropertyMeta*>(this->member(identifier, MemberType::InstanceProperty, includeProtocols));
805+
return propMeta && propMeta->isAvailableInClass(klass, /*isStatic*/ false) ? propMeta : nullptr;
762806
}
763807

764-
const PropertyMeta* instanceProperty(StringImpl* identifier, bool includeProtocols = true) const {
765-
return reinterpret_cast<const PropertyMeta*>(this->member(identifier, MemberType::InstanceProperty, includeProtocols));
808+
const PropertyMeta* instanceProperty(StringImpl* identifier, Class klass, bool includeProtocols = true) const {
809+
auto propMeta = static_cast<const PropertyMeta*>(this->member(identifier, MemberType::InstanceProperty, includeProtocols));
810+
return propMeta && propMeta->isAvailableInClass(klass, /*isStatic*/ false) ? propMeta : nullptr;
766811
}
767812

768813
/// static properties
769-
const PropertyMeta* staticProperty(const char* identifier, bool includeProtocols = true) const {
770-
return reinterpret_cast<const PropertyMeta*>(this->member(identifier, MemberType::StaticProperty, includeProtocols));
814+
const PropertyMeta* staticProperty(const char* identifier, Class klass, bool includeProtocols = true) const {
815+
auto propMeta = static_cast<const PropertyMeta*>(this->member(identifier, MemberType::StaticProperty, includeProtocols));
816+
return propMeta && propMeta->isAvailableInClass(klass, /*isStatic*/ true) ? propMeta : nullptr;
771817
}
772818

773-
const PropertyMeta* staticProperty(StringImpl* identifier, bool includeProtocols = true) const {
774-
return reinterpret_cast<const PropertyMeta*>(this->member(identifier, MemberType::StaticProperty, includeProtocols));
819+
const PropertyMeta* staticProperty(StringImpl* identifier, Class klass, bool includeProtocols = true) const {
820+
auto propMeta = static_cast<const PropertyMeta*>(this->member(identifier, MemberType::StaticProperty, includeProtocols));
821+
return propMeta && propMeta->isAvailableInClass(klass, /*isStatic*/ true) ? propMeta : nullptr;
775822
}
776823

777824
/// vectors
778-
std::vector<const PropertyMeta*> instanceProperties() const {
825+
std::vector<const PropertyMeta*> instanceProperties(Class klass) const {
779826
std::vector<const PropertyMeta*> properties;
780-
return this->instanceProperties(properties);
827+
return this->instanceProperties(properties, klass);
781828
}
782829

783-
std::vector<const PropertyMeta*> instancePropertiesWithProtocols() const {
830+
std::vector<const PropertyMeta*> instancePropertiesWithProtocols(Class klass) const {
784831
std::vector<const PropertyMeta*> properties;
785-
return this->instancePropertiesWithProtocols(properties);
832+
return this->instancePropertiesWithProtocols(properties, klass);
786833
}
787834

788-
std::vector<const PropertyMeta*> instanceProperties(std::vector<const PropertyMeta*>& container) const {
835+
std::vector<const PropertyMeta*> instanceProperties(std::vector<const PropertyMeta*>& container, Class klass) const {
789836
for (Array<PtrTo<PropertyMeta>>::iterator it = this->instanceProps->begin(); it != this->instanceProps->end(); it++) {
790-
container.push_back((*it).valuePtr());
837+
if ((*it)->isAvailableInClass(klass, /*isStatic*/ false)) {
838+
container.push_back((*it).valuePtr());
839+
}
791840
}
792841
return container;
793842
}
794843

795-
std::vector<const PropertyMeta*> instancePropertiesWithProtocols(std::vector<const PropertyMeta*>& container) const;
844+
std::vector<const PropertyMeta*> instancePropertiesWithProtocols(std::vector<const PropertyMeta*>& container, Class klass) const;
796845

797-
std::vector<const PropertyMeta*> staticProperties() const {
846+
std::vector<const PropertyMeta*> staticProperties(Class klass) const {
798847
std::vector<const PropertyMeta*> properties;
799-
return this->staticProperties(properties);
848+
return this->staticProperties(properties, klass);
800849
}
801850

802-
std::vector<const PropertyMeta*> staticPropertiesWithProtocols() const {
851+
std::vector<const PropertyMeta*> staticPropertiesWithProtocols(Class klass) const {
803852
std::vector<const PropertyMeta*> properties;
804-
return this->staticPropertiesWithProtocols(properties);
853+
return this->staticPropertiesWithProtocols(properties, klass);
805854
}
806855

807-
std::vector<const PropertyMeta*> staticProperties(std::vector<const PropertyMeta*>& container) const {
856+
std::vector<const PropertyMeta*> staticProperties(std::vector<const PropertyMeta*>& container, Class klass) const {
808857
for (Array<PtrTo<PropertyMeta>>::iterator it = this->staticProps->begin(); it != this->staticProps->end(); it++) {
809-
container.push_back((*it).valuePtr());
858+
if ((*it)->isAvailableInClass(klass, /*isStatic*/ true)) {
859+
container.push_back((*it).valuePtr());
860+
}
810861
}
811862
return container;
812863
}
813864

814-
std::vector<const PropertyMeta*> staticPropertiesWithProtocols(std::vector<const PropertyMeta*>& container) const;
865+
std::vector<const PropertyMeta*> staticPropertiesWithProtocols(std::vector<const PropertyMeta*>& container, Class klass) const;
815866

816-
std::vector<const MethodMeta*> initializers() const {
867+
std::vector<const MethodMeta*> initializers(Class klass) const {
817868
std::vector<const MethodMeta*> initializers;
818-
return this->initializers(initializers);
869+
return this->initializers(initializers, klass);
819870
}
820871

821-
std::vector<const MethodMeta*> initializersWithProtcols() const {
872+
std::vector<const MethodMeta*> initializersWithProtocols(Class klass) const {
822873
std::vector<const MethodMeta*> initializers;
823-
return this->initializersWithProtcols(initializers);
874+
return this->initializersWithProtocols(initializers, klass);
824875
}
825876

826-
std::vector<const MethodMeta*> initializers(std::vector<const MethodMeta*>& container) const;
877+
std::vector<const MethodMeta*> initializers(std::vector<const MethodMeta*>& container, Class klass) const;
827878

828-
std::vector<const MethodMeta*> initializersWithProtcols(std::vector<const MethodMeta*>& container) const;
879+
std::vector<const MethodMeta*> initializersWithProtocols(std::vector<const MethodMeta*>& container, Class klass) const;
829880
};
830881

831882
struct ProtocolMeta : BaseClassMeta {
@@ -843,9 +894,10 @@ struct InterfaceMeta : BaseClassMeta {
843894

844895
const InterfaceMeta* baseMeta() const {
845896
if (this->baseName() != nullptr) {
846-
const Meta* baseMeta = MetaFile::instance()->globalTable()->findMeta(this->baseName());
847-
return baseMeta->type() == MetaType::Interface ? reinterpret_cast<const InterfaceMeta*>(baseMeta) : nullptr;
897+
const InterfaceMeta* baseMeta = MetaFile::instance()->globalTable()->findInterfaceMeta(this->baseName());
898+
return baseMeta;
848899
}
900+
849901
return nullptr;
850902
}
851903
};

0 commit comments

Comments
 (0)