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/Protocol.h>
27 #import <objc/runtime.h>
28 #import <wtf/HashSet.h>
29 #import <wtf/Vector.h>
31 inline bool protocolImplementsProtocol(Protocol
*candidate
, Protocol
*target
)
33 unsigned protocolProtocolsCount
;
34 Protocol
** protocolProtocols
= protocol_copyProtocolList(candidate
, &protocolProtocolsCount
);
35 for (unsigned i
= 0; i
< protocolProtocolsCount
; ++i
) {
36 if (protocol_isEqual(protocolProtocols
[i
], target
)) {
37 free(protocolProtocols
);
41 free(protocolProtocols
);
45 inline void forEachProtocolImplementingProtocol(Class cls
, Protocol
*target
, void (^callback
)(Protocol
*))
50 Vector
<Protocol
*> worklist
;
51 HashSet
<void*> visited
;
53 // Initially fill the worklist with the Class's protocols.
54 unsigned protocolsCount
;
55 Protocol
** protocols
= class_copyProtocolList(cls
, &protocolsCount
);
56 worklist
.append(protocols
, protocolsCount
);
59 while (!worklist
.isEmpty()) {
60 Protocol
*protocol
= worklist
.last();
61 worklist
.removeLast();
63 // Are we encountering this Protocol for the first time?
64 if (!visited
.add(protocol
).isNewEntry
)
67 // If it implements the protocol, make the callback.
68 if (protocolImplementsProtocol(protocol
, target
))
71 // Add incorporated protocols to the worklist.
72 protocols
= protocol_copyProtocolList(protocol
, &protocolsCount
);
73 worklist
.append(protocols
, protocolsCount
);
78 inline void forEachMethodInClass(Class cls
, void (^callback
)(Method
))
81 Method
* methods
= class_copyMethodList(cls
, &count
);
82 for (unsigned i
= 0; i
< count
; ++i
)
87 inline void forEachMethodInProtocol(Protocol
*protocol
, BOOL isRequiredMethod
, BOOL isInstanceMethod
, void (^callback
)(SEL
, const char*))
90 struct objc_method_description
* methods
= protocol_copyMethodDescriptionList(protocol
, isRequiredMethod
, isInstanceMethod
, &count
);
91 for (unsigned i
= 0; i
< count
; ++i
)
92 callback(methods
[i
].name
, methods
[i
].types
);
96 inline void forEachPropertyInProtocol(Protocol
*protocol
, void (^callback
)(objc_property_t
))
99 objc_property_t
* properties
= protocol_copyPropertyList(protocol
, &count
);
100 for (unsigned i
= 0; i
< count
; ++i
)
101 callback(properties
[i
]);
105 template<char open
, char close
>
106 void skipPair(const char*& position
)
110 char c
= *position
++;
112 @
throw [NSException exceptionWithName
:NSInternalInconsistencyException reason
:@
"Malformed type encoding" userInfo
:nil
];
121 WTF_MAKE_NONCOPYABLE(StringRange
);
123 StringRange(const char* begin
, const char* end
) : m_ptr(strndup(begin
, end
- begin
)) { }
124 ~StringRange() { free(m_ptr
); }
125 operator const char*() const { return m_ptr
; }
126 const char* get() const { return m_ptr
; }
133 WTF_MAKE_NONCOPYABLE(StructBuffer
);
135 StructBuffer(const char* encodedType
)
137 NSUInteger size
, alignment
;
138 NSGetSizeAndAlignment(encodedType
, &size
, &alignment
);
140 m_allocation
= static_cast<char*>(malloc(size
+ alignment
));
141 m_buffer
= reinterpret_cast<char*>((reinterpret_cast<intptr_t>(m_allocation
) + alignment
) & ~alignment
);
144 ~StructBuffer() { free(m_allocation
); }
145 operator void*() const { return m_buffer
; }
152 template<typename DelegateType
>
153 typename
DelegateType::ResultType
parseObjCType(const char*& position
)
157 switch (*position
++) {
159 return DelegateType::template typeInteger
<char>();
161 return DelegateType::template typeInteger
<int>();
163 return DelegateType::template typeInteger
<short>();
165 return DelegateType::template typeInteger
<long>();
167 return DelegateType::template typeDouble
<long long>();
169 return DelegateType::template typeInteger
<unsigned char>();
171 return DelegateType::template typeInteger
<unsigned>();
173 return DelegateType::template typeInteger
<unsigned short>();
175 return DelegateType::template typeInteger
<unsigned long>();
177 return DelegateType::template typeDouble
<unsigned long long>();
179 return DelegateType::template typeDouble
<float>();
181 return DelegateType::template typeDouble
<double>();
183 return DelegateType::typeBool();
185 return DelegateType::typeVoid();
187 case '@': { // An object (whether statically typed or typed id)
188 if (position
[0] == '?' && position
[1] == '<') {
190 const char* begin
= position
;
191 skipPair
<'<','>'>(position
);
192 return DelegateType::typeBlock(begin
, position
- 1);
195 if (*position
== '"') {
196 const char* begin
= position
+ 1;
197 const char* protocolPosition
= strchr(begin
, '<');
198 const char* endOfType
= strchr(begin
, '"');
199 position
= endOfType
+ 1;
201 // There's no protocol involved in this type, so just handle the class name.
202 if (!protocolPosition
|| protocolPosition
> endOfType
)
203 return DelegateType::typeOfClass(begin
, endOfType
);
204 // We skipped the class name and went straight to the protocol, so this is an id type.
205 if (begin
== protocolPosition
)
206 return DelegateType::typeId();
207 // We have a class name with a protocol. For now, ignore the protocol.
208 return DelegateType::typeOfClass(begin
, protocolPosition
);
211 return DelegateType::typeId();
214 case '{': { // {name=type...} A structure
215 const char* begin
= position
- 1;
216 skipPair
<'{','}'>(position
);
217 return DelegateType::typeStruct(begin
, position
);
220 // NOT supporting C strings, arrays, pointers, unions, bitfields, function pointers.
221 case '*': // A character string (char *)
222 case '[': // [array type] An array
223 case '(': // (name=type...) A union
224 case 'b': // bnum A bit field of num bits
225 case '^': // ^type A pointer to type
226 case '?': // An unknown type (among other things, this code is used for function pointers)
227 // NOT supporting Objective-C Class, SEL
228 case '#': // A class object (Class)
229 case ':': // A method selector (SEL)
236 // Forward declare some Objective-C runtime internal methods that are not API.
237 const char *_protocol_getMethodTypeEncoding(Protocol
*, SEL
, BOOL isRequiredMethod
, BOOL isInstanceMethod
);
238 id
objc_initWeak(id
*, id
);
239 void objc_destroyWeak(id
*);
240 bool _Block_has_signature(void *);
241 const char * _Block_signature(void *);