1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// ---------------------------------------------------------------------------
5// typeparse.h
6// ---------------------------------------------------------------------------
7//
8
9//
10
11
12#ifndef TYPEPARSE_H
13#define TYPEPARSE_H
14
15#include "common.h"
16#include "class.h"
17#include "typehandle.h"
18
19// To work around a warning about redefining "TypeName" include the file
20// that defines Windows.UI.Xaml.Interop.TypeName now.
21#ifdef FEATURE_COMINTEROP
22#include <windows.ui.xaml.interop.h>
23#endif
24
25//#define TYPE_NAME_RESERVED_CHAR W(",[]&*+\\")
26
27bool inline IsTypeNameReservedChar(WCHAR ch)
28{
29 LIMITED_METHOD_CONTRACT;
30
31 switch (ch)
32 {
33 case W(','):
34 case W('['):
35 case W(']'):
36 case W('&'):
37 case W('*'):
38 case W('+'):
39 case W('\\'):
40 return true;
41
42 default:
43 return false;
44 }
45}
46
47
48DomainAssembly * LoadDomainAssembly(
49 SString * psszAssemblySpec,
50 Assembly * pRequestingAssembly,
51 ICLRPrivBinder * pPrivHostBinder,
52 BOOL bThrowIfNotFound,
53 SString * pssOuterTypeName);
54
55class TypeNameFactory : public ITypeNameFactory
56{
57public:
58 static HRESULT CreateObject(REFIID riid, void **ppUnk);
59
60public:
61 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppUnk);
62 virtual ULONG STDMETHODCALLTYPE AddRef() { LIMITED_METHOD_CONTRACT; m_count++; return m_count; }
63 virtual ULONG STDMETHODCALLTYPE Release() { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC_HOST_ONLY; m_count--; ULONG count = m_count; if (count == 0) delete this; return count; }
64
65public:
66 virtual HRESULT STDMETHODCALLTYPE ParseTypeName(LPCWSTR szName, DWORD* pError, ITypeName** ppTypeName);
67 virtual HRESULT STDMETHODCALLTYPE GetTypeNameBuilder(ITypeNameBuilder** ppTypeBuilder);
68
69public:
70 TypeNameFactory() : m_count(0)
71 {
72 WRAPPER_NO_CONTRACT;
73 SString::Startup();
74 }
75
76 virtual ~TypeNameFactory() {}
77
78private:
79 DWORD m_count;
80};
81
82class TypeName : public ITypeName
83{
84private:
85 template<typename PRODUCT>
86 class Factory
87 {
88 public:
89 const static DWORD MAX_PRODUCT = 4;
90
91 public:
92 Factory() : m_cProduct(0), m_next(NULL) { LIMITED_METHOD_CONTRACT; }
93 ~Factory()
94 {
95 CONTRACTL
96 {
97 NOTHROW;
98 SO_TOLERANT;
99 }
100 CONTRACTL_END;
101 VALIDATE_BACKOUT_STACK_CONSUMPTION;
102
103 if (m_next)
104 delete m_next;
105 }
106
107 PRODUCT* Create()
108 { WRAPPER_NO_CONTRACT; if (m_cProduct == (INT32)MAX_PRODUCT) return GetNext()->Create(); return &m_product[m_cProduct++]; }
109
110 private:
111 Factory* GetNext() { if (!m_next) m_next = new Factory<PRODUCT>(); return m_next; }
112
113 private:
114 PRODUCT m_product[MAX_PRODUCT];
115 INT32 m_cProduct;
116 Factory* m_next;
117 };
118 friend class TypeName::Factory<TypeName>;
119 friend class TypeNameBuilder;
120
121private:
122 class TypeNameParser
123 {
124 TypeNameParser(LPCWSTR szTypeName, TypeName* pTypeName)
125 {
126 CONTRACTL
127 {
128 THROWS;
129 GC_NOTRIGGER;
130 MODE_ANY;
131 }
132 CONTRACTL_END;
133
134 if (szTypeName == NULL)
135 {
136 szTypeName = W("");
137 }
138
139 m_currentToken = TypeNameEmpty;
140 m_nextToken = TypeNameEmpty;
141
142 m_pTypeName = pTypeName;
143 m_sszTypeName = szTypeName;
144 m_currentItr = m_itr = m_sszTypeName;
145 }
146
147 private:
148 friend class TypeName;
149
150 private:
151 typedef enum {
152 //
153 // TOKENS
154 //
155 TypeNameEmpty = 0x8000,
156 TypeNameIdentifier = 0x0001,
157 TypeNamePostIdentifier = 0x0002,
158 TypeNameOpenSqBracket = 0x0004,
159 TypeNameCloseSqBracket = 0x0008,
160 TypeNameComma = 0x0010,
161 TypeNamePlus = 0x0020,
162 TypeNameAstrix = 0x0040,
163 TypeNameAmpersand = 0x0080,
164 TypeNameBackSlash = 0x0100,
165 TypeNameEnd = 0x4000,
166
167 //
168 // 1 TOKEN LOOK AHEAD
169 //
170 TypeNameNAME = TypeNameIdentifier,
171 TypeNameNESTNAME = TypeNameIdentifier,
172 TypeNameASSEMSPEC = TypeNameIdentifier,
173 TypeNameGENPARAM = TypeNameOpenSqBracket | TypeNameEmpty,
174 TypeNameFULLNAME = TypeNameNAME,
175 TypeNameAQN = TypeNameFULLNAME | TypeNameEnd,
176 TypeNameASSEMBLYSPEC = TypeNameIdentifier,
177 TypeNameGENARG = TypeNameOpenSqBracket | TypeNameFULLNAME,
178 TypeNameGENARGS = TypeNameGENARG,
179 TypeNameEAQN = TypeNameIdentifier,
180 TypeNameEASSEMSPEC = TypeNameIdentifier,
181 TypeNameARRAY = TypeNameOpenSqBracket,
182 TypeNameQUALIFIER = TypeNameAmpersand | TypeNameAstrix | TypeNameARRAY | TypeNameEmpty,
183 TypeNameRANK = TypeNameComma | TypeNameEmpty,
184 } TypeNameTokens;
185
186 typedef enum {
187 TypeNameNone = 0x00,
188 TypeNameId = 0x01,
189 TypeNameFusionName = 0x02,
190 TypeNameEmbeddedFusionName = 0x03,
191 } TypeNameIdentifiers;
192
193 //
194 // LEXIFIER
195 //
196 private:
197 TypeNameTokens LexAToken(BOOL ignorePlus = FALSE);
198 BOOL GetIdentifier(SString* sszId, TypeNameIdentifiers identiferType);
199 void NextToken() { WRAPPER_NO_CONTRACT; m_currentToken = m_nextToken; m_currentItr = m_itr; m_nextToken = LexAToken(); }
200 BOOL NextTokenIs(TypeNameTokens token) { LIMITED_METHOD_CONTRACT; return !!(m_nextToken & token); }
201 BOOL TokenIs(TypeNameTokens token) { LIMITED_METHOD_CONTRACT; return !!(m_currentToken & token); }
202 BOOL TokenIs(int token) { LIMITED_METHOD_CONTRACT; return TokenIs((TypeNameTokens)token); }
203
204 //
205 // PRODUCTIONS
206 //
207 private:
208 BOOL START();
209
210 BOOL AQN();
211 // /* empty */
212 // FULLNAME ',' ASSEMSPEC
213 // FULLNAME
214
215 BOOL ASSEMSPEC();
216 // fusionName
217
218 BOOL FULLNAME();
219 // NAME GENPARAMS QUALIFIER
220
221 BOOL GENPARAMS();
222 // *empty*
223 // '[' GENARGS ']'
224
225 BOOL GENARGS();
226 // GENARG
227 // GENARG ',' GENARGS
228
229 BOOL GENARG();
230 // '[' EAQN ']'
231 // FULLNAME
232
233 BOOL EAQN();
234 // FULLNAME ',' EASSEMSPEC
235 // FULLNAME
236
237 BOOL EASSEMSPEC();
238 // embededFusionName
239
240 BOOL QUALIFIER();
241 // *empty*
242 // '&'
243 // *' QUALIFIER
244 // ARRAY QUALIFIER
245
246 BOOL ARRAY();
247 // '[' RANK ']'
248 // '[' '*' ']'
249
250 BOOL RANK(DWORD* pdwRank);
251 // *empty*
252 // ',' RANK
253
254 BOOL NAME();
255 // id
256 // id '+' NESTNAME
257
258 BOOL NESTNAME();
259 // id
260 // id '+' NESTNAME
261
262 public:
263 void Parse(DWORD* pError)
264 {
265 CONTRACTL
266 {
267 THROWS;
268 GC_NOTRIGGER;
269 MODE_ANY;
270 }
271 CONTRACTL_END;
272
273 *pError = (DWORD)-1;
274 if (!START())
275 *pError = (DWORD)(m_currentItr - m_sszTypeName) - 1;
276 }
277
278 private:
279 TypeName* m_pTypeName;
280 LPCWSTR m_sszTypeName;
281 LPCWSTR m_itr;
282 LPCWSTR m_currentItr;
283 TypeNameTokens m_currentToken;
284 TypeNameTokens m_nextToken;
285 };
286 friend class TypeName::TypeNameParser;
287
288public:
289 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppUnk);
290 virtual ULONG STDMETHODCALLTYPE AddRef();
291 virtual ULONG STDMETHODCALLTYPE Release();
292
293public:
294 virtual HRESULT STDMETHODCALLTYPE GetNameCount(DWORD* pCount);
295 virtual HRESULT STDMETHODCALLTYPE GetNames(DWORD count, BSTR* rgbszNames, DWORD* pFetched);
296 virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentCount(DWORD* pCount);
297 virtual HRESULT STDMETHODCALLTYPE GetTypeArguments(DWORD count, ITypeName** rgpArguments, DWORD* pFetched);
298 virtual HRESULT STDMETHODCALLTYPE GetModifierLength(DWORD* pCount);
299 virtual HRESULT STDMETHODCALLTYPE GetModifiers(DWORD count, DWORD* rgModifiers, DWORD* pFetched);
300 virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(BSTR* rgbszAssemblyNames);
301
302public:
303 TypeName(LPCWSTR szTypeName, DWORD* pError) : m_bIsGenericArgument(FALSE), m_count(0)
304 {
305 CONTRACTL
306 {
307 THROWS;
308 GC_NOTRIGGER;
309 MODE_ANY;
310 }
311 CONTRACTL_END;
312 TypeNameParser parser(szTypeName, this);
313 parser.Parse(pError);
314 }
315
316 virtual ~TypeName();
317
318public:
319#ifndef CROSSGEN_COMPILE
320 static void QCALLTYPE QCreateTypeNameParser (LPCWSTR wszTypeName, QCall::ObjectHandleOnStack pNames, BOOL throwOnError);
321 static void QCALLTYPE QReleaseTypeNameParser(TypeName * pTypeName);
322 static void QCALLTYPE QGetNames (TypeName * pTypeName, QCall::ObjectHandleOnStack pNames);
323 static void QCALLTYPE QGetTypeArguments (TypeName * pTypeName, QCall::ObjectHandleOnStack pTypeArguments);
324 static void QCALLTYPE QGetModifiers (TypeName * pTypeName, QCall::ObjectHandleOnStack pModifiers);
325 static void QCALLTYPE QGetAssemblyName (TypeName * pTypeName, QCall::StringHandleOnStack pAssemblyName);
326#endif //CROSSGEN_COMPILE
327
328 //-------------------------------------------------------------------------------------------
329 // Retrieves a type from an assembly. It requires the caller to know which assembly
330 // the type is in.
331 //-------------------------------------------------------------------------------------------
332 static TypeHandle GetTypeFromAssembly(LPCWSTR szTypeName, Assembly *pAssembly, BOOL bThrowIfNotFound = TRUE);
333
334 TypeHandle GetTypeFromAsm();
335
336 //-------------------------------------------------------------------------------------------
337 // Retrieves a type. Will assert if the name is not fully qualified.
338 //-------------------------------------------------------------------------------------------
339 static TypeHandle GetTypeFromAsmQualifiedName(LPCWSTR szFullyQualifiedName);
340
341
342 //-------------------------------------------------------------------------------------------
343 // This version is used for resolving types named in custom attributes such as those used
344 // for interop. Thus, it follows a well-known multistage set of rules for determining which
345 // assembly the type is in. It will also enforce that the requesting assembly has access
346 // rights to the type being loaded.
347 //
348 // The search logic is:
349 //
350 // if szTypeName is ASM-qualified, only that assembly will be searched.
351 // if szTypeName is not ASM-qualified, we will search for the types in the following order:
352 // - in pRequestingAssembly (if not NULL). pRequestingAssembly is the assembly that contained
353 // the custom attribute from which the typename was derived.
354 // - in mscorlib.dll
355 // - raise an AssemblyResolveEvent() in the current appdomain
356 //
357 // pRequestingAssembly may be NULL. In that case, the "visibility" check will simply check that
358 // the loaded type has public access.
359 //
360 //--------------------------------------------------------------------------------------------
361 static TypeHandle GetTypeUsingCASearchRules(LPCUTF8 szTypeName, Assembly *pRequestingAssembly, BOOL *pfTypeNameWasQualified = NULL, BOOL bDoVisibilityChecks = TRUE);
362 static TypeHandle GetTypeUsingCASearchRules(LPCWSTR szTypeName, Assembly *pRequestingAssembly, BOOL *pfTypeNameWasQualified = NULL, BOOL bDoVisibilityChecks = TRUE);
363
364
365 //--------------------------------------------------------------------------------------------------------------
366 // This everything-but-the-kitchen-sink version is what used to be called "GetType()". It exposes all the
367 // funky knobs needed for implementing the specific requirements of the managed Type.GetType() apis and friends.
368 // Really that knowledge shouldn't even be embedded in the TypeParse class at all but for now, we'll
369 // settle for giving this entrypoint a really ugly name so that only the two FCALL's that really need it will call
370 // it.
371 //--------------------------------------------------------------------------------------------------------------
372 static TypeHandle GetTypeManaged(
373 LPCWSTR szTypeName,
374 DomainAssembly* pAssemblyGetType,
375 BOOL bThrowIfNotFound,
376 BOOL bIgnoreCase,
377 BOOL bProhibitAssemblyQualifiedName,
378 Assembly* pRequestingAssembly,
379 BOOL bLoadTypeFromPartialNameHack,
380 OBJECTREF *pKeepAlive,
381 ICLRPrivBinder * pPrivHostBinder = nullptr);
382
383
384public:
385 SString* GetAssembly() { WRAPPER_NO_CONTRACT; return &m_assembly; }
386
387private:
388 TypeName() : m_bIsGenericArgument(FALSE), m_count(0) { LIMITED_METHOD_CONTRACT; }
389 TypeName* AddGenericArgument();
390
391 SString* AddName()
392 {
393 CONTRACTL
394 {
395 THROWS;
396 GC_NOTRIGGER;
397 MODE_ANY;
398 }
399 CONTRACTL_END;
400
401 return m_names.AppendEx(m_nestNameFactory.Create());
402 }
403
404 SArray<SString*>& GetNames() { WRAPPER_NO_CONTRACT; return m_names; }
405 SArray<TypeName*>& GetGenericArguments() { WRAPPER_NO_CONTRACT; return m_genericArguments; }
406 SArray<DWORD>& GetSignature() { WRAPPER_NO_CONTRACT; return m_signature; }
407 void SetByRef() { WRAPPER_NO_CONTRACT; m_signature.Append(ELEMENT_TYPE_BYREF); }
408 void SetPointer() { WRAPPER_NO_CONTRACT; m_signature.Append(ELEMENT_TYPE_PTR); }
409 void SetSzArray() { WRAPPER_NO_CONTRACT; m_signature.Append(ELEMENT_TYPE_SZARRAY); }
410
411 void SetArray(DWORD rank)
412 {
413 CONTRACTL
414 {
415 THROWS;
416 GC_NOTRIGGER;
417 MODE_ANY;
418 }
419 CONTRACTL_END;
420 m_signature.Append(ELEMENT_TYPE_ARRAY);
421 m_signature.Append(rank);
422 }
423
424 SString* ToString(SString* pBuf, BOOL bAssemblySpec = FALSE, BOOL bSignature = FALSE, BOOL bGenericArguments = FALSE);
425
426private:
427 //----------------------------------------------------------------------------------------------------------------
428 // This is the "uber" GetType() that all public GetType() funnels through. It's main job is to figure out which
429 // Assembly to load the type from and then invoke GetTypeHaveAssembly.
430 //
431 // It's got a highly baroque interface partly for historical reasons and partly because it's the uber-function
432 // for all of the possible GetTypes.
433 //----------------------------------------------------------------------------------------------------------------
434 TypeHandle GetTypeWorker(
435 BOOL bThrowIfNotFound,
436 BOOL bIgnoreCase,
437 Assembly* pAssemblyGetType,
438
439 BOOL fEnableCASearchRules,
440
441 BOOL bProhibitAssemblyQualifiedName,
442
443 Assembly* pRequestingAssembly,
444 ICLRPrivBinder * pPrivHostBinder,
445 BOOL bLoadTypeFromPartialNameHack,
446 OBJECTREF *pKeepAlive);
447
448 //----------------------------------------------------------------------------------------------------------------
449 // These functions are the ones that actually loads the type once we've pinned down the Assembly it's in.
450 //----------------------------------------------------------------------------------------------------------------
451 TypeHandle GetTypeHaveAssembly(Assembly* pAssembly, BOOL bThrowIfNotFound, BOOL bIgnoreCase, OBJECTREF *pKeepAlive)
452 {
453 return GetTypeHaveAssemblyHelper(pAssembly, bThrowIfNotFound, bIgnoreCase, pKeepAlive, TRUE);
454 }
455 TypeHandle GetTypeHaveAssemblyHelper(Assembly* pAssembly, BOOL bThrowIfNotFound, BOOL bIgnoreCase, OBJECTREF *pKeepAlive, BOOL bRecurse);
456 SAFEHANDLE GetSafeHandle();
457
458private:
459 BOOL m_bIsGenericArgument;
460 DWORD m_count;
461 InlineSArray<DWORD, 128> m_signature;
462 InlineSArray<TypeName*, 16> m_genericArguments;
463 InlineSArray<SString*, 16> m_names;
464 InlineSString<128> m_assembly;
465 Factory<InlineSString<128> > m_nestNameFactory;
466};
467
468#endif
469