2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #import <objc/runtime.h>
27 #import <wtf/HashSet.h>
28 #import <wtf/Vector.h>
30 inline bool protocolImplementsProtocol(Protocol
*candidate
, Protocol
*target
)
32 unsigned protocolProtocolsCount
;
33 Protocol
** protocolProtocols
= protocol_copyProtocolList(candidate
, &protocolProtocolsCount
);
34 for (unsigned i
= 0; i
< protocolProtocolsCount
; ++i
) {
35 if (protocol_isEqual(protocolProtocols
[i
], target
)) {
36 free(protocolProtocols
);
40 free(protocolProtocols
);
44 inline void forEachProtocolImplementingProtocol(Class cls
, Protocol
*target
, void (^callback
)(Protocol
*))
49 Vector
<Protocol
*> worklist
;
50 HashSet
<void*> visited
;
52 // Initially fill the worklist with the Class's protocols.
53 unsigned protocolsCount
;
54 Protocol
** protocols
= class_copyProtocolList(cls
, &protocolsCount
);
55 worklist
.append(protocols
, protocolsCount
);
58 while (!worklist
.isEmpty()) {
59 Protocol
*protocol
= worklist
.last();
60 worklist
.removeLast();
62 // Are we encountering this Protocol for the first time?
63 if (!visited
.add(protocol
).isNewEntry
)
66 // If it implements the protocol, make the callback.
67 if (protocolImplementsProtocol(protocol
, target
))
70 // Add incorporated protocols to the worklist.
71 protocols
= protocol_copyProtocolList(protocol
, &protocolsCount
);
72 worklist
.append(protocols
, protocolsCount
);
77 inline void forEachMethodInClass(Class cls
, void (^callback
)(Method
))
80 Method
* methods
= class_copyMethodList(cls
, &count
);
81 for (unsigned i
= 0; i
< count
; ++i
)
86 inline void forEachMethodInProtocol(Protocol
*protocol
, BOOL isRequiredMethod
, BOOL isInstanceMethod
, void (^callback
)(SEL
, const char*))
89 struct objc_method_description
* methods
= protocol_copyMethodDescriptionList(protocol
, isRequiredMethod
, isInstanceMethod
, &count
);
90 for (unsigned i
= 0; i
< count
; ++i
)
91 callback(methods
[i
].name
, methods
[i
].types
);
95 inline void forEachPropertyInProtocol(Protocol
*protocol
, void (^callback
)(objc_property_t
))
98 objc_property_t
* properties
= protocol_copyPropertyList(protocol
, &count
);
99 for (unsigned i
= 0; i
< count
; ++i
)
100 callback(properties
[i
]);
104 template<char open
, char close
>
105 void skipPair(const char*& position
)
109 char c
= *position
++;
111 @
throw [NSException exceptionWithName
:NSInternalInconsistencyException reason
:@
"Malformed type encoding" userInfo
:nil
];
120 WTF_MAKE_NONCOPYABLE(StringRange
);
122 StringRange(const char* begin
, const char* end
) : m_ptr(strndup(begin
, end
- begin
)) { }
123 ~StringRange() { free(m_ptr
); }
124 operator const char*() const { return m_ptr
; }
125 const char* get() const { return m_ptr
; }
132 WTF_MAKE_NONCOPYABLE(StructBuffer
);
134 StructBuffer(const char* encodedType
)
136 NSUInteger size
, alignment
;
137 NSGetSizeAndAlignment(encodedType
, &size
, &alignment
);
139 m_allocation
= static_cast<char*>(malloc(size
+ alignment
));
140 m_buffer
= reinterpret_cast<char*>((reinterpret_cast<intptr_t>(m_allocation
) + alignment
) & ~alignment
);
143 ~StructBuffer() { free(m_allocation
); }
144 operator void*() const { return m_buffer
; }
151 template<typename DelegateType
>
152 typename
DelegateType::ResultType
parseObjCType(const char*& position
)
156 switch (*position
++) {
158 return DelegateType::template typeInteger
<char>();
160 return DelegateType::template typeInteger
<int>();
162 return DelegateType::template typeInteger
<short>();
164 return DelegateType::template typeInteger
<long>();
166 return DelegateType::template typeDouble
<unsigned long long>();
168 return DelegateType::template typeInteger
<unsigned char>();
170 return DelegateType::template typeInteger
<unsigned>();
172 return DelegateType::template typeInteger
<unsigned short>();
174 return DelegateType::template typeInteger
<unsigned long>();
176 return DelegateType::template typeDouble
<unsigned long long>();
178 return DelegateType::template typeDouble
<float>();
180 return DelegateType::template typeDouble
<double>();
182 return DelegateType::typeBool();
184 return DelegateType::typeVoid();
186 case '@': { // An object (whether statically typed or typed id)
187 if (position
[0] == '?' && position
[1] == '<') {
189 const char* begin
= position
;
190 skipPair
<'<','>'>(position
);
191 return DelegateType::typeBlock(begin
, position
- 1);
194 if (*position
== '"') {
195 const char* begin
= position
+ 1;
196 const char* protocolPosition
= strchr(begin
, '<');
197 const char* endOfType
= strchr(begin
, '"');
198 position
= endOfType
+ 1;
200 // There's no protocol involved in this type, so just handle the class name.
201 if (!protocolPosition
|| protocolPosition
> endOfType
)
202 return DelegateType::typeOfClass(begin
, endOfType
);
203 // We skipped the class name and went straight to the protocol, so this is an id type.
204 if (begin
== protocolPosition
)
205 return DelegateType::typeId();
206 // We have a class name with a protocol. For now, ignore the protocol.
207 return DelegateType::typeOfClass(begin
, protocolPosition
);
210 return DelegateType::typeId();
213 case '{': { // {name=type...} A structure
214 const char* begin
= position
- 1;
215 skipPair
<'{','}'>(position
);
216 return DelegateType::typeStruct(begin
, position
);
219 // NOT supporting C strings, arrays, pointers, unions, bitfields, function pointers.
220 case '*': // A character string (char *)
221 case '[': // [array type] An array
222 case '(': // (name=type...) A union
223 case 'b': // bnum A bit field of num bits
224 case '^': // ^type A pointer to type
225 case '?': // An unknown type (among other things, this code is used for function pointers)
226 // NOT supporting Objective-C Class, SEL
227 case '#': // A class object (Class)
228 case ':': // A method selector (SEL)
235 // Forward declare some Objective-C runtime internal methods that are not API.
236 const char *_protocol_getMethodTypeEncoding(Protocol
*, SEL
, BOOL isRequiredMethod
, BOOL isInstanceMethod
);
237 id
objc_initWeak(id
*, id
);
238 void objc_destroyWeak(id
*);
239 bool _Block_has_signature(void *);
240 const char * _Block_signature(void *);