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.cpp |
6 | // --------------------------------------------------------------------------- |
7 | // |
8 | |
9 | // |
10 | |
11 | |
12 | #include "common.h" |
13 | #include "class.h" |
14 | #include "typehandle.h" |
15 | #include "sstring.h" |
16 | #include "typeparse.h" |
17 | #include "typestring.h" |
18 | #include "assemblynative.hpp" |
19 | #include "stackprobe.h" |
20 | #include "fstring.h" |
21 | |
22 | // |
23 | // TypeNameFactory |
24 | // |
25 | HRESULT STDMETHODCALLTYPE TypeNameFactory::QueryInterface(REFIID riid, void **ppUnk) |
26 | { |
27 | WRAPPER_NO_CONTRACT; |
28 | |
29 | *ppUnk = 0; |
30 | |
31 | if (riid == IID_IUnknown) |
32 | *ppUnk = (IUnknown *)this; |
33 | else if (riid == IID_ITypeNameFactory) |
34 | *ppUnk = (ITypeNameFactory*)this; |
35 | else |
36 | return (E_NOINTERFACE); |
37 | |
38 | AddRef(); |
39 | return S_OK; |
40 | } |
41 | |
42 | HRESULT TypeNameFactoryCreateObject(REFIID riid, void **ppUnk) |
43 | { |
44 | CONTRACTL |
45 | { |
46 | NOTHROW; |
47 | GC_NOTRIGGER; |
48 | } |
49 | CONTRACTL_END; |
50 | |
51 | HRESULT hr = S_OK; |
52 | |
53 | TypeNameFactory *pTypeNameFactory = new (nothrow) TypeNameFactory(); |
54 | |
55 | if (!pTypeNameFactory) |
56 | return (E_OUTOFMEMORY); |
57 | |
58 | hr = pTypeNameFactory->QueryInterface(riid, ppUnk); |
59 | |
60 | if (FAILED(hr)) |
61 | delete pTypeNameFactory; |
62 | |
63 | return hr; |
64 | } |
65 | |
66 | |
67 | HRESULT STDMETHODCALLTYPE TypeNameFactory::ParseTypeName(LPCWSTR szTypeName, DWORD* pError, ITypeName** ppTypeName) |
68 | { |
69 | CONTRACTL |
70 | { |
71 | SO_TOLERANT; |
72 | WRAPPER(THROWS); |
73 | }CONTRACTL_END; |
74 | |
75 | if (!ppTypeName || !pError) |
76 | return E_INVALIDARG; |
77 | |
78 | HRESULT hr = S_OK; |
79 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); |
80 | |
81 | *ppTypeName = NULL; |
82 | *pError = (DWORD)-1; |
83 | |
84 | ITypeName* pTypeName = new (nothrow) TypeName(szTypeName, pError); |
85 | |
86 | if (! pTypeName) |
87 | { |
88 | hr = E_OUTOFMEMORY; |
89 | } |
90 | else |
91 | { |
92 | pTypeName->AddRef(); |
93 | |
94 | if (*pError != (DWORD)-1) |
95 | { |
96 | pTypeName->Release(); |
97 | hr = S_FALSE; |
98 | } |
99 | else |
100 | { |
101 | *ppTypeName = pTypeName; |
102 | } |
103 | } |
104 | |
105 | END_SO_INTOLERANT_CODE; |
106 | |
107 | return hr; |
108 | } |
109 | |
110 | HRESULT STDMETHODCALLTYPE TypeNameFactory::GetTypeNameBuilder(ITypeNameBuilder** ppTypeNameBuilder) |
111 | { |
112 | CONTRACTL |
113 | { |
114 | THROWS; // operator new has EX_TRY/EX_CATCH or other contract transitions(s) |
115 | GC_NOTRIGGER; |
116 | MODE_ANY; |
117 | } |
118 | CONTRACTL_END; |
119 | |
120 | if (!ppTypeNameBuilder) |
121 | return E_INVALIDARG; |
122 | |
123 | *ppTypeNameBuilder = NULL; |
124 | |
125 | HRESULT hr = S_OK; |
126 | |
127 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); |
128 | |
129 | ITypeNameBuilder* pTypeNameBuilder = new (nothrow) TypeNameBuilderWrapper(); |
130 | |
131 | if (pTypeNameBuilder) |
132 | { |
133 | pTypeNameBuilder->AddRef(); |
134 | |
135 | *ppTypeNameBuilder = pTypeNameBuilder; |
136 | } |
137 | else |
138 | { |
139 | hr = E_OUTOFMEMORY; |
140 | } |
141 | |
142 | END_SO_INTOLERANT_CODE; |
143 | |
144 | return hr; |
145 | } |
146 | |
147 | // |
148 | // TypeName |
149 | // |
150 | SString* TypeName::ToString(SString* pBuf, BOOL bAssemblySpec, BOOL bSignature, BOOL bGenericArguments) |
151 | { |
152 | WRAPPER_NO_CONTRACT; |
153 | |
154 | PRECONDITION(!bGenericArguments & !bSignature &! bAssemblySpec); |
155 | |
156 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return pBuf); |
157 | { |
158 | TypeNameBuilder tnb(pBuf); |
159 | |
160 | for (COUNT_T i = 0; i < m_names.GetCount(); i ++) |
161 | tnb.AddName(m_names[i]->GetUnicode()); |
162 | } |
163 | END_SO_INTOLERANT_CODE; |
164 | |
165 | return pBuf; |
166 | } |
167 | |
168 | |
169 | DWORD STDMETHODCALLTYPE TypeName::AddRef() |
170 | { |
171 | LIMITED_METHOD_CONTRACT; |
172 | |
173 | m_count++; |
174 | |
175 | return m_count; |
176 | } |
177 | |
178 | DWORD STDMETHODCALLTYPE TypeName::Release() |
179 | { |
180 | CONTRACTL |
181 | { |
182 | THROWS; |
183 | GC_TRIGGERS; |
184 | SO_TOLERANT; |
185 | } |
186 | CONTRACTL_END; |
187 | VALIDATE_BACKOUT_STACK_CONSUMPTION; |
188 | |
189 | m_count--; |
190 | |
191 | DWORD dwCount = m_count; |
192 | if (dwCount == 0) |
193 | delete this; |
194 | |
195 | return dwCount; |
196 | } |
197 | |
198 | TypeName::~TypeName() |
199 | { |
200 | CONTRACTL |
201 | { |
202 | THROWS; |
203 | GC_TRIGGERS; |
204 | SO_TOLERANT; |
205 | } |
206 | CONTRACTL_END; |
207 | VALIDATE_BACKOUT_STACK_CONSUMPTION; |
208 | |
209 | for(COUNT_T i = 0; i < m_genericArguments.GetCount(); i ++) |
210 | m_genericArguments[i]->Release(); |
211 | } |
212 | |
213 | HRESULT STDMETHODCALLTYPE TypeName::QueryInterface(REFIID riid, void **ppUnk) |
214 | { |
215 | WRAPPER_NO_CONTRACT; |
216 | |
217 | *ppUnk = 0; |
218 | |
219 | if (riid == IID_IUnknown) |
220 | *ppUnk = (IUnknown *)this; |
221 | else if (riid == IID_ITypeName) |
222 | *ppUnk = (ITypeName*)this; |
223 | else |
224 | return (E_NOINTERFACE); |
225 | |
226 | AddRef(); |
227 | return S_OK; |
228 | } |
229 | |
230 | HRESULT STDMETHODCALLTYPE TypeName::GetNameCount(DWORD* pCount) |
231 | { |
232 | WRAPPER_NO_CONTRACT; |
233 | |
234 | if (!pCount) |
235 | return E_INVALIDARG; |
236 | |
237 | *pCount = m_names.GetCount(); |
238 | |
239 | return S_OK; |
240 | } |
241 | |
242 | HRESULT STDMETHODCALLTYPE TypeName::GetNames(DWORD count, BSTR* bszName, DWORD* pFetched) |
243 | { |
244 | CONTRACTL |
245 | { |
246 | SO_TOLERANT; |
247 | WRAPPER(THROWS); |
248 | }CONTRACTL_END; |
249 | |
250 | HRESULT hr = S_OK; |
251 | |
252 | if (!pFetched) |
253 | return E_INVALIDARG; |
254 | |
255 | *pFetched = m_names.GetCount(); |
256 | |
257 | if (m_names.GetCount() > count) |
258 | return S_FALSE; |
259 | |
260 | if (!bszName) |
261 | return E_INVALIDARG; |
262 | |
263 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); |
264 | { |
265 | for (COUNT_T i = 0; i < m_names.GetCount(); i ++) |
266 | bszName[i] = SysAllocString(m_names[i]->GetUnicode()); |
267 | } |
268 | END_SO_INTOLERANT_CODE; |
269 | |
270 | return hr; |
271 | } |
272 | |
273 | HRESULT STDMETHODCALLTYPE TypeName::GetTypeArgumentCount(DWORD* pCount) |
274 | { |
275 | WRAPPER_NO_CONTRACT; |
276 | |
277 | if (!pCount) |
278 | return E_INVALIDARG; |
279 | |
280 | *pCount = m_genericArguments.GetCount(); |
281 | |
282 | return S_OK; |
283 | } |
284 | |
285 | HRESULT STDMETHODCALLTYPE TypeName::GetTypeArguments(DWORD count, ITypeName** ppArguments, DWORD* pFetched) |
286 | { |
287 | WRAPPER_NO_CONTRACT; |
288 | |
289 | if (!pFetched) |
290 | return E_INVALIDARG; |
291 | |
292 | *pFetched = m_genericArguments.GetCount(); |
293 | |
294 | if (m_genericArguments.GetCount() > count) |
295 | return S_FALSE; |
296 | |
297 | if (!ppArguments) |
298 | return E_INVALIDARG; |
299 | |
300 | for (COUNT_T i = 0; i < m_genericArguments.GetCount(); i ++) |
301 | { |
302 | ppArguments[i] = m_genericArguments[i]; |
303 | m_genericArguments[i]->AddRef(); |
304 | } |
305 | |
306 | return S_OK; |
307 | } |
308 | |
309 | HRESULT STDMETHODCALLTYPE TypeName::GetModifierLength(DWORD* pCount) |
310 | { |
311 | WRAPPER_NO_CONTRACT; |
312 | |
313 | if (pCount == NULL) |
314 | return E_INVALIDARG; |
315 | |
316 | *pCount = m_signature.GetCount(); |
317 | |
318 | return S_OK; |
319 | } |
320 | |
321 | HRESULT STDMETHODCALLTYPE TypeName::GetModifiers(DWORD count, DWORD* pModifiers, DWORD* pFetched) |
322 | { |
323 | WRAPPER_NO_CONTRACT; |
324 | |
325 | if (!pFetched) |
326 | return E_INVALIDARG; |
327 | |
328 | *pFetched = m_signature.GetCount(); |
329 | |
330 | if (m_signature.GetCount() > count) |
331 | return S_FALSE; |
332 | |
333 | if (!pModifiers) |
334 | return E_INVALIDARG; |
335 | |
336 | for (COUNT_T i = 0; i < m_signature.GetCount(); i ++) |
337 | pModifiers[i] = m_signature[i]; |
338 | |
339 | return S_OK; |
340 | } |
341 | |
342 | HRESULT STDMETHODCALLTYPE TypeName::GetAssemblyName(BSTR* pszAssemblyName) |
343 | { |
344 | CONTRACTL |
345 | { |
346 | SO_TOLERANT; |
347 | WRAPPER(THROWS); |
348 | }CONTRACTL_END; |
349 | |
350 | HRESULT hr = S_OK; |
351 | |
352 | if (pszAssemblyName == NULL) |
353 | return E_INVALIDARG; |
354 | |
355 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); |
356 | { |
357 | *pszAssemblyName = SysAllocString(m_assembly.GetUnicode()); |
358 | } |
359 | END_SO_INTOLERANT_CODE; |
360 | |
361 | if (*pszAssemblyName == NULL) |
362 | hr= E_OUTOFMEMORY; |
363 | |
364 | return hr; |
365 | } |
366 | |
367 | #if!defined(CROSSGEN_COMPILE) |
368 | SAFEHANDLE TypeName::GetSafeHandle() |
369 | { |
370 | CONTRACTL |
371 | { |
372 | THROWS; |
373 | GC_TRIGGERS; |
374 | MODE_COOPERATIVE; |
375 | } |
376 | CONTRACTL_END; |
377 | |
378 | SAFEHANDLE objSafeHandle = NULL; |
379 | |
380 | GCPROTECT_BEGIN(objSafeHandle); |
381 | |
382 | objSafeHandle = (SAFEHANDLE)AllocateObject(MscorlibBinder::GetClass(CLASS__SAFE_TYPENAMEPARSER_HANDLE)); |
383 | CallDefaultConstructor(objSafeHandle); |
384 | |
385 | this->AddRef(); |
386 | objSafeHandle->SetHandle(this); |
387 | |
388 | GCPROTECT_END(); |
389 | |
390 | return objSafeHandle; |
391 | } |
392 | |
393 | /*static*/ |
394 | void QCALLTYPE TypeName::QCreateTypeNameParser(LPCWSTR wszTypeName, QCall::ObjectHandleOnStack pHandle, BOOL throwOnError) |
395 | { |
396 | QCALL_CONTRACT; |
397 | |
398 | BEGIN_QCALL; |
399 | |
400 | DWORD error = (DWORD)-1; |
401 | ReleaseHolder<TypeName> pTypeName = new TypeName(wszTypeName, &error); |
402 | pTypeName->AddRef(); |
403 | |
404 | if (error == (DWORD)-1) |
405 | { |
406 | GCX_COOP(); |
407 | pHandle.Set(pTypeName->GetSafeHandle()); |
408 | } |
409 | else |
410 | { |
411 | if (throwOnError) |
412 | { |
413 | StackSString buf; |
414 | StackSString msg(W("typeName@" )); |
415 | COUNT_T size = buf.GetUnicodeAllocation(); |
416 | _itow_s(error, buf.OpenUnicodeBuffer(size), size, /*radix*/10); |
417 | buf.CloseBuffer(); |
418 | msg.Append(buf); |
419 | COMPlusThrowArgumentException(msg.GetUnicode(), NULL); |
420 | } |
421 | } |
422 | |
423 | END_QCALL; |
424 | } |
425 | |
426 | /*static*/ |
427 | void QCALLTYPE TypeName::QReleaseTypeNameParser(TypeName * pTypeName) |
428 | { |
429 | CONTRACTL |
430 | { |
431 | QCALL_CHECK; |
432 | PRECONDITION(CheckPointer(pTypeName)); |
433 | } |
434 | CONTRACTL_END; |
435 | |
436 | BEGIN_QCALL; |
437 | |
438 | pTypeName->Release(); |
439 | |
440 | END_QCALL; |
441 | } |
442 | |
443 | /*static*/ |
444 | void QCALLTYPE TypeName::QGetNames(TypeName * pTypeName, QCall::ObjectHandleOnStack pNames) |
445 | { |
446 | CONTRACTL |
447 | { |
448 | QCALL_CHECK; |
449 | PRECONDITION(CheckPointer(pTypeName)); |
450 | } |
451 | CONTRACTL_END; |
452 | |
453 | BEGIN_QCALL; |
454 | |
455 | SArray<SString*> names = pTypeName->GetNames(); |
456 | COUNT_T count = names.GetCount(); |
457 | |
458 | GCX_COOP(); |
459 | |
460 | if (count > 0) |
461 | { |
462 | PTRARRAYREF pReturnNames = NULL; |
463 | |
464 | GCPROTECT_BEGIN(pReturnNames); |
465 | |
466 | pReturnNames = (PTRARRAYREF)AllocateObjectArray(count, g_pStringClass); |
467 | |
468 | for (COUNT_T i = 0; i < count; i++) |
469 | { |
470 | STRINGREF str = StringObject::NewString(names[i]->GetUnicode()); |
471 | pReturnNames->SetAt(i, str); |
472 | } |
473 | |
474 | pNames.Set(pReturnNames); |
475 | |
476 | GCPROTECT_END(); |
477 | } |
478 | else |
479 | { |
480 | pNames.Set(NULL); |
481 | } |
482 | |
483 | END_QCALL; |
484 | } |
485 | |
486 | /*static*/ |
487 | void QCALLTYPE TypeName::QGetTypeArguments(TypeName * pTypeName, QCall::ObjectHandleOnStack pTypeArguments) |
488 | { |
489 | CONTRACTL |
490 | { |
491 | QCALL_CHECK; |
492 | PRECONDITION(CheckPointer(pTypeName)); |
493 | } |
494 | CONTRACTL_END; |
495 | |
496 | BEGIN_QCALL; |
497 | |
498 | SArray<TypeName*> arguments = pTypeName->GetGenericArguments(); |
499 | COUNT_T count = arguments.GetCount(); |
500 | |
501 | GCX_COOP(); |
502 | |
503 | if (count > 0) |
504 | { |
505 | PTRARRAYREF pReturnArguments = NULL; |
506 | |
507 | GCPROTECT_BEGIN(pReturnArguments); |
508 | |
509 | pReturnArguments = (PTRARRAYREF)AllocateObjectArray(count, MscorlibBinder::GetClass(CLASS__SAFE_TYPENAMEPARSER_HANDLE)); |
510 | |
511 | for (COUNT_T i = 0; i < count; i++) |
512 | { |
513 | SAFEHANDLE handle = arguments[i]->GetSafeHandle(); |
514 | _ASSERTE(handle != NULL); |
515 | |
516 | pReturnArguments->SetAt(i, handle); |
517 | } |
518 | |
519 | pTypeArguments.Set(pReturnArguments); |
520 | |
521 | GCPROTECT_END(); |
522 | } |
523 | else |
524 | { |
525 | pTypeArguments.Set(NULL); |
526 | } |
527 | |
528 | END_QCALL; |
529 | } |
530 | |
531 | /*static*/ |
532 | void QCALLTYPE TypeName::QGetModifiers(TypeName * pTypeName, QCall::ObjectHandleOnStack pModifiers) |
533 | { |
534 | CONTRACTL |
535 | { |
536 | QCALL_CHECK; |
537 | PRECONDITION(CheckPointer(pTypeName)); |
538 | } |
539 | CONTRACTL_END; |
540 | |
541 | BEGIN_QCALL; |
542 | |
543 | SArray<DWORD> modifiers = pTypeName->GetSignature(); |
544 | COUNT_T count = modifiers.GetCount(); |
545 | |
546 | GCX_COOP(); |
547 | |
548 | if (count > 0) |
549 | { |
550 | I4ARRAYREF pReturnModifiers = NULL; |
551 | |
552 | GCPROTECT_BEGIN(pReturnModifiers); |
553 | |
554 | //TODO: how do we Get |
555 | pReturnModifiers = (I4ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_I4, count); |
556 | INT32 *pToArray = pReturnModifiers->GetDirectPointerToNonObjectElements(); |
557 | |
558 | for (COUNT_T i = 0; i < count; i++) |
559 | { |
560 | pToArray[i] = modifiers[i]; |
561 | } |
562 | |
563 | pModifiers.Set(pReturnModifiers); |
564 | |
565 | GCPROTECT_END(); |
566 | } |
567 | else |
568 | { |
569 | pModifiers.Set(NULL); |
570 | } |
571 | |
572 | END_QCALL; |
573 | } |
574 | |
575 | /*static*/ |
576 | void QCALLTYPE TypeName::QGetAssemblyName(TypeName * pTypeName, QCall::StringHandleOnStack pAssemblyName) |
577 | { |
578 | CONTRACTL |
579 | { |
580 | QCALL_CHECK; |
581 | PRECONDITION(CheckPointer(pTypeName)); |
582 | } |
583 | CONTRACTL_END; |
584 | |
585 | BEGIN_QCALL; |
586 | |
587 | pAssemblyName.Set(*(pTypeName->GetAssembly())); |
588 | |
589 | END_QCALL; |
590 | } |
591 | #endif//!CROSSGEN_COMPILE |
592 | |
593 | // |
594 | // TypeName::TypeNameParser |
595 | // |
596 | #undef IfFailGo |
597 | #define IfFailGo(P) if (!P) return FALSE; |
598 | |
599 | TypeName* TypeName::AddGenericArgument() |
600 | { |
601 | WRAPPER_NO_CONTRACT; |
602 | |
603 | TypeName* pGenArg = new TypeName(); |
604 | pGenArg->AddRef(); |
605 | |
606 | pGenArg->m_bIsGenericArgument = TRUE; |
607 | return m_genericArguments.AppendEx(pGenArg); |
608 | } |
609 | |
610 | TypeName::TypeNameParser::TypeNameTokens TypeName::TypeNameParser::LexAToken(BOOL ignorePlus) |
611 | { |
612 | LIMITED_METHOD_CONTRACT; |
613 | |
614 | if (m_nextToken == TypeNameIdentifier) |
615 | return TypeNamePostIdentifier; |
616 | |
617 | if (m_nextToken == TypeNameEnd) |
618 | return TypeNameEnd; |
619 | |
620 | if (*m_itr == W('\0')) |
621 | return TypeNameEnd; |
622 | |
623 | if (COMCharacter::nativeIsWhiteSpace(*m_itr)) |
624 | { |
625 | m_itr++; |
626 | return LexAToken(); |
627 | } |
628 | |
629 | WCHAR c = *m_itr; |
630 | m_itr++; |
631 | switch(c) |
632 | { |
633 | case W(','): return TypeNameComma; |
634 | case W('['): return TypeNameOpenSqBracket; |
635 | case W(']'): return TypeNameCloseSqBracket; |
636 | case W('&'): return TypeNameAmpersand; |
637 | case W('*'): return TypeNameAstrix; |
638 | case W('+'): if (!ignorePlus) return TypeNamePlus; |
639 | case W('\\'): |
640 | m_itr--; |
641 | return TypeNameIdentifier; |
642 | } |
643 | |
644 | ASSERT(!IsTypeNameReservedChar(c)); |
645 | |
646 | m_itr--; |
647 | return TypeNameIdentifier; |
648 | } |
649 | |
650 | BOOL TypeName::TypeNameParser::GetIdentifier(SString* sszId, TypeName::TypeNameParser::TypeNameIdentifiers identifierType) |
651 | { |
652 | CONTRACTL |
653 | { |
654 | THROWS; |
655 | GC_NOTRIGGER; |
656 | MODE_ANY; |
657 | } |
658 | CONTRACTL_END; |
659 | |
660 | PRECONDITION(m_currentToken == TypeNameIdentifier && m_nextToken == TypeNamePostIdentifier); |
661 | |
662 | sszId->Clear(); |
663 | |
664 | LPCWSTR start = m_currentItr; |
665 | InlineSArray<LPCWSTR, 32> m_escape; |
666 | |
667 | if (identifierType == TypeNameId) |
668 | { |
669 | do |
670 | { |
671 | switch (* m_currentItr ++) |
672 | { |
673 | case W(','): |
674 | case W('['): |
675 | case W(']'): |
676 | case W('&'): |
677 | case W('*'): |
678 | case W('+'): |
679 | case W('\0'): |
680 | goto done; |
681 | |
682 | case W('\\'): |
683 | m_escape.Append(m_currentItr - 1); |
684 | |
685 | if (! IsTypeNameReservedChar(*m_currentItr) || *m_currentItr == '\0') |
686 | return FALSE; |
687 | |
688 | m_currentItr++; |
689 | break; |
690 | |
691 | default: |
692 | break; |
693 | } |
694 | } |
695 | while(true); |
696 | |
697 | done: |
698 | m_currentItr--; |
699 | } |
700 | else if (identifierType == TypeNameFusionName) |
701 | { |
702 | while(*m_currentItr != W('\0')) |
703 | m_currentItr++; |
704 | } |
705 | else if (identifierType == TypeNameEmbeddedFusionName) |
706 | { |
707 | for (; (*m_currentItr != W('\0')) && (*m_currentItr != W(']')); m_currentItr++) |
708 | { |
709 | if (*m_currentItr == W('\\')) |
710 | { |
711 | if (*(m_currentItr + 1) == W(']')) |
712 | { |
713 | m_escape.Append(m_currentItr); |
714 | m_currentItr ++; |
715 | continue; |
716 | } |
717 | } |
718 | |
719 | if (*m_currentItr == '\0') |
720 | return FALSE; |
721 | } |
722 | if (*m_currentItr == W('\0')) |
723 | { |
724 | return FALSE; |
725 | } |
726 | } |
727 | else |
728 | return FALSE; |
729 | |
730 | sszId->Set(start, (COUNT_T)(m_currentItr - start)); |
731 | |
732 | for (SCOUNT_T i = m_escape.GetCount() - 1; i >= 0; i--) |
733 | sszId->Delete(sszId->Begin() + (SCOUNT_T)(m_escape[i] - start), 1); |
734 | |
735 | m_itr = m_currentItr; |
736 | m_nextToken = LexAToken(); |
737 | return TRUE; |
738 | } |
739 | |
740 | BOOL TypeName::TypeNameParser::START() |
741 | { |
742 | WRAPPER_NO_CONTRACT; |
743 | |
744 | NextToken(); |
745 | NextToken(); |
746 | return AQN(); |
747 | } |
748 | |
749 | // FULLNAME ',' ASSEMSPEC |
750 | // FULLNAME |
751 | // /* empty */ |
752 | BOOL TypeName::TypeNameParser::AQN() |
753 | { |
754 | CONTRACTL |
755 | { |
756 | THROWS; |
757 | GC_NOTRIGGER; |
758 | MODE_ANY; |
759 | } |
760 | CONTRACTL_END; |
761 | IfFailGo(TokenIs(TypeNameAQN)); |
762 | |
763 | if (TokenIs(TypeNameEnd)) |
764 | return TRUE; |
765 | |
766 | IfFailGo(FULLNAME()); |
767 | |
768 | if (TokenIs(TypeNameComma)) |
769 | { |
770 | NextToken(); |
771 | IfFailGo(ASSEMSPEC()); |
772 | } |
773 | |
774 | IfFailGo(TokenIs(TypeNameEnd)); |
775 | |
776 | return TRUE; |
777 | } |
778 | |
779 | // fusionName |
780 | BOOL TypeName::TypeNameParser::ASSEMSPEC() |
781 | { |
782 | WRAPPER_NO_CONTRACT; |
783 | IfFailGo(TokenIs(TypeNameASSEMSPEC)); |
784 | |
785 | GetIdentifier(m_pTypeName->GetAssembly(), TypeNameFusionName); |
786 | |
787 | NextToken(); |
788 | |
789 | return TRUE; |
790 | } |
791 | |
792 | // NAME GENPARAMS QUALIFIER |
793 | BOOL TypeName::TypeNameParser::FULLNAME() |
794 | { |
795 | WRAPPER_NO_CONTRACT; |
796 | IfFailGo(TokenIs(TypeNameFULLNAME)); |
797 | IfFailGo(NAME()); |
798 | |
799 | IfFailGo(GENPARAMS()); |
800 | |
801 | IfFailGo(QUALIFIER()); |
802 | |
803 | return TRUE; |
804 | } |
805 | |
806 | // *empty* |
807 | // '[' GENARGS ']' |
808 | BOOL TypeName::TypeNameParser::GENPARAMS() |
809 | { |
810 | CONTRACTL |
811 | { |
812 | THROWS; |
813 | GC_NOTRIGGER; |
814 | MODE_ANY; |
815 | } |
816 | CONTRACTL_END; |
817 | |
818 | if (!TokenIs(TypeNameGENPARAM)) |
819 | return TRUE; |
820 | |
821 | if (!NextTokenIs(TypeNameGENARGS)) |
822 | return TRUE; |
823 | |
824 | NextToken(); |
825 | IfFailGo(GENARGS()); |
826 | |
827 | IfFailGo(TokenIs(TypeNameCloseSqBracket)); |
828 | NextToken(); |
829 | |
830 | return TRUE; |
831 | } |
832 | |
833 | // GENARG |
834 | // GENARG ',' GENARGS |
835 | BOOL TypeName::TypeNameParser::GENARGS() |
836 | { |
837 | CONTRACTL |
838 | { |
839 | THROWS; |
840 | GC_NOTRIGGER; |
841 | MODE_ANY; |
842 | } |
843 | CONTRACTL_END; |
844 | IfFailGo(TokenIs(TypeNameGENARGS)); |
845 | |
846 | IfFailGo(GENARG()); |
847 | |
848 | if (TokenIs(TypeNameComma)) |
849 | { |
850 | NextToken(); |
851 | IfFailGo(GENARGS()); |
852 | } |
853 | |
854 | return TRUE; |
855 | } |
856 | |
857 | // '[' EAQN ']' |
858 | // FULLNAME |
859 | BOOL TypeName::TypeNameParser::GENARG() |
860 | { |
861 | CONTRACTL |
862 | { |
863 | THROWS; |
864 | GC_NOTRIGGER; |
865 | MODE_ANY; |
866 | } |
867 | CONTRACTL_END; |
868 | IfFailGo(TokenIs(TypeNameGENARG)); |
869 | |
870 | TypeName* pEnclosingTypeName = m_pTypeName; |
871 | m_pTypeName = m_pTypeName->AddGenericArgument(); |
872 | { |
873 | if (TokenIs(TypeNameOpenSqBracket)) |
874 | { |
875 | NextToken(); |
876 | IfFailGo(EAQN()); |
877 | |
878 | IfFailGo(TokenIs(TypeNameCloseSqBracket)); |
879 | NextToken(); |
880 | } |
881 | else |
882 | { |
883 | IfFailGo(FULLNAME()); |
884 | } |
885 | } |
886 | m_pTypeName = pEnclosingTypeName; |
887 | |
888 | return TRUE; |
889 | } |
890 | |
891 | // FULLNAME ',' EASSEMSPEC |
892 | // FULLNAME |
893 | BOOL TypeName::TypeNameParser::EAQN() |
894 | { |
895 | CONTRACTL |
896 | { |
897 | THROWS; |
898 | GC_NOTRIGGER; |
899 | MODE_ANY; |
900 | } |
901 | CONTRACTL_END; |
902 | IfFailGo(TokenIs(TypeNameEAQN)); |
903 | |
904 | IfFailGo(FULLNAME()); |
905 | |
906 | if (TokenIs(TypeNameComma)) |
907 | { |
908 | NextToken(); |
909 | IfFailGo(EASSEMSPEC()); |
910 | } |
911 | |
912 | return TRUE; |
913 | } |
914 | |
915 | // embeddedFusionName |
916 | BOOL TypeName::TypeNameParser::EASSEMSPEC() |
917 | { |
918 | WRAPPER_NO_CONTRACT; |
919 | IfFailGo(TokenIs(TypeNameEASSEMSPEC)); |
920 | |
921 | GetIdentifier(m_pTypeName->GetAssembly(), TypeNameEmbeddedFusionName); |
922 | |
923 | NextToken(); |
924 | |
925 | return TRUE; |
926 | } |
927 | |
928 | // *empty* |
929 | // '&' |
930 | // '*' QUALIFIER |
931 | // ARRAY QUALIFIER |
932 | BOOL TypeName::TypeNameParser::QUALIFIER() |
933 | { |
934 | CONTRACTL |
935 | { |
936 | THROWS; |
937 | GC_NOTRIGGER; |
938 | MODE_ANY; |
939 | } |
940 | CONTRACTL_END; |
941 | |
942 | if (!TokenIs(TypeNameQUALIFIER)) |
943 | return TRUE; |
944 | |
945 | if (TokenIs(TypeNameAmpersand)) |
946 | { |
947 | m_pTypeName->SetByRef(); |
948 | |
949 | NextToken(); |
950 | } |
951 | else if (TokenIs(TypeNameAstrix)) |
952 | { |
953 | m_pTypeName->SetPointer(); |
954 | |
955 | NextToken(); |
956 | IfFailGo(QUALIFIER()); |
957 | } |
958 | else |
959 | { |
960 | IfFailGo(ARRAY()); |
961 | IfFailGo(QUALIFIER()); |
962 | } |
963 | |
964 | return TRUE; |
965 | } |
966 | |
967 | // '[' RANK ']' |
968 | // '[' '*' ']' |
969 | BOOL TypeName::TypeNameParser::ARRAY() |
970 | { |
971 | CONTRACTL |
972 | { |
973 | THROWS; |
974 | GC_NOTRIGGER; |
975 | MODE_ANY; |
976 | } |
977 | CONTRACTL_END; |
978 | IfFailGo(TokenIs(TypeNameARRAY)); |
979 | |
980 | NextToken(); |
981 | |
982 | if (TokenIs(TypeNameAstrix)) |
983 | { |
984 | m_pTypeName->SetArray(1); |
985 | |
986 | NextToken(); |
987 | } |
988 | else |
989 | { |
990 | DWORD dwRank = 1; |
991 | IfFailGo(RANK(&dwRank)); |
992 | |
993 | if (dwRank == 1) |
994 | m_pTypeName->SetSzArray(); |
995 | else |
996 | m_pTypeName->SetArray(dwRank); |
997 | } |
998 | |
999 | IfFailGo(TokenIs(TypeNameCloseSqBracket)); |
1000 | NextToken(); |
1001 | |
1002 | return TRUE; |
1003 | } |
1004 | |
1005 | // *empty* |
1006 | // ',' RANK |
1007 | BOOL TypeName::TypeNameParser::RANK(DWORD* pdwRank) |
1008 | { |
1009 | WRAPPER_NO_CONTRACT; |
1010 | |
1011 | if (!TokenIs(TypeNameRANK)) |
1012 | return TRUE; |
1013 | |
1014 | NextToken(); |
1015 | *pdwRank = *pdwRank + 1; |
1016 | IfFailGo(RANK(pdwRank)); |
1017 | |
1018 | return TRUE; |
1019 | } |
1020 | |
1021 | // id |
1022 | // id '+' NESTNAME |
1023 | BOOL TypeName::TypeNameParser::NAME() |
1024 | { |
1025 | CONTRACTL |
1026 | { |
1027 | THROWS; |
1028 | GC_NOTRIGGER; |
1029 | MODE_ANY; |
1030 | } |
1031 | CONTRACTL_END; |
1032 | IfFailGo(TokenIs(TypeNameNAME)); |
1033 | |
1034 | GetIdentifier(m_pTypeName->AddName(), TypeNameId); |
1035 | |
1036 | NextToken(); |
1037 | |
1038 | if (TokenIs(TypeNamePlus)) |
1039 | { |
1040 | NextToken(); |
1041 | IfFailGo(NESTNAME()); |
1042 | } |
1043 | |
1044 | return TRUE; |
1045 | } |
1046 | |
1047 | // id |
1048 | // id '+' NESTNAME |
1049 | BOOL TypeName::TypeNameParser::NESTNAME() |
1050 | { |
1051 | WRAPPER_NO_CONTRACT; |
1052 | IfFailGo(TokenIs(TypeNameNESTNAME)); |
1053 | |
1054 | GetIdentifier(m_pTypeName->AddName(), TypeNameId); |
1055 | |
1056 | NextToken(); |
1057 | if (TokenIs(TypeNamePlus)) |
1058 | { |
1059 | NextToken(); |
1060 | IfFailGo(NESTNAME()); |
1061 | } |
1062 | |
1063 | return TRUE; |
1064 | } |
1065 | |
1066 | //-------------------------------------------------------------------------------------------------------------- |
1067 | // This version is used for resolving types named in custom attributes such as those used |
1068 | // for interop. Thus, it follows a well-known multistage set of rules for determining which |
1069 | // assembly the type is in. It will also enforce that the requesting assembly has access |
1070 | // rights to the type being loaded. |
1071 | // |
1072 | // The search logic is: |
1073 | // |
1074 | // if szTypeName is ASM-qualified, only that assembly will be searched. |
1075 | // if szTypeName is not ASM-qualified, we will search for the types in the following order: |
1076 | // - in pRequestingAssembly (if not NULL). pRequestingAssembly is the assembly that contained |
1077 | // the custom attribute from which the typename was derived. |
1078 | // - in mscorlib.dll |
1079 | // - raise an AssemblyResolveEvent() in the current appdomain |
1080 | // |
1081 | // pRequestingAssembly may be NULL. In that case, the "visibility" check will simply check that |
1082 | // the loaded type has public access. |
1083 | //-------------------------------------------------------------------------------------------------------------- |
1084 | /* public static */ |
1085 | TypeHandle TypeName::GetTypeUsingCASearchRules(LPCUTF8 szTypeName, Assembly *pRequestingAssembly, BOOL *pfNameIsAsmQualified/* = NULL*/, BOOL bDoVisibilityChecks/* = TRUE*/) |
1086 | { |
1087 | STATIC_CONTRACT_THROWS; |
1088 | STATIC_CONTRACT_GC_TRIGGERS; |
1089 | STATIC_CONTRACT_FAULT; |
1090 | |
1091 | StackSString sszAssemblyQualifiedName(SString::Utf8, szTypeName); |
1092 | return GetTypeUsingCASearchRules(sszAssemblyQualifiedName.GetUnicode(), pRequestingAssembly, pfNameIsAsmQualified, bDoVisibilityChecks); |
1093 | } |
1094 | |
1095 | TypeHandle TypeName::GetTypeUsingCASearchRules(LPCWSTR szTypeName, Assembly *pRequestingAssembly, BOOL *pfNameIsAsmQualified/* = NULL*/, BOOL bDoVisibilityChecks/* = TRUE*/) |
1096 | { |
1097 | STATIC_CONTRACT_THROWS; |
1098 | STATIC_CONTRACT_GC_TRIGGERS; |
1099 | STATIC_CONTRACT_FAULT; |
1100 | |
1101 | DWORD error = (DWORD)-1; |
1102 | |
1103 | GCX_COOP(); |
1104 | OBJECTREF keepAlive = NULL; |
1105 | TypeHandle th = TypeHandle(); |
1106 | |
1107 | GCPROTECT_BEGIN(keepAlive); |
1108 | |
1109 | #ifdef __GNUC__ |
1110 | // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack |
1111 | // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit |
1112 | // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits |
1113 | // since we don't have the same constraints. |
1114 | NewHolder<TypeName> pTypeName = new TypeName(szTypeName, &error); |
1115 | #else // __GNUC__ |
1116 | TypeName typeName(szTypeName, &error); |
1117 | TypeName *pTypeName = &typeName; |
1118 | #endif // __GNUC__ |
1119 | |
1120 | if (error != (DWORD)-1) |
1121 | { |
1122 | StackSString buf; |
1123 | StackSString msg(W("typeName@" )); |
1124 | COUNT_T size = buf.GetUnicodeAllocation(); |
1125 | _itow_s(error,buf.OpenUnicodeBuffer(size),size,10); |
1126 | buf.CloseBuffer(); |
1127 | msg.Append(buf); |
1128 | COMPlusThrowArgumentException(msg.GetUnicode(), NULL); |
1129 | } |
1130 | |
1131 | if (pfNameIsAsmQualified) |
1132 | { |
1133 | *pfNameIsAsmQualified = TRUE; |
1134 | if (pTypeName->GetAssembly()->IsEmpty()) |
1135 | *pfNameIsAsmQualified = FALSE; |
1136 | } |
1137 | |
1138 | th = pTypeName->GetTypeWorker( |
1139 | /*bThrowIfNotFound = */ TRUE, |
1140 | /*bIgnoreCase = */ FALSE, |
1141 | /*pAssemblyGetType =*/ NULL, |
1142 | /*fEnableCASearchRules = */ TRUE, |
1143 | /*fProhibitAsmQualifiedName = */ FALSE, |
1144 | pRequestingAssembly, |
1145 | nullptr, |
1146 | FALSE, |
1147 | &keepAlive); |
1148 | |
1149 | ASSERT(!th.IsNull()); |
1150 | LoaderAllocator *pLoaderAllocator = th.GetLoaderAllocator(); |
1151 | |
1152 | if (pLoaderAllocator->IsCollectible()) |
1153 | { |
1154 | if ((pRequestingAssembly == NULL) || !pRequestingAssembly->GetLoaderAllocator()->IsCollectible()) |
1155 | { |
1156 | COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible" )); |
1157 | } |
1158 | else |
1159 | { |
1160 | pRequestingAssembly->GetLoaderAllocator()->EnsureReference(pLoaderAllocator); |
1161 | } |
1162 | } |
1163 | |
1164 | GCPROTECT_END(); |
1165 | return th; |
1166 | } |
1167 | |
1168 | |
1169 | |
1170 | |
1171 | |
1172 | |
1173 | //-------------------------------------------------------------------------------------------------------------- |
1174 | // This everything-but-the-kitchen-sink version is what used to be called "GetType()". It exposes all the |
1175 | // funky knobs needed for implementing the specific requirements of the managed Type.GetType() apis and friends. |
1176 | //-------------------------------------------------------------------------------------------------------------- |
1177 | /*public static */ TypeHandle TypeName::GetTypeManaged( |
1178 | LPCWSTR szTypeName, |
1179 | DomainAssembly* pAssemblyGetType, |
1180 | BOOL bThrowIfNotFound, |
1181 | BOOL bIgnoreCase, |
1182 | BOOL bProhibitAsmQualifiedName, |
1183 | Assembly* pRequestingAssembly, |
1184 | BOOL bLoadTypeFromPartialNameHack, |
1185 | OBJECTREF *pKeepAlive, |
1186 | ICLRPrivBinder * pPrivHostBinder) |
1187 | { |
1188 | STANDARD_VM_CONTRACT; |
1189 | |
1190 | if (!*szTypeName) |
1191 | COMPlusThrow(kArgumentException, W("Format_StringZeroLength" )); |
1192 | |
1193 | DWORD error = (DWORD)-1; |
1194 | |
1195 | /* Partial name workaround loading must not load a collectible type */ |
1196 | if (bLoadTypeFromPartialNameHack) |
1197 | pKeepAlive = NULL; |
1198 | |
1199 | #ifdef __GNUC__ |
1200 | // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack |
1201 | // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit |
1202 | // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits |
1203 | // since we don't have the same constraints. |
1204 | NewHolder<TypeName> pTypeName = new TypeName(szTypeName, &error); |
1205 | #else // __GNUC__ |
1206 | TypeName typeName(szTypeName, &error); |
1207 | TypeName *pTypeName = &typeName; |
1208 | #endif // __GNUC__ |
1209 | |
1210 | if (error != (DWORD)-1) |
1211 | { |
1212 | if (!bThrowIfNotFound) |
1213 | return TypeHandle(); |
1214 | |
1215 | StackSString buf; |
1216 | StackSString msg(W("typeName@" )); |
1217 | COUNT_T size = buf.GetUnicodeAllocation(); |
1218 | _itow_s(error, buf.OpenUnicodeBuffer(size), size, /*radix*/10); |
1219 | buf.CloseBuffer(); |
1220 | msg.Append(buf); |
1221 | COMPlusThrowArgumentException(msg.GetUnicode(), NULL); |
1222 | } |
1223 | |
1224 | BOOL bPeriodPrefix = szTypeName[0] == W('.'); |
1225 | |
1226 | TypeHandle result = pTypeName->GetTypeWorker( |
1227 | bPeriodPrefix ? FALSE : bThrowIfNotFound, |
1228 | bIgnoreCase, |
1229 | pAssemblyGetType ? pAssemblyGetType->GetAssembly() : NULL, |
1230 | /*fEnableCASearchRules = */TRUE, |
1231 | bProhibitAsmQualifiedName, |
1232 | pRequestingAssembly, |
1233 | pPrivHostBinder, |
1234 | bLoadTypeFromPartialNameHack, |
1235 | pKeepAlive); |
1236 | |
1237 | if (bPeriodPrefix && result.IsNull()) |
1238 | { |
1239 | new (pTypeName) TypeName(szTypeName + 1, &error); |
1240 | |
1241 | if (error != (DWORD)-1) |
1242 | { |
1243 | if (!bThrowIfNotFound) |
1244 | return TypeHandle(); |
1245 | |
1246 | StackSString buf; |
1247 | StackSString msg(W("typeName@" )); |
1248 | COUNT_T size = buf.GetUnicodeAllocation(); |
1249 | _itow_s(error-1,buf.OpenUnicodeBuffer(size),size,10); |
1250 | buf.CloseBuffer(); |
1251 | msg.Append(buf); |
1252 | COMPlusThrowArgumentException(msg.GetUnicode(), NULL); |
1253 | } |
1254 | |
1255 | result = pTypeName->GetTypeWorker( |
1256 | bThrowIfNotFound, |
1257 | bIgnoreCase, |
1258 | pAssemblyGetType ? pAssemblyGetType->GetAssembly() : NULL, |
1259 | /*fEnableCASearchRules = */TRUE, |
1260 | bProhibitAsmQualifiedName, |
1261 | pRequestingAssembly, |
1262 | pPrivHostBinder, |
1263 | bLoadTypeFromPartialNameHack, |
1264 | pKeepAlive); |
1265 | } |
1266 | |
1267 | return result; |
1268 | } |
1269 | |
1270 | |
1271 | |
1272 | |
1273 | //------------------------------------------------------------------------------------------- |
1274 | // Retrieves a type from an assembly. It requires the caller to know which assembly |
1275 | // the type is in. |
1276 | //------------------------------------------------------------------------------------------- |
1277 | /* public static */ TypeHandle TypeName::GetTypeFromAssembly(LPCWSTR szTypeName, Assembly *pAssembly, BOOL bThrowIfNotFound /*= TRUE*/) |
1278 | { |
1279 | STATIC_CONTRACT_THROWS; |
1280 | STATIC_CONTRACT_GC_TRIGGERS; |
1281 | STATIC_CONTRACT_FAULT; |
1282 | |
1283 | _ASSERTE(szTypeName != NULL); |
1284 | _ASSERTE(pAssembly != NULL); |
1285 | |
1286 | if (!*szTypeName) |
1287 | COMPlusThrow(kArgumentException, W("Format_StringZeroLength" )); |
1288 | |
1289 | DWORD error = (DWORD)-1; |
1290 | |
1291 | #ifdef __GNUC__ |
1292 | // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack |
1293 | // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit |
1294 | // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits |
1295 | // since we don't have the same constraints. |
1296 | NewHolder<TypeName> pTypeName = new TypeName(szTypeName, &error); |
1297 | #else // __GNUC__ |
1298 | TypeName typeName(szTypeName, &error); |
1299 | TypeName *pTypeName = &typeName; |
1300 | #endif // __GNUC__ |
1301 | |
1302 | if (error != (DWORD)-1) |
1303 | { |
1304 | StackSString buf; |
1305 | StackSString msg(W("typeName@" )); |
1306 | COUNT_T size = buf.GetUnicodeAllocation(); |
1307 | _itow_s(error,buf.OpenUnicodeBuffer(size),size,10); |
1308 | buf.CloseBuffer(); |
1309 | msg.Append(buf); |
1310 | COMPlusThrowArgumentException(msg.GetUnicode(), NULL); |
1311 | } |
1312 | |
1313 | // Because the typename can come from untrusted input, we will throw an exception rather than assert. |
1314 | // (This also assures that the shipping build does the right thing.) |
1315 | if (!(pTypeName->GetAssembly()->IsEmpty())) |
1316 | { |
1317 | COMPlusThrow(kArgumentException, IDS_EE_CANNOT_HAVE_ASSEMBLY_SPEC); |
1318 | } |
1319 | |
1320 | return pTypeName->GetTypeWorker(bThrowIfNotFound, /*bIgnoreCase = */FALSE, pAssembly, /*fEnableCASearchRules = */FALSE, FALSE, NULL, |
1321 | nullptr, // pPrivHostBinder |
1322 | FALSE, NULL /* cannot find a collectible type unless it is in assembly */); |
1323 | } |
1324 | |
1325 | //------------------------------------------------------------------------------------------- |
1326 | // Retrieves a type. Will assert if the name is not fully qualified. |
1327 | //------------------------------------------------------------------------------------------- |
1328 | /* public static */ TypeHandle TypeName::GetTypeFromAsmQualifiedName(LPCWSTR szFullyQualifiedName) |
1329 | { |
1330 | STATIC_CONTRACT_THROWS; |
1331 | STATIC_CONTRACT_GC_TRIGGERS; |
1332 | STATIC_CONTRACT_FAULT; |
1333 | |
1334 | _ASSERTE(szFullyQualifiedName != NULL); |
1335 | |
1336 | if (!*szFullyQualifiedName) |
1337 | COMPlusThrow(kArgumentException, W("Format_StringZeroLength" )); |
1338 | |
1339 | DWORD error = (DWORD)-1; |
1340 | |
1341 | #ifdef __GNUC__ |
1342 | // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack |
1343 | // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit |
1344 | // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits |
1345 | // since we don't have the same constraints. |
1346 | NewHolder<TypeName> pTypeName = new TypeName(szFullyQualifiedName, &error); |
1347 | #else // __GNUC__ |
1348 | TypeName typeName(szFullyQualifiedName, &error); |
1349 | TypeName *pTypeName = &typeName; |
1350 | #endif // __GNUC__ |
1351 | |
1352 | if (error != (DWORD)-1) |
1353 | { |
1354 | StackSString buf; |
1355 | StackSString msg(W("typeName@" )); |
1356 | COUNT_T size = buf.GetUnicodeAllocation(); |
1357 | _itow_s(error,buf.OpenUnicodeBuffer(size),size,10); |
1358 | buf.CloseBuffer(); |
1359 | msg.Append(buf); |
1360 | COMPlusThrowArgumentException(msg.GetUnicode(), NULL); |
1361 | } |
1362 | |
1363 | return pTypeName->GetTypeFromAsm(); |
1364 | } |
1365 | |
1366 | |
1367 | TypeHandle TypeName::GetTypeFromAsm() |
1368 | { |
1369 | STATIC_CONTRACT_THROWS; |
1370 | STATIC_CONTRACT_GC_TRIGGERS; |
1371 | STATIC_CONTRACT_FAULT; |
1372 | |
1373 | // Because the typename can come from untrusted input, we will throw an exception rather than assert. |
1374 | // (This also assures that the shipping build does the right thing.) |
1375 | if (this->GetAssembly()->IsEmpty()) |
1376 | { |
1377 | COMPlusThrow(kArgumentException, IDS_EE_NEEDS_ASSEMBLY_SPEC); |
1378 | } |
1379 | |
1380 | return this->GetTypeWorker( |
1381 | /*bThrowIfNotFound =*/TRUE, |
1382 | /*bIgnoreCase = */FALSE, |
1383 | NULL, |
1384 | /*fEnableCASearchRules = */FALSE, |
1385 | FALSE, |
1386 | NULL, |
1387 | nullptr, // pPrivHostBinder |
1388 | FALSE, |
1389 | NULL /* cannot find a collectible type */); |
1390 | } |
1391 | |
1392 | |
1393 | |
1394 | // ------------------------------------------------------------------------------------------------------------- |
1395 | // This is the "uber" GetType() that all public GetType() funnels through. It's main job is to figure out which |
1396 | // Assembly to load the type from and then invoke GetTypeHaveAssembly. |
1397 | // |
1398 | // It's got a highly baroque interface partly for historical reasons and partly because it's the uber-function |
1399 | // for all of the possible GetTypes. |
1400 | // ------------------------------------------------------------------------------------------------------------- |
1401 | /* private instance */ TypeHandle TypeName::GetTypeWorker( |
1402 | BOOL bThrowIfNotFound, |
1403 | BOOL bIgnoreCase, |
1404 | Assembly* pAssemblyGetType, |
1405 | |
1406 | BOOL fEnableCASearchRules, |
1407 | BOOL bProhibitAsmQualifiedName, |
1408 | Assembly* pRequestingAssembly, |
1409 | ICLRPrivBinder * pPrivHostBinder, |
1410 | BOOL bLoadTypeFromPartialNameHack, |
1411 | OBJECTREF *pKeepAlive) |
1412 | { |
1413 | CONTRACT(TypeHandle) |
1414 | { |
1415 | THROWS; |
1416 | GC_TRIGGERS; |
1417 | MODE_ANY; |
1418 | POSTCONDITION(!(RETVAL.IsNull() && bThrowIfNotFound)); |
1419 | } |
1420 | CONTRACT_END |
1421 | |
1422 | GCX_COOP(); |
1423 | |
1424 | ASSEMBLYREF asmRef = NULL; |
1425 | TypeHandle th = TypeHandle(); |
1426 | GCPROTECT_BEGIN(asmRef); |
1427 | |
1428 | // We don't ever want to get anything related to a collectible type in here if we are not able to return one. |
1429 | ASSEMBLYREF *pAsmRef = &asmRef; |
1430 | if (pKeepAlive == NULL) |
1431 | pAsmRef = NULL; |
1432 | |
1433 | //requires a lot of space |
1434 | DECLARE_INTERIOR_STACK_PROBE; |
1435 | // This function is recursive, so it must have an interior probe |
1436 | if (bThrowIfNotFound) |
1437 | { |
1438 | DO_INTERIOR_STACK_PROBE_FOR_CHECK_THREAD(12); |
1439 | } |
1440 | else |
1441 | { |
1442 | DO_INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD(12, goto Exit;); |
1443 | } |
1444 | |
1445 | // An explicit assembly has been specified so look for the type there |
1446 | if (!GetAssembly()->IsEmpty()) |
1447 | { |
1448 | |
1449 | if (bProhibitAsmQualifiedName && !m_bIsGenericArgument) |
1450 | { |
1451 | if (bThrowIfNotFound) |
1452 | { |
1453 | COMPlusThrow(kArgumentException, IDS_EE_ASSEMBLY_GETTYPE_CANNONT_HAVE_ASSEMBLY_SPEC); |
1454 | } |
1455 | else |
1456 | { |
1457 | th = TypeHandle(); |
1458 | goto Exit; |
1459 | } |
1460 | } |
1461 | |
1462 | SString * pssOuterTypeName = NULL; |
1463 | if (GetNames().GetCount() > 0) |
1464 | { |
1465 | pssOuterTypeName = GetNames()[0]; |
1466 | } |
1467 | |
1468 | // We want to catch the exception if we're going to later try a partial bind. |
1469 | if (bLoadTypeFromPartialNameHack) |
1470 | { |
1471 | EX_TRY |
1472 | { |
1473 | DomainAssembly *pDomainAssembly = LoadDomainAssembly(GetAssembly(), pRequestingAssembly, |
1474 | pPrivHostBinder, |
1475 | bThrowIfNotFound, pssOuterTypeName); |
1476 | if (pDomainAssembly) |
1477 | { |
1478 | th = GetTypeHaveAssembly(pDomainAssembly->GetAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive); |
1479 | } |
1480 | } |
1481 | EX_CATCH |
1482 | { |
1483 | th = TypeHandle(); |
1484 | } |
1485 | EX_END_CATCH(RethrowTransientExceptions); |
1486 | } |
1487 | else |
1488 | { |
1489 | DomainAssembly *pDomainAssembly = LoadDomainAssembly(GetAssembly(), pRequestingAssembly, |
1490 | pPrivHostBinder, |
1491 | bThrowIfNotFound, pssOuterTypeName); |
1492 | if (pDomainAssembly) |
1493 | { |
1494 | th = GetTypeHaveAssembly(pDomainAssembly->GetAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive); |
1495 | } |
1496 | } |
1497 | } |
1498 | |
1499 | // There's no explicit assembly so look in the assembly specified by the original caller (Assembly.GetType) |
1500 | else if (pAssemblyGetType) |
1501 | { |
1502 | th = GetTypeHaveAssembly(pAssemblyGetType, bThrowIfNotFound, bIgnoreCase, pKeepAlive); |
1503 | } |
1504 | |
1505 | // Otherwise look in the caller's assembly then the system assembly |
1506 | else if (fEnableCASearchRules) |
1507 | { |
1508 | // Look for type in caller's assembly |
1509 | if (pRequestingAssembly) |
1510 | th = GetTypeHaveAssembly(pRequestingAssembly, bThrowIfNotFound, bIgnoreCase, pKeepAlive); |
1511 | |
1512 | // Look for type in system assembly |
1513 | if (th.IsNull()) |
1514 | { |
1515 | if (pRequestingAssembly != SystemDomain::SystemAssembly()) |
1516 | th = GetTypeHaveAssembly(SystemDomain::SystemAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive); |
1517 | } |
1518 | |
1519 | // Raise AssemblyResolveEvent to try to resolve assembly |
1520 | if (th.IsNull()) |
1521 | { |
1522 | AppDomain *pDomain = (AppDomain *)SystemDomain::GetCurrentDomain(); |
1523 | |
1524 | if ((BaseDomain*)pDomain != SystemDomain::System()) |
1525 | { |
1526 | TypeNameBuilder tnb; |
1527 | for (COUNT_T i = 0; i < GetNames().GetCount(); i ++) |
1528 | tnb.AddName(GetNames()[i]->GetUnicode()); |
1529 | |
1530 | StackScratchBuffer bufFullName; |
1531 | DomainAssembly* pDomainAssembly = pDomain->RaiseTypeResolveEventThrowing(pRequestingAssembly?pRequestingAssembly->GetDomainAssembly():NULL,tnb.GetString()->GetANSI(bufFullName), pAsmRef); |
1532 | if (pDomainAssembly) |
1533 | th = GetTypeHaveAssembly(pDomainAssembly->GetAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive); |
1534 | } |
1535 | } |
1536 | } |
1537 | else |
1538 | { |
1539 | _ASSERTE(!"You must pass either a asm-qualified typename or an actual Assembly." ); |
1540 | } |
1541 | |
1542 | |
1543 | if (!th.IsNull() && (!m_genericArguments.IsEmpty() || !m_signature.IsEmpty())) |
1544 | { |
1545 | #ifdef CROSSGEN_COMPILE |
1546 | // This method is used to parse type names in custom attributes. We do not support |
1547 | // that these custom attributes will contain composed types. |
1548 | CrossGenNotSupported("GetTypeWorker" ); |
1549 | #else |
1550 | struct _gc |
1551 | { |
1552 | PTRARRAYREF refGenericArguments; |
1553 | OBJECTREF keepAlive; |
1554 | REFLECTCLASSBASEREF refGenericArg; |
1555 | } gc; |
1556 | |
1557 | gc.refGenericArguments = NULL; |
1558 | gc.keepAlive = NULL; |
1559 | gc.refGenericArg = NULL; |
1560 | |
1561 | BOOL abortCall = FALSE; |
1562 | |
1563 | GCPROTECT_BEGIN(gc); |
1564 | INT32 cGenericArgs = m_genericArguments.GetCount(); |
1565 | |
1566 | if (cGenericArgs > 0) |
1567 | { |
1568 | TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY); |
1569 | gc.refGenericArguments = (PTRARRAYREF)AllocateArrayEx(arrayHandle, &cGenericArgs, 1); |
1570 | } |
1571 | // Instantiate generic arguments |
1572 | for (INT32 i = 0; i < cGenericArgs; i++) |
1573 | { |
1574 | TypeHandle thGenericArg = m_genericArguments[i]->GetTypeWorker( |
1575 | bThrowIfNotFound, bIgnoreCase, |
1576 | pAssemblyGetType, fEnableCASearchRules, bProhibitAsmQualifiedName, pRequestingAssembly, |
1577 | pPrivHostBinder, |
1578 | bLoadTypeFromPartialNameHack, |
1579 | (pKeepAlive != NULL) ? &gc.keepAlive : NULL /* Only pass a keepalive parameter if we were passed a keepalive parameter */); |
1580 | |
1581 | if (thGenericArg.IsNull()) |
1582 | { |
1583 | abortCall = TRUE; |
1584 | break; |
1585 | } |
1586 | |
1587 | gc.refGenericArg = (REFLECTCLASSBASEREF)thGenericArg.GetManagedClassObject(); |
1588 | |
1589 | gc.refGenericArguments->SetAt(i, gc.refGenericArg); |
1590 | } |
1591 | |
1592 | MethodDescCallSite getTypeHelper(METHOD__RT_TYPE_HANDLE__GET_TYPE_HELPER); |
1593 | |
1594 | ARG_SLOT args[5] = { |
1595 | (ARG_SLOT)OBJECTREFToObject(th.GetManagedClassObject()), |
1596 | (ARG_SLOT)OBJECTREFToObject(gc.refGenericArguments), |
1597 | (ARG_SLOT)(SIZE_T)m_signature.OpenRawBuffer(), |
1598 | m_signature.GetCount(), |
1599 | }; |
1600 | |
1601 | REFLECTCLASSBASEREF refType = NULL; |
1602 | |
1603 | if (!abortCall) |
1604 | refType = (REFLECTCLASSBASEREF)getTypeHelper.Call_RetOBJECTREF(args); |
1605 | |
1606 | if (refType != NULL) |
1607 | { |
1608 | th = refType->GetType(); |
1609 | if (pKeepAlive) |
1610 | *pKeepAlive = refType; |
1611 | } |
1612 | else |
1613 | { |
1614 | th = TypeHandle(); |
1615 | } |
1616 | GCPROTECT_END(); |
1617 | #endif // CROSSGEN_COMPILE |
1618 | } |
1619 | |
1620 | if (th.IsNull() && bThrowIfNotFound) |
1621 | { |
1622 | StackSString buf; |
1623 | LPCWSTR wszName = ToString(&buf)->GetUnicode(); |
1624 | MAKE_UTF8PTR_FROMWIDE(szName, wszName); |
1625 | |
1626 | if (GetAssembly() && !GetAssembly()->IsEmpty()) |
1627 | { |
1628 | ThrowTypeLoadException(NULL, szName, GetAssembly()->GetUnicode(), NULL, IDS_CLASSLOAD_GENERAL); |
1629 | } |
1630 | else if (pAssemblyGetType) |
1631 | { |
1632 | pAssemblyGetType->ThrowTypeLoadException(NULL, szName, IDS_CLASSLOAD_GENERAL); |
1633 | } |
1634 | else if (pRequestingAssembly) |
1635 | { |
1636 | pRequestingAssembly->ThrowTypeLoadException(NULL, szName, IDS_CLASSLOAD_GENERAL); |
1637 | } |
1638 | else |
1639 | { |
1640 | ThrowTypeLoadException(NULL, szName, NULL, NULL, IDS_CLASSLOAD_GENERAL); |
1641 | } |
1642 | } |
1643 | |
1644 | Exit: |
1645 | ; |
1646 | END_INTERIOR_STACK_PROBE; |
1647 | |
1648 | GCPROTECT_END(); |
1649 | |
1650 | RETURN th; |
1651 | } |
1652 | |
1653 | //---------------------------------------------------------------------------------------------------------------- |
1654 | // This is the one that actually loads the type once we've pinned down the Assembly it's in. |
1655 | //---------------------------------------------------------------------------------------------------------------- |
1656 | /* private */ |
1657 | TypeHandle |
1658 | TypeName::GetTypeHaveAssemblyHelper( |
1659 | Assembly * pAssembly, |
1660 | BOOL bThrowIfNotFound, |
1661 | BOOL bIgnoreCase, |
1662 | OBJECTREF * pKeepAlive, |
1663 | BOOL bRecurse) |
1664 | { |
1665 | WRAPPER_NO_CONTRACT; |
1666 | |
1667 | TypeHandle th = TypeHandle(); |
1668 | SArray<SString *> & names = GetNames(); |
1669 | Module * pManifestModule = pAssembly->GetManifestModule(); |
1670 | Module * pLookOnlyInModule = NULL; |
1671 | ClassLoader * pClassLoader = pAssembly->GetLoader(); |
1672 | |
1673 | NameHandle typeName(pManifestModule, mdtBaseType); |
1674 | |
1675 | #ifndef CROSSGEN_COMPILE |
1676 | if (pAssembly->IsCollectible()) |
1677 | { |
1678 | if (pKeepAlive == NULL) |
1679 | { |
1680 | COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleResolveFailure" )); |
1681 | } |
1682 | *pKeepAlive = pAssembly->GetLoaderAllocator()->GetExposedObject(); |
1683 | } |
1684 | #endif |
1685 | |
1686 | // Set up the name handle |
1687 | if (bIgnoreCase) |
1688 | typeName.SetCaseInsensitive(); |
1689 | |
1690 | EX_TRY |
1691 | { |
1692 | for (COUNT_T i = 0; i < names.GetCount(); i ++) |
1693 | { |
1694 | // each extra name represents one more level of nesting |
1695 | LPCWSTR wname = names[i]->GetUnicode(); |
1696 | |
1697 | MAKE_UTF8PTR_FROMWIDE(name, wname); |
1698 | typeName.SetName(name); |
1699 | |
1700 | // typeName.m_pBucket gets set here if the type is found |
1701 | // it will be used in the next iteration to look up the nested type |
1702 | th = pClassLoader->LoadTypeHandleThrowing(&typeName, CLASS_LOADED, pLookOnlyInModule); |
1703 | |
1704 | // DDB 117395: if we didn't find a type, don't bother looking for its nested type |
1705 | if (th.IsNull()) |
1706 | break; |
1707 | |
1708 | if (th.GetAssembly() != pAssembly) |
1709 | { // It is forwarded type |
1710 | |
1711 | // Use the found assembly class loader for potential nested types search |
1712 | // The nested type has to be in the same module as the nesting type, so it doesn't make |
1713 | // sense to follow the same chain of type forwarders again for the nested type |
1714 | pClassLoader = th.GetAssembly()->GetLoader(); |
1715 | } |
1716 | |
1717 | // Nested types must live in the module of the nesting type |
1718 | if ((i == 0) && (names.GetCount() > 1) && (pLookOnlyInModule == NULL)) |
1719 | { |
1720 | Module * pFoundModule = th.GetModule(); |
1721 | |
1722 | // Ensure that the bucket in the NameHandle is set to a valid bucket for all cases. |
1723 | |
1724 | // If the type is in the manifest module, it will always be set correctly, |
1725 | // or if the type is forwarded always lookup via the standard logic |
1726 | if ((pFoundModule == pManifestModule) || (pFoundModule->GetAssembly() != pAssembly)) |
1727 | continue; |
1728 | |
1729 | pLookOnlyInModule = pFoundModule; |
1730 | |
1731 | // If the type is not in the manifest module, and the nesting type is in the exported |
1732 | // types table of the manifest module, but the nested type is not, then unless the bucket |
1733 | // is from the actual defining module, then the LoadTypeHandleThrowing logic will fail. |
1734 | // To fix this, we must force the loader to record the bucket that refers to the nesting type |
1735 | // from within the defining module's available class table. |
1736 | |
1737 | // Re-run the LoadTypeHandleThrowing, but force it to only look in the class table for the module which |
1738 | // defines the type. This should cause typeName.m_pBucket to be set to the bucket |
1739 | // which corresponds to the type in the defining module, instead of potentially in the manifest module. |
1740 | i = -1; |
1741 | typeName.SetBucket(HashedTypeEntry()); |
1742 | } |
1743 | } |
1744 | |
1745 | if (th.IsNull() && bRecurse) |
1746 | { |
1747 | IMDInternalImport * pManifestImport = pManifestModule->GetMDImport(); |
1748 | HENUMInternalHolder phEnum(pManifestImport); |
1749 | phEnum.EnumInit(mdtFile, mdTokenNil); |
1750 | mdToken mdFile; |
1751 | |
1752 | while (pManifestImport->EnumNext(&phEnum, &mdFile)) |
1753 | { |
1754 | if (pManifestModule->LookupFile(mdFile)) |
1755 | continue; |
1756 | |
1757 | pManifestModule->LoadModule(GetAppDomain(), mdFile, FALSE); |
1758 | |
1759 | th = GetTypeHaveAssemblyHelper(pAssembly, bThrowIfNotFound, bIgnoreCase, NULL, FALSE); |
1760 | |
1761 | if (!th.IsNull()) |
1762 | break; |
1763 | } |
1764 | } |
1765 | } |
1766 | EX_CATCH |
1767 | { |
1768 | if (bThrowIfNotFound) |
1769 | EX_RETHROW; |
1770 | |
1771 | Exception * ex = GET_EXCEPTION(); |
1772 | |
1773 | // Let non-File-not-found exceptions propagate |
1774 | if (EEFileLoadException::GetFileLoadKind(ex->GetHR()) != kFileNotFoundException) |
1775 | EX_RETHROW; |
1776 | } |
1777 | EX_END_CATCH(RethrowTerminalExceptions); |
1778 | |
1779 | return th; |
1780 | } // TypeName::GetTypeHaveAssemblyHelper |
1781 | |
1782 | |
1783 | DomainAssembly * LoadDomainAssembly( |
1784 | SString * psszAssemblySpec, |
1785 | Assembly * pRequestingAssembly, |
1786 | ICLRPrivBinder * pPrivHostBinder, |
1787 | BOOL bThrowIfNotFound, |
1788 | SString * pssOuterTypeName) |
1789 | { |
1790 | CONTRACTL |
1791 | { |
1792 | MODE_ANY; |
1793 | THROWS; |
1794 | GC_TRIGGERS; |
1795 | INJECT_FAULT(COMPlusThrowOM();); |
1796 | } |
1797 | CONTRACTL_END; |
1798 | AssemblySpec spec; |
1799 | DomainAssembly *pDomainAssembly = NULL; |
1800 | |
1801 | StackScratchBuffer buffer; |
1802 | LPCUTF8 szAssemblySpec = psszAssemblySpec->GetUTF8(buffer); |
1803 | IfFailThrow(spec.Init(szAssemblySpec)); |
1804 | |
1805 | if (spec.IsContentType_WindowsRuntime()) |
1806 | { |
1807 | _ASSERTE(pssOuterTypeName != NULL); |
1808 | spec.SetWindowsRuntimeType(*pssOuterTypeName); |
1809 | } |
1810 | |
1811 | if (pPrivHostBinder) |
1812 | { |
1813 | spec.SetHostBinder(pPrivHostBinder); |
1814 | } |
1815 | else if (pRequestingAssembly && (!pRequestingAssembly->IsCollectible())) |
1816 | { |
1817 | GCX_PREEMP(); |
1818 | spec.SetParentAssembly(pRequestingAssembly->GetDomainAssembly()); |
1819 | } |
1820 | |
1821 | // If the requesting assembly has Fallback LoadContext binder available, |
1822 | // then set it up in the AssemblySpec. |
1823 | if (pRequestingAssembly != NULL) |
1824 | { |
1825 | PEFile *pRequestingAssemblyManifestFile = pRequestingAssembly->GetManifestFile(); |
1826 | spec.SetFallbackLoadContextBinderForRequestingAssembly(pRequestingAssemblyManifestFile->GetFallbackLoadContextBinder()); |
1827 | } |
1828 | |
1829 | if (bThrowIfNotFound) |
1830 | { |
1831 | pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED); |
1832 | } |
1833 | else |
1834 | { |
1835 | EX_TRY |
1836 | { |
1837 | pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED, bThrowIfNotFound); |
1838 | } |
1839 | EX_CATCH |
1840 | { |
1841 | Exception *ex = GET_EXCEPTION(); |
1842 | |
1843 | // Let non-File-not-found exceptions propagate |
1844 | if (EEFileLoadException::GetFileLoadKind(ex->GetHR()) != kFileNotFoundException) |
1845 | EX_RETHROW; |
1846 | } |
1847 | EX_END_CATCH(RethrowTerminalExceptions); |
1848 | } |
1849 | |
1850 | return pDomainAssembly; |
1851 | } |
1852 | |
1853 | |
1854 | |