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//
25HRESULT 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
42HRESULT 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
67HRESULT 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
110HRESULT 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//
150SString* 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
169DWORD STDMETHODCALLTYPE TypeName::AddRef()
170{
171 LIMITED_METHOD_CONTRACT;
172
173 m_count++;
174
175 return m_count;
176}
177
178DWORD 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
198TypeName::~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
213HRESULT 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
230HRESULT 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
242HRESULT 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
273HRESULT 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
285HRESULT 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
309HRESULT 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
321HRESULT 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
342HRESULT 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)
368SAFEHANDLE 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*/
394void 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*/
427void 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*/
444void 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*/
487void 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*/
532void 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*/
576void 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
599TypeName* 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
610TypeName::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
650BOOL 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
697done:
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
740BOOL 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 */
752BOOL 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
780BOOL 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
793BOOL 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 ']'
808BOOL 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
835BOOL 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
859BOOL 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
893BOOL 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
916BOOL 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
932BOOL 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// '[' '*' ']'
969BOOL 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
1007BOOL 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
1023BOOL 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
1049BOOL 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 */
1085TypeHandle 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
1095TypeHandle 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
1367TypeHandle 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
1644Exit:
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 */
1657TypeHandle
1658TypeName::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
1783DomainAssembly * 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