diff options
Diffstat (limited to 'src/md/compiler/newmerger.cpp')
-rw-r--r-- | src/md/compiler/newmerger.cpp | 6303 |
1 files changed, 6303 insertions, 0 deletions
diff --git a/src/md/compiler/newmerger.cpp b/src/md/compiler/newmerger.cpp new file mode 100644 index 0000000000..d5199bb570 --- /dev/null +++ b/src/md/compiler/newmerger.cpp @@ -0,0 +1,6303 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// NewMerger.cpp +// + +// +// contains utility code to MD directory +// +// This file provides Compiler Support functionality in metadata. +//***************************************************************************** +#include "stdafx.h" + +#include "newmerger.h" +#include "regmeta.h" + + +#include "importhelper.h" +#include "rwutil.h" +#include "mdlog.h" +#include <posterror.h> +#include <sstring.h> +#include "ndpversion.h" + +#ifdef FEATURE_METADATA_EMIT_ALL + +#define MODULEDEFTOKEN TokenFromRid(1, mdtModule) + +#define COR_MSCORLIB_NAME "mscorlib" +#define COR_MSCORLIB_TYPEREF {0xb7, 0x7a, 0x5c, 0x56,0x19,0x34,0xe0,0x89} + +#define COR_CONSTRUCTOR_METADATA_IDENTIFIER W(".ctor") + +#define COR_COMPILERSERVICE_NAMESPACE "System.Runtime.CompilerServices" +#define COR_EXCEPTIONSERVICE_NAMESPACE "System.Runtime.ExceptionServices" +#define COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE "SuppressMergeCheckAttribute" +#define COR_HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE "HandleProcessCorruptedStateExceptionsAttribute" +#define COR_MISCBITS_NAMESPACE "Microsoft.VisualC" +#define COR_MISCBITS_ATTRIBUTE "Microsoft.VisualC.MiscellaneousBitsAttribute" +#define COR_NATIVECPPCLASS_ATTRIBUTE "System.Runtime.CompilerServices.NativeCppClassAttribute" + +// MODULE_CA_LOCATION W("System.Runtime.CompilerServices.AssemblyAttributesGoHere") +#define MODULE_CA_TYPENAME "AssemblyAttributesGoHere" // fake assembly type-ref for hanging Assembly-level CAs off of + +//***************************************************************************** +// BEGIN: Security Critical Attributes and Enumeration +//***************************************************************************** +#define COR_SECURITYCRITICALSCOPE_ENUM_W W("System.Security.SecurityCriticalScope") + +#define COR_SECURITYCRITICAL_ATTRIBUTE_FULL "System.Security.SecurityCriticalAttribute" +#define COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL "System.Security.SecurityTransparentAttribute" +#define COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL "System.Security.SecurityTreatAsSafeAttribute" + +#define COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W W("System.Security.SecurityCriticalAttribute") +#define COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL_W W("System.Security.SecurityTransparentAttribute") +#define COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W W("System.Security.SecurityTreatAsSafeAttribute") +#define COR_SECURITYSAFECRITICAL_ATTRIBUTE_FULL_W W("System.Security.SecuritySafeCriticalAttribute") + + // definitions of enumeration for System.Security.SecurityCriticalScope (Explicit or Everything) +#define COR_SECURITYCRITICAL_CTOR_ARGCOUNT_NO_SCOPE 0 +#define COR_SECURITYCRITICAL_CTOR_ARGCOUNT_SCOPE_EVERYTHING 1 +#define COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE (3) +#define COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE (5 + sizeof(mdTypeRef) * 1) + +#define COR_SECURITYCRITICAL_ATTRIBUTE_NAMESPACE "System.Security" +#define COR_SECURITYCRITICAL_ATTRIBUTE "SecurityCriticalAttribute" +#define COR_SECURITYTRANSPARENT_ATTRIBUTE_NAMESPACE "System.Security" +#define COR_SECURITYTRANSPARENT_ATTRIBUTE "SecurityTransparentAttribute" +#define COR_SECURITYTREATASSAFE_ATTRIBUTE_NAMESPACE "System.Security" +#define COR_SECURITYTREATASSAFE_ATTRIBUTE "SecurityTreatAsSafeAttribute" +#define COR_SECURITYSAFECRITICAL_ATTRIBUTE "SecuritySafeCriticalAttribute" + + +#define COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING { 0x01, 0x00 ,0x01, 0x00, 0x00, 0x00 ,0x00, 0x00 } +#define COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EXPLICIT {0x01, 0x00, 0x00 ,0x00} +#define COR_SECURITYTREATASSAFE_ATTRIBUTE_VALUE {0x01, 0x00, 0x00 ,0x00} + + + // if true, then registry has been read for enabling or disabling SecurityCritical support +static BOOL g_fRefShouldMergeCriticalChecked = FALSE; + +// by default, security critical attributes will be merged (e.g. unmarked CRT marked Critical/TAS) +// - unless registry config explicitly disables merging +static BOOL g_fRefShouldMergeCritical = TRUE; +//***************************************************************************** +// END: Security Critical Attributes and Enumeration +//***************************************************************************** + +//***************************************************************************** +// Checks to see if the given type is managed or native. We'll key off of the +// Custom Attribute "Microsoft.VisualC.MiscellaneousBitsAttribute". If the third +// byte has the 01000000 bit set then it is an unmanaged type. +// If we can't find the attribute, we will also check for the presence of the +// "System.Runtime.CompilerServices.NativeCppClassAttribute" Custom Attribute +// since the CPP compiler stopped emitting MiscellaneousBitsAttribute in Dev11. +//***************************************************************************** +HRESULT IsManagedType(CMiniMdRW* pMiniMd, + mdTypeDef td, + BOOL *fIsManagedType) +{ + // First look for the custom attribute + HENUMInternal hEnum; + HRESULT hr = S_OK; + + IfFailRet(pMiniMd->CommonEnumCustomAttributeByName(td, COR_MISCBITS_ATTRIBUTE, false, &hEnum)); + + // If there aren't any custom attributes here, then this must be a managed type + if (hEnum.m_ulCount > 0) + { + // Let's loop through these, and see if any of them have that magical bit set. + mdCustomAttribute ca; + CustomAttributeRec *pRec; + ULONG cbData = 0; + + while(HENUMInternal::EnumNext(&hEnum, &ca)) + { + const BYTE* pData = NULL; + + IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(ca), &pRec)); + IfFailGo(pMiniMd->getValueOfCustomAttribute(pRec, &pData, &cbData)); + + if (pData != NULL && cbData >=3) + { + // See if the magical bit is set to make this an unmanaged type + if ((*(pData+2)&0x40) > 0) + { + // Yes, this is an unmanaged type + HENUMInternal::ClearEnum(&hEnum); + *fIsManagedType = FALSE; + return S_OK; + } + } + } + + } + + HENUMInternal::ClearEnum(&hEnum); + + // If this was emitted by a Dev11+ CPP compiler, we only have NativeCppClassAttribute + // so let's check for that before calling this a managed class. + IfFailRet(pMiniMd->CommonEnumCustomAttributeByName(td, COR_NATIVECPPCLASS_ATTRIBUTE, false, &hEnum)); + if (hEnum.m_ulCount > 0) + { + // Yes, this is an unmanaged type + HENUMInternal::ClearEnum(&hEnum); + *fIsManagedType = FALSE; + return S_OK; + } + + // Nope, this isn't an unmanaged type.... must be managed + HENUMInternal::ClearEnum(&hEnum); + *fIsManagedType = TRUE; + hr = S_OK; +ErrExit: + return hr; +}// IsManagedType + + +//***************************************************************************** +// "Is CustomAttribute from certain namespace and assembly" check helper +// Returns S_OK and fills **ppTypeRefRec. +// Returns error code or S_FALSE otherwise as not found and fills **ppTypeRefRec with NULL. +//***************************************************************************** +HRESULT IsAttributeFromNamespace( + CMiniMdRW *pMiniMd, + mdToken tk, + LPCSTR szNamespace, + LPCSTR szAssembly, + TypeRefRec **ppTypeRefRec) +{ + HRESULT hr = S_OK; + if(TypeFromToken(tk) == mdtMemberRef) + { + MemberRefRec *pMemRefRec; + IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tk), &pMemRefRec)); + tk = pMiniMd->getClassOfMemberRef(pMemRefRec); + } + if(TypeFromToken(tk) == mdtTypeRef) + { + TypeRefRec *pTypeRefRec; + IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tk), &pTypeRefRec)); + LPCSTR szTypeRefNamespace; + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szTypeRefNamespace)); + if (strcmp(szTypeRefNamespace, szNamespace) == 0) + { + mdToken tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec); + if (TypeFromToken(tkResTmp) == mdtAssemblyRef) + { + AssemblyRefRec *pAsmRefRec; + IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResTmp), &pAsmRefRec)); + LPCSTR szAssemblyRefName; + IfFailGo(pMiniMd->getNameOfAssemblyRef(pAsmRefRec, &szAssemblyRefName)); + if(SString::_stricmp(szAssemblyRefName, szAssembly) == 0) + { + *ppTypeRefRec = pTypeRefRec; + return S_OK; + } + } + } + } + // Record not found + hr = S_FALSE; +ErrExit: + *ppTypeRefRec = NULL; + return hr; +} + +//***************************************************************************** +// constructor +//***************************************************************************** +NEWMERGER::NEWMERGER() + : m_pRegMetaEmit(0), + m_pImportDataList(NULL), + m_optimizeRefToDef(MDRefToDefDefault), + m_isscsSecurityCritical(ISSCS_Unknown), + m_isscsSecurityCriticalAllScopes(~ISSCS_Unknown) +{ + m_pImportDataTail = &(m_pImportDataList); +#if _DEBUG + m_iImport = 0; +#endif // _DEBUG +} // NEWMERGER::NEWMERGER() + +//***************************************************************************** +// initializer +//***************************************************************************** +HRESULT NEWMERGER::Init(RegMeta *pRegMeta) +{ + HRESULT hr = NOERROR; + MergeTypeData * pMTD; + + m_pRegMetaEmit = pRegMeta; + + // burn an entry so that the RID matches the array index + IfNullGo(pMTD = m_rMTDs.Append()); + + pMTD->m_bSuppressMergeCheck = false; + pMTD->m_cMethods = 0; + pMTD->m_cFields = 0; + pMTD->m_cEvents = 0; + pMTD->m_cProperties = 0; + +ErrExit: + return hr; +} // NEWMERGER::Init + +//***************************************************************************** +// destructor +//***************************************************************************** +NEWMERGER::~NEWMERGER() +{ + if (m_pImportDataList) + { + // delete this list and release all AddRef'ed interfaces! + MergeImportData *pNext; + for (pNext = m_pImportDataList; pNext != NULL; ) + { + pNext = m_pImportDataList->m_pNextImportData; + if (m_pImportDataList->m_pHandler) + m_pImportDataList->m_pHandler->Release(); + if (m_pImportDataList->m_pHostMapToken) + m_pImportDataList->m_pHostMapToken->Release(); + if (m_pImportDataList->m_pMDTokenMap) + delete m_pImportDataList->m_pMDTokenMap; + m_pImportDataList->m_pRegMetaImport->Release(); + delete m_pImportDataList; + m_pImportDataList = pNext; + } + } +} // NEWMERGER::~NEWMERGER + +//***************************************************************************** +CMiniMdRW *NEWMERGER::GetMiniMdEmit() +{ + return &(m_pRegMetaEmit->m_pStgdb->m_MiniMd); +} // CMiniMdRW *NEWMERGER::GetMiniMdEmit() + +//***************************************************************************** +// Adding a new import +//***************************************************************************** +HRESULT NEWMERGER::AddImport( + IMetaDataImport2 *pImport, // [IN] The scope to be merged. + IMapToken *pHostMapToken, // [IN] Host IMapToken interface to receive token remap notification + IUnknown *pHandler) // [IN] An object to receive error notification. +{ + HRESULT hr = NOERROR; + MergeImportData *pData; + + RegMeta *pRM = static_cast<RegMeta*>(pImport); + + // Add a MergeImportData to track the information for this import scope + pData = new (nothrow) MergeImportData; + IfNullGo( pData ); + pData->m_pRegMetaImport = pRM; + pData->m_pRegMetaImport->AddRef(); + pData->m_pHostMapToken = pHostMapToken; + if (pData->m_pHostMapToken) + pData->m_pHostMapToken->AddRef(); + if (pHandler) + { + pData->m_pHandler = pHandler; + pData->m_pHandler->AddRef(); + } + else + { + pData->m_pHandler = NULL; + } + + pData->m_pMDTokenMap = NULL; + pData->m_pNextImportData = NULL; +#if _DEBUG + pData->m_iImport = ++m_iImport; +#endif // _DEBUG + + pData->m_tkHandleProcessCorruptedStateCtor = mdTokenNil; + // add the newly create node to the tail of the list + *m_pImportDataTail = pData; + m_pImportDataTail = &(pData->m_pNextImportData); + +ErrExit: + + return hr; +} // HRESULT NEWMERGER::AddImport() + +HRESULT NEWMERGER::InitMergeTypeData() +{ + CMiniMdRW *pMiniMdEmit; + ULONG cTypeDefRecs; + ULONG i, j; + bool bSuppressMergeCheck; + + ULONG ridStart, ridEnd; + RID ridMap; + + mdToken tkSuppressMergeCheckCtor = mdTokenNil; + mdToken tkCA; + mdMethodDef mdEmit; + mdFieldDef fdEmit; + mdEvent evEmit; + mdProperty prEmit; + + TypeDefRec *pTypeDefRec; + EventMapRec *pEventMapRec; + PropertyMapRec *pPropertyMapRec; + + MergeTypeData *pMTD; + + HRESULT hr = NOERROR; + + pMiniMdEmit = GetMiniMdEmit(); + + // cache the SuppressMergeCheckAttribute.ctor token + ImportHelper::FindCustomAttributeCtorByName( + pMiniMdEmit, COR_MSCORLIB_NAME, + COR_COMPILERSERVICE_NAMESPACE, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE, + &tkSuppressMergeCheckCtor); + + cTypeDefRecs = pMiniMdEmit->getCountTypeDefs(); + _ASSERTE(m_rMTDs.Count() > 0); + + for (i = m_rMTDs.Count(); i <= cTypeDefRecs; i++) + { + IfNullGo(pMTD = m_rMTDs.Append()); + + pMTD->m_cMethods = 0; + pMTD->m_cFields = 0; + pMTD->m_cEvents = 0; + pMTD->m_cProperties = 0; + pMTD->m_bSuppressMergeCheck = (tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit, + TokenFromRid(i, mdtTypeDef), tkSuppressMergeCheckCtor, + NULL, 0, &tkCA)); + + IfFailGo(pMiniMdEmit->GetTypeDefRecord(i, &pTypeDefRec)); + + // Count the number methods + ridStart = pMiniMdEmit->getMethodListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMdEmit->getEndMethodListOfTypeDef(i, &ridEnd)); + + for (j = ridStart; j < ridEnd; j++) + { + IfFailGo(pMiniMdEmit->GetMethodRid(j, (ULONG *)&mdEmit)); + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit, + mdEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) + { + pMTD->m_cMethods++; + } + } + + // Count the number fields + ridStart = pMiniMdEmit->getFieldListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMdEmit->getEndFieldListOfTypeDef(i, &ridEnd)); + + for (j = ridStart; j < ridEnd; j++) + { + IfFailGo(pMiniMdEmit->GetFieldRid(j, (ULONG *)&fdEmit)); + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit, + fdEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) + { + pMTD->m_cFields++; + } + } + + // Count the number of events + IfFailGo(pMiniMdEmit->FindEventMapFor(i, &ridMap)); + if (!InvalidRid(ridMap)) + { + IfFailGo(pMiniMdEmit->GetEventMapRecord(ridMap, &pEventMapRec)); + ridStart = pMiniMdEmit->getEventListOfEventMap(pEventMapRec); + IfFailGo(pMiniMdEmit->getEndEventListOfEventMap(ridMap, &ridEnd)); + + for (j = ridStart; j < ridEnd; j++) + { + IfFailGo(pMiniMdEmit->GetEventRid(j, (ULONG *)&evEmit)); + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit, + evEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) + { + pMTD->m_cEvents++; + } + } + } + + // Count the number of properties + IfFailGo(pMiniMdEmit->FindPropertyMapFor(i, &ridMap)); + if (!InvalidRid(ridMap)) + { + IfFailGo(pMiniMdEmit->GetPropertyMapRecord(ridMap, &pPropertyMapRec)); + ridStart = pMiniMdEmit->getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailGo(pMiniMdEmit->getEndPropertyListOfPropertyMap(ridMap, &ridEnd)); + + for (j = ridStart; j < ridEnd; j++) + { + IfFailGo(pMiniMdEmit->GetPropertyRid(j, (ULONG *)&prEmit)); + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit, + prEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) + { + pMTD->m_cProperties++; + } + } + } + } + +ErrExit: + return hr; +} + +//***************************************************************************** +// Merge now +//***************************************************************************** +HRESULT NEWMERGER::Merge(MergeFlags dwMergeFlags, CorRefToDefCheck optimizeRefToDef) +{ + MergeImportData *pImportData = m_pImportDataList; + MDTOKENMAP **pPrevMap = NULL; + MDTOKENMAP *pMDTokenMap; + HRESULT hr = NOERROR; + MDTOKENMAP *pCurTKMap; + int i; + +#if _DEBUG + { + LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + LOG((LOGMD, "Merge scope list\n")); + i = 0; + for (MergeImportData *pID = m_pImportDataList; pID != NULL; pID = pID->m_pNextImportData) + { + WCHAR szScope[1024], szGuid[40]; + GUID mvid; + ULONG cchScope; + pID->m_pRegMetaImport->GetScopeProps(szScope, 1024, &cchScope, &mvid); + szScope[1023] = 0; + GuidToLPWSTR(mvid, szGuid, 40); + ++i; // Counter is 1-based. + LOG((LOGMD, "%3d: %ls : %ls\n", i, szGuid, szScope)); + } + LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + } +#endif // _DEBUG + + m_dwMergeFlags = dwMergeFlags; + m_optimizeRefToDef = optimizeRefToDef; + + // check to see if we need to do dup check + m_fDupCheck = ((m_dwMergeFlags & NoDupCheck) != NoDupCheck); + + while (pImportData) + { + // Verify that we have a filter for each import scope. + IfNullGo( pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd.GetFilterTable() ); + + // cache the SuppressMergeCheckAttribute.ctor token for each import scope + ImportHelper::FindCustomAttributeCtorByName( + &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd, COR_MSCORLIB_NAME, + COR_COMPILERSERVICE_NAMESPACE, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE, + &pImportData->m_tkSuppressMergeCheckCtor); + + // cache the HandleProcessCorruptedStateExceptionsAttribute.ctor token for each import scope + ImportHelper::FindCustomAttributeCtorByName( + &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd, COR_MSCORLIB_NAME, + COR_EXCEPTIONSERVICE_NAMESPACE, COR_HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE, + &pImportData->m_tkHandleProcessCorruptedStateCtor); + + // check for security critical attribute in the assembly (i.e. explicit annotations) + InputScopeSecurityCriticalStatus isscsTemp = CheckInputScopeIsCritical(pImportData, hr); + IfFailGo(hr); + // clear the unset flag bits (e.g. if critical, clear transparent bit) + // whatever bits remain are bits that have been set in all scopes + if (ISSCS_Unknown == (isscsTemp & ISSCS_SECURITYCRITICAL_FLAGS)) + m_isscsSecurityCriticalAllScopes &= ISSCS_SECURITYCRITICAL_LEGACY; + else + m_isscsSecurityCriticalAllScopes &= isscsTemp; + // set the flag bits (essentially, this allows us to see if _any_ scopes requested a bit) + m_isscsSecurityCritical |= isscsTemp; + + // create the tokenmap class to track metadata token remap for each import scope + pMDTokenMap = new (nothrow) MDTOKENMAP; + IfNullGo(pMDTokenMap); + IfFailGo(pMDTokenMap->Init((IMetaDataImport2*)pImportData->m_pRegMetaImport)); + pImportData->m_pMDTokenMap = pMDTokenMap; + pImportData->m_pMDTokenMap->m_pMap = pImportData->m_pHostMapToken; + if (pImportData->m_pHostMapToken) + pImportData->m_pHostMapToken->AddRef(); + pImportData->m_pMDTokenMap->m_pNextMap = NULL; + if (pPrevMap) + *pPrevMap = pImportData->m_pMDTokenMap; + pPrevMap = &(pImportData->m_pMDTokenMap->m_pNextMap); + pImportData = pImportData->m_pNextImportData; + } + + // Populate the m_rMTDs with the type info already defined in the emit scope + IfFailGo( InitMergeTypeData() ); + + // 1. Merge Module + IfFailGo( MergeModule( ) ); + + // 2. Merge TypeDef partially (i.e. only name) + IfFailGo( MergeTypeDefNamesOnly() ); + + // 3. Merge ModuleRef property and do ModuleRef to ModuleDef optimization + IfFailGo( MergeModuleRefs() ); + + // 4. Merge AssemblyRef. + IfFailGo( MergeAssemblyRefs() ); + + // 5. Merge TypeRef with TypeRef to TypeDef optimization + IfFailGo( MergeTypeRefs() ); + + // 6. Merge TypeSpec & MethodSpec + IfFailGo( MergeTypeSpecs() ); + + // 7. Now Merge the remaining of TypeDef records + IfFailGo( CompleteMergeTypeDefs() ); + + // 8. Merge Methods and Fields. Such that Signature translation is respecting the TypeRef to TypeDef optimization. + IfFailGo( MergeTypeDefChildren() ); + + // 9. Merge MemberRef with MemberRef to MethodDef/FieldDef optimization + IfFailGo( MergeMemberRefs( ) ); + + // 10. Merge InterfaceImpl + IfFailGo( MergeInterfaceImpls( ) ); + + // merge all of the remaining in metadata .... + + // 11. constant has dependency on property, field, param + IfFailGo( MergeConstants() ); + + // 12. field marshal has dependency on param and field + IfFailGo( MergeFieldMarshals() ); + + // 13. in ClassLayout, move over the FieldLayout and deal with FieldLayout as well + IfFailGo( MergeClassLayouts() ); + + // 14. FieldLayout has dependency on FieldDef. + IfFailGo( MergeFieldLayouts() ); + + // 15. FieldRVA has dependency on FieldDef. + IfFailGo( MergeFieldRVAs() ); + + // 16. MethodImpl has dependency on MemberRef, MethodDef, TypeRef and TypeDef. + IfFailGo( MergeMethodImpls() ); + + // 17. pinvoke depends on MethodDef and ModuleRef + IfFailGo( MergePinvoke() ); + + IfFailGo( MergeStandAloneSigs() ); + + IfFailGo( MergeMethodSpecs() ); + + IfFailGo( MergeStrings() ); + + if (m_dwMergeFlags & MergeManifest) + { + // keep the manifest!! + IfFailGo( MergeAssembly() ); + IfFailGo( MergeFiles() ); + IfFailGo( MergeExportedTypes() ); + IfFailGo( MergeManifestResources() ); + } + else if (m_dwMergeFlags & ::MergeExportedTypes) + { + IfFailGo( MergeFiles() ); + IfFailGo( MergeExportedTypes() ); + } + + IfFailGo( MergeCustomAttributes() ); + IfFailGo( MergeDeclSecuritys() ); + + + // Please don't add any MergeXxx() below here. CustomAttributess must be + // very late, because custom values are various other types. + + // Fixup list cannot be merged. Linker will need to re-emit them. + + // Now call back to host for the result of token remap + // + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // Send token remap information for each import scope + pCurTKMap = pImportData->m_pMDTokenMap; + TOKENREC *pRec; + if (pImportData->m_pHostMapToken) + { + for (i = 0; i < pCurTKMap->Count(); i++) + { + pRec = pCurTKMap->Get(i); + if (!pRec->IsEmpty()) + pImportData->m_pHostMapToken->Map(pRec->m_tkFrom, pRec->m_tkTo); + } + } + } + + // And last, but not least, let's do Security critical module-level attribute consolidation + // and metadata fixups. + IfFailGo( MergeSecurityCriticalAttributes() ); + + + + + +#if _DEBUG + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // dump the mapping + LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + LOG((LOGMD, "Dumping token remap for one import scope!\n")); + LOG((LOGMD, "This is the %d import scope for merge!\n", pImportData->m_iImport)); + + pCurTKMap = pImportData->m_pMDTokenMap; + TOKENREC *pRec; + for (i = 0; i < pCurTKMap->Count(); i++) + { + pRec = pCurTKMap->Get(i); + if (!pRec->IsEmpty()) + { + LOG((LOGMD, " Token 0x%08x ====>>>> Token 0x%08x\n", pRec->m_tkFrom, pRec->m_tkTo)); + } + } + LOG((LOGMD, "End dumping token remap!\n")); + LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")); + } +#endif // _DEBUG + +ErrExit: + return hr; +} // HRESULT NEWMERGER::Merge() + + +//***************************************************************************** +// Merge ModuleDef +//***************************************************************************** +HRESULT NEWMERGER::MergeModule() +{ + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + HRESULT hr = NOERROR; + TOKENREC *pTokenRec; + + // we don't really merge Module information but we create a one to one mapping for each module token into the TokenMap + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + // set the current MDTokenMap + + pCurTkMap = pImportData->m_pMDTokenMap; + IfFailGo( pCurTkMap->InsertNotFound(MODULEDEFTOKEN, true, MODULEDEFTOKEN, &pTokenRec) ); + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeModule() + + +//***************************************************************************** +// Merge TypeDef but only Names. This is a partial merge to support TypeRef to TypeDef optimization +//***************************************************************************** +HRESULT NEWMERGER::MergeTypeDefNamesOnly() +{ + HRESULT hr = NOERROR; + TypeDefRec *pRecImport = NULL; + TypeDefRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdTypeDef tdEmit; + mdTypeDef tdImport; + bool bDuplicate; + DWORD dwFlags; + DWORD dwExportFlags; + NestedClassRec *pNestedRec; + RID iNestedRec; + mdTypeDef tdNester; + TOKENREC *pTokenRec; + + LPCUTF8 szNameImp; + LPCUTF8 szNamespaceImp; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + iCount = pMiniMdImport->getCountTypeDefs(); + + // Merge the typedefs + for (i = 1; i <= iCount; i++) + { + // only merge those TypeDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false) + continue; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImport, &szNameImp)); + IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImport, &szNamespaceImp)); + + // If the class is a Nested class, get the parent token. + dwFlags = pMiniMdImport->getFlagsOfTypeDef(pRecImport); + if (IsTdNested(dwFlags)) + { + IfFailGo(pMiniMdImport->FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &iNestedRec)); + if (InvalidRid(iNestedRec)) + { + _ASSERTE(!"Bad state!"); + IfFailGo(META_E_BADMETADATA); + } + else + { + IfFailGo(pMiniMdImport->GetNestedClassRecord(iNestedRec, &pNestedRec)); + tdNester = pMiniMdImport->getEnclosingClassOfNestedClass(pNestedRec); + _ASSERTE(!IsNilToken(tdNester)); + IfFailGo(pCurTkMap->Remap(tdNester, &tdNester)); + } + } + else + tdNester = mdTokenNil; + + bSuppressMergeCheck = (pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + TokenFromRid(i, mdtTypeDef), pImportData->m_tkSuppressMergeCheckCtor, + NULL, 0, &tkCA)); + + // does this TypeDef already exist in the emit scope? + if ( ImportHelper::FindTypeDefByName( + pMiniMdEmit, + szNamespaceImp, + szNameImp, + tdNester, + &tdEmit) == S_OK ) + { + // Yes, it does + bDuplicate = true; + + // Let's look at their accessiblities. + IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(tdEmit), &pRecEmit)); + dwExportFlags = pMiniMdEmit->getFlagsOfTypeDef(pRecEmit); + + // Managed types need to have the same accessiblity + BOOL fManagedType = FALSE; + IfFailGo(IsManagedType(pMiniMdImport, TokenFromRid(i, mdtTypeDef), &fManagedType)); + if (fManagedType) + { + if ((dwFlags&tdVisibilityMask) != (dwExportFlags&tdVisibilityMask)) + { + CheckContinuableErrorEx(META_E_MISMATCHED_VISIBLITY, pImportData, TokenFromRid(i, mdtTypeDef)); + } + + } + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + if (pMTD->m_bSuppressMergeCheck != bSuppressMergeCheck) + { + CheckContinuableErrorEx(META_E_MD_INCONSISTENCY, pImportData, TokenFromRid(i, mdtTypeDef)); + } + } + else + { + // No, it doesn't. Copy it over. + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddTypeDefRecord(&pRecEmit, (RID *)&tdEmit)); + + // make sure the index matches + _ASSERTE(((mdTypeDef)m_rMTDs.Count()) == tdEmit); + + IfNullGo(pMTD = m_rMTDs.Append()); + + pMTD->m_cMethods = 0; + pMTD->m_cFields = 0; + pMTD->m_cEvents = 0; + pMTD->m_cProperties = 0; + pMTD->m_bSuppressMergeCheck = bSuppressMergeCheck; + + tdEmit = TokenFromRid( tdEmit, mdtTypeDef ); + + // Set Full Qualified Name. + IfFailGo( CopyTypeDefPartially( pRecEmit, pMiniMdImport, pRecImport) ); + + // Create a NestedClass record if the class is a Nested class. + if (! IsNilToken(tdNester)) + { + IfFailGo(pMiniMdEmit->AddNestedClassRecord(&pNestedRec, &iNestedRec)); + + // copy over the information + IfFailGo( pMiniMdEmit->PutToken(TBL_NestedClass, NestedClassRec::COL_NestedClass, + pNestedRec, tdEmit)); + + // tdNester has already been remapped above to the Emit scope. + IfFailGo( pMiniMdEmit->PutToken(TBL_NestedClass, NestedClassRec::COL_EnclosingClass, + pNestedRec, tdNester)); + IfFailGo( pMiniMdEmit->AddNestedClassToHash(iNestedRec) ); + + } + } + + // record the token movement + tdImport = TokenFromRid(i, mdtTypeDef); + IfFailGo( pCurTkMap->InsertNotFound(tdImport, bDuplicate, tdEmit, &pTokenRec) ); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeTypeDefNamesOnly() + + +//***************************************************************************** +// Merge EnclosingType tables +//***************************************************************************** +HRESULT NEWMERGER::CopyTypeDefPartially( + TypeDefRec *pRecEmit, // [IN] the emit record to fill + CMiniMdRW *pMiniMdImport, // [IN] the importing scope + TypeDefRec *pRecImp) // [IN] the record to import + +{ + HRESULT hr; + LPCUTF8 szNameImp; + LPCUTF8 szNamespaceImp; + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + + IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImp, &szNameImp)); + IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImp, &szNamespaceImp)); + + IfFailGo( pMiniMdEmit->PutString( TBL_TypeDef, TypeDefRec::COL_Name, pRecEmit, szNameImp) ); + IfFailGo( pMiniMdEmit->PutString( TBL_TypeDef, TypeDefRec::COL_Namespace, pRecEmit, szNamespaceImp) ); + + pRecEmit->SetFlags(pRecImp->GetFlags()); + + // Don't copy over the extends until TypeRef's remap is calculated + +ErrExit: + return hr; + +} // HRESULT NEWMERGER::CopyTypeDefPartially() + + +//***************************************************************************** +// Merge ModuleRef tables including ModuleRef to ModuleDef optimization +//***************************************************************************** +HRESULT NEWMERGER::MergeModuleRefs() +{ + HRESULT hr = NOERROR; + ModuleRefRec *pRecImport = NULL; + ModuleRefRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdModuleRef mrEmit; + bool bDuplicate = false; + TOKENREC *pTokenRec; + LPCUTF8 szNameImp; + bool isModuleDef; + + MergeImportData *pImportData; + MergeImportData *pData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountModuleRefs(); + + // loop through all ModuleRef + for (i = 1; i <= iCount; i++) + { + // only merge those ModuleRefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsModuleRefMarked(TokenFromRid(i, mdtModuleRef)) == false) + continue; + + isModuleDef = false; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetModuleRefRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getNameOfModuleRef(pRecImport, &szNameImp)); + + // Only do the ModuleRef to ModuleDef optimization if ModuleRef's name is meaningful! + if ( szNameImp && szNameImp[0] != '\0') + { + + // Check to see if this ModuleRef has become the ModuleDef token + for (pData = m_pImportDataList; pData != NULL; pData = pData->m_pNextImportData) + { + CMiniMdRW *pMiniMd = &(pData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + ModuleRec *pRec; + LPCUTF8 szName; + + IfFailGo(pMiniMd->GetModuleRecord(MODULEDEFTOKEN, &pRec)); + IfFailGo(pMiniMd->getNameOfModule(pRec, &szName)); + if (szName && szName[0] != '\0' && strcmp(szNameImp, szName) == 0) + { + // We found an import Module for merging that has the same name as the ModuleRef + isModuleDef = true; + bDuplicate = true; + mrEmit = MODULEDEFTOKEN; // set the resulting token to ModuleDef Token + break; + } + } + } + + if (isModuleDef == false) + { + // does this ModuleRef already exist in the emit scope? + hr = ImportHelper::FindModuleRef(pMiniMdEmit, + szNameImp, + &mrEmit); + if (hr == S_OK) + { + // Yes, it does + bDuplicate = true; + } + else if (hr == CLDB_E_RECORD_NOTFOUND) + { + // No, it doesn't. Copy it over. + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecEmit, (RID*)&mrEmit)); + mrEmit = TokenFromRid(mrEmit, mdtModuleRef); + + // Set ModuleRef Name. + IfFailGo( pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, pRecEmit, szNameImp) ); + } + else + IfFailGo(hr); + } + + // record the token movement + IfFailGo( pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtModuleRef), + bDuplicate, + mrEmit, + &pTokenRec) ); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeModuleRefs() + + +//***************************************************************************** +// Merge AssemblyRef tables +//***************************************************************************** +HRESULT NEWMERGER::MergeAssemblyRefs() +{ + HRESULT hr = NOERROR; + AssemblyRefRec *pRecImport = NULL; + AssemblyRefRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + mdAssemblyRef arEmit; + bool bDuplicate = false; + LPCUTF8 szTmp; + const void *pbTmp; + ULONG cbTmp; + ULONG iCount; + ULONG i; + ULONG iRecord; + TOKENREC *pTokenRec; + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountAssemblyRefs(); + + // loope through all the AssemblyRefs. + for (i = 1; i <= iCount; i++) + { + // Compare with the emit scope. + IfFailGo(pMiniMdImport->GetAssemblyRefRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getPublicKeyOrTokenOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp)); + hr = CLDB_E_RECORD_NOTFOUND; + if (m_fDupCheck) + { + LPCSTR szAssemblyRefName; + LPCSTR szAssemblyRefLocale; + IfFailGo(pMiniMdImport->getNameOfAssemblyRef(pRecImport, &szAssemblyRefName)); + IfFailGo(pMiniMdImport->getLocaleOfAssemblyRef(pRecImport, &szAssemblyRefLocale)); + hr = ImportHelper::FindAssemblyRef( + pMiniMdEmit, + szAssemblyRefName, + szAssemblyRefLocale, + pbTmp, + cbTmp, + pRecImport->GetMajorVersion(), + pRecImport->GetMinorVersion(), + pRecImport->GetBuildNumber(), + pRecImport->GetRevisionNumber(), + pRecImport->GetFlags(), + &arEmit); + } + if (hr == S_OK) + { + // Yes, it does + bDuplicate = true; + + // <TODO>@FUTURE: more verification?</TODO> + } + else if (hr == CLDB_E_RECORD_NOTFOUND) + { + // No, it doesn't. Copy it over. + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecEmit, &iRecord)); + arEmit = TokenFromRid(iRecord, mdtAssemblyRef); + + pRecEmit->Copy(pRecImport); + + IfFailGo(pMiniMdImport->getPublicKeyOrTokenOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp)); + IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken, + pRecEmit, pbTmp, cbTmp)); + + IfFailGo(pMiniMdImport->getNameOfAssemblyRef(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name, + pRecEmit, szTmp)); + + IfFailGo(pMiniMdImport->getLocaleOfAssemblyRef(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale, + pRecEmit, szTmp)); + + IfFailGo(pMiniMdImport->getHashValueOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp)); + IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue, + pRecEmit, pbTmp, cbTmp)); + + } + else + IfFailGo(hr); + + // record the token movement. + IfFailGo(pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtAssemblyRef), + bDuplicate, + arEmit, + &pTokenRec)); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeAssemblyRefs() + + +//***************************************************************************** +// Merge TypeRef tables also performing TypeRef to TypeDef opitimization. ie. +// we will not introduce a TypeRef record if we can optimize it to a TypeDef. +//***************************************************************************** +HRESULT NEWMERGER::MergeTypeRefs() +{ + HRESULT hr = NOERROR; + TypeRefRec *pRecImport = NULL; + TypeRefRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdTypeRef trEmit; + bool bDuplicate = false; + TOKENREC *pTokenRec; + bool isTypeDef; + + mdToken tkResImp; + mdToken tkResEmit; + LPCUTF8 szNameImp; + LPCUTF8 szNamespaceImp; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountTypeRefs(); + + // loop through all TypeRef + for (i = 1; i <= iCount; i++) + { + // only merge those TypeRefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsTypeRefMarked(TokenFromRid(i, mdtTypeRef)) == false) + continue; + + isTypeDef = false; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetTypeRefRecord(i, &pRecImport)); + tkResImp = pMiniMdImport->getResolutionScopeOfTypeRef(pRecImport); + IfFailGo(pMiniMdImport->getNamespaceOfTypeRef(pRecImport, &szNamespaceImp)); + IfFailGo(pMiniMdImport->getNameOfTypeRef(pRecImport, &szNameImp)); + if (!IsNilToken(tkResImp)) + { + IfFailGo(pCurTkMap->Remap(tkResImp, &tkResEmit)); + } + else + { + tkResEmit = tkResImp; + } + + // There are some interesting cases to consider here. + // 1) If the TypeRef's ResolutionScope is a nil token, or is the MODULEDEFTOKEN (current module), + // then the TypeRef refers to a type in the current scope, so we should find a corresponding + // TypeDef in the output scope. If we find the TypeDef, we'll remap this TypeRef token + // to that TypeDef token. + // If we don't find that TypeDef, or if "TypeRef to TypeDef" optimization is turned off, we'll + // create the TypeRef in the output scope. + // 2) If the TypeRef's ResolutionScope has been resolved to a TypeDef, then this TypeRef was part + // of a nested type definition. In that case, we'd better find a corresponding TypeDef + // or we have an error. + if (IsNilToken(tkResEmit) || tkResEmit == MODULEDEFTOKEN || TypeFromToken(tkResEmit) == mdtTypeDef) + { + hr = ImportHelper::FindTypeDefByName( + pMiniMdEmit, + szNamespaceImp, + szNameImp, + (TypeFromToken(tkResEmit) == mdtTypeDef) ? tkResEmit : mdTokenNil, + &trEmit); + if (hr == S_OK) + { + isTypeDef = true; + + // it really does not matter if we set the duplicate to true or false. + bDuplicate = true; + } + } + + // If the ResolutionScope was merged as a TypeDef, and this token wasn't found as TypeDef, send the error. + if (TypeFromToken(tkResEmit) == mdtTypeDef && !isTypeDef) + { + // Send the error notification. Use the "continuable error" callback, but even if linker says it is + // ok, don't continue. + CheckContinuableErrorEx(META_E_TYPEDEF_MISSING, pImportData, TokenFromRid(i, mdtTypeRef)); + IfFailGo(META_E_TYPEDEF_MISSING); + } + + // If this TypeRef cannot be optmized to a TypeDef or the Ref to Def optimization is turned off, do the following. + if (!isTypeDef || !((m_optimizeRefToDef & MDTypeRefToDef) == MDTypeRefToDef)) + { + // does this TypeRef already exist in the emit scope? + if ( m_fDupCheck && ImportHelper::FindTypeRefByName( + pMiniMdEmit, + tkResEmit, + szNamespaceImp, + szNameImp, + &trEmit) == S_OK ) + { + // Yes, it does + bDuplicate = true; + } + else + { + // No, it doesn't. Copy it over. + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddTypeRefRecord(&pRecEmit, (RID*)&trEmit)); + trEmit = TokenFromRid(trEmit, mdtTypeRef); + + // Set ResolutionScope. tkResEmit has already been re-mapped. + IfFailGo(pMiniMdEmit->PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope, + pRecEmit, tkResEmit)); + + // Set Name. + IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Name, + pRecEmit, szNameImp)); + IfFailGo(pMiniMdEmit->AddNamedItemToHash(TBL_TypeRef, trEmit, szNameImp, 0)); + + // Set Namespace. + IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Namespace, + pRecEmit, szNamespaceImp)); + } + } + + // record the token movement + IfFailGo( pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtTypeRef), + bDuplicate, + trEmit, + &pTokenRec) ); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeTypeRefs() + + +//***************************************************************************** +// copy over the remaining information of partially merged TypeDef records. Right now only +// extends field is delayed to here. The reason that we delay extends field is because we want +// to optimize TypeRef to TypeDef if possible. +//***************************************************************************** +HRESULT NEWMERGER::CompleteMergeTypeDefs() +{ + HRESULT hr = NOERROR; + TypeDefRec *pRecImport = NULL; + TypeDefRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + TOKENREC *pTokenRec; + mdToken tkExtendsImp; + mdToken tkExtendsEmit; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + iCount = pMiniMdImport->getCountTypeDefs(); + + // Merge the typedefs + for (i = 1; i <= iCount; i++) + { + // only merge those TypeDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false) + continue; + + if ( !pCurTkMap->Find(TokenFromRid(i, mdtTypeDef), &pTokenRec) ) + { + _ASSERTE( !"bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + + if (pTokenRec->m_isDuplicate == false) + { + // get the extends token from the import + IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport)); + tkExtendsImp = pMiniMdImport->getExtendsOfTypeDef(pRecImport); + + // map the extends token to an merged token + IfFailGo( pCurTkMap->Remap(tkExtendsImp, &tkExtendsEmit) ); + + // set the extends to the merged TypeDef records. + IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(pTokenRec->m_tkTo), &pRecEmit)); + IfFailGo(pMiniMdEmit->PutToken(TBL_TypeDef, TypeDefRec::COL_Extends, pRecEmit, tkExtendsEmit)); + } + else + { + // <TODO>@FUTURE: we can check to make sure the import extends maps to the one that is set to the emit scope. + // Otherwise, it is a error to report to linker.</TODO> + } + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::CompleteMergeTypeDefs() + + +//***************************************************************************** +// merging TypeSpecs +//***************************************************************************** +HRESULT NEWMERGER::MergeTypeSpecs() +{ + HRESULT hr = NOERROR; + TypeSpecRec *pRecImport = NULL; + TypeSpecRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + TOKENREC *pTokenRec; + mdTypeSpec tsImp; + mdTypeSpec tsEmit; + bool fDuplicate; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + iCount = pMiniMdImport->getCountTypeSpecs(); + + // loop through all TypeSpec + for (i = 1; i <= iCount; i++) + { + // only merge those TypeSpecs that are marked + if ( pMiniMdImport->GetFilterTable()->IsTypeSpecMarked(TokenFromRid(i, mdtTypeSpec)) == false) + continue; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetTypeSpecRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getSignatureOfTypeSpec(pRecImport, &pbSig, &cbSig)); + + // convert tokens contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInFieldSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly information. + pMiniMdImport, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + hr = CLDB_E_RECORD_NOTFOUND; + if (m_fDupCheck) + hr = ImportHelper::FindTypeSpec( + pMiniMdEmit, + (PCOR_SIGNATURE) qbSig.Ptr(), + cbEmit, + &tsEmit ); + + if ( hr == S_OK ) + { + // find a duplicate + fDuplicate = true; + } + else + { + // copy over + fDuplicate = false; + IfFailGo(pMiniMdEmit->AddTypeSpecRecord(&pRecEmit, (ULONG *)&tsEmit)); + tsEmit = TokenFromRid(tsEmit, mdtTypeSpec); + IfFailGo( pMiniMdEmit->PutBlob( + TBL_TypeSpec, + TypeSpecRec::COL_Signature, + pRecEmit, + (PCOR_SIGNATURE)qbSig.Ptr(), + cbEmit)); + } + tsImp = TokenFromRid(i, mdtTypeSpec); + + // Record the token movement + IfFailGo( pCurTkMap->InsertNotFound(tsImp, fDuplicate, tsEmit, &pTokenRec) ); + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeTypeSpecs() + + +//***************************************************************************** +// merging Children of TypeDefs. This includes field, method, parameter, property, event +//***************************************************************************** +HRESULT NEWMERGER::MergeTypeDefChildren() +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdTypeDef tdEmit; + mdTypeDef tdImport; + TOKENREC *pTokenRec; + +#if _DEBUG + TypeDefRec *pRecImport = NULL; + LPCUTF8 szNameImp; + LPCUTF8 szNamespaceImp; +#endif // _DEBUG + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountTypeDefs(); + + // loop through all TypeDef again to merge/copy Methods, fields, events, and properties + // + for (i = 1; i <= iCount; i++) + { + // only merge those TypeDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false) + continue; + +#if _DEBUG + IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImport, &szNameImp)); + IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImport, &szNamespaceImp)); +#endif // _DEBUG + + // check to see if the typedef is duplicate or not + tdImport = TokenFromRid(i, mdtTypeDef); + if ( pCurTkMap->Find( tdImport, &pTokenRec) == false) + { + _ASSERTE( !"bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + tdEmit = pTokenRec->m_tkTo; + if (pTokenRec->m_isDuplicate == false) + { + // now move all of the children records over + IfFailGo( CopyMethods(pImportData, tdImport, tdEmit) ); + IfFailGo( CopyFields(pImportData, tdImport, tdEmit) ); + + IfFailGo( CopyEvents(pImportData, tdImport, tdEmit) ); + + // Property has dependency on events + IfFailGo( CopyProperties(pImportData, tdImport, tdEmit) ); + + // Generic Params. + IfFailGo( CopyGenericParams(pImportData, tdImport, tdEmit) ); + } + else + { + // verify the children records + IfFailGo( VerifyMethods(pImportData, tdImport, tdEmit) ); + IfFailGo( VerifyFields(pImportData, tdImport, tdEmit) ); + IfFailGo( VerifyEvents(pImportData, tdImport, tdEmit) ); + + // property has dependency on events + IfFailGo( VerifyProperties(pImportData, tdImport, tdEmit) ); + + IfFailGo( VerifyGenericParams(pImportData, tdImport, tdEmit) ); + } + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeTypeDefChildren() + + +//******************************************************************************* +// Helper to copy an Method record +//******************************************************************************* +HRESULT NEWMERGER::CopyMethod( + MergeImportData *pImportData, // [IN] import scope + MethodRec *pRecImp, // [IN] the record to import + MethodRec *pRecEmit) // [IN] the emit record to fill +{ + HRESULT hr; + CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + LPCUTF8 szName; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + MDTOKENMAP *pCurTkMap; + + pCurTkMap = pImportData->m_pMDTokenMap; + + // copy over the fix part of the record + pRecEmit->Copy(pRecImp); + + // copy over the name + IfFailGo(pMiniMdImp->getNameOfMethod(pRecImp, &szName)); + IfFailGo(pMiniMdEmit->PutString(TBL_Method, MethodRec::COL_Name, pRecEmit, szName)); + + // copy over the signature + IfFailGo(pMiniMdImp->getSignatureOfMethod(pRecImp, &pbSig, &cbSig)); + + // convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImp, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + IfFailGo(pMiniMdEmit->PutBlob(TBL_Method, MethodRec::COL_Signature, pRecEmit, qbSig.Ptr(), cbEmit)); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyMethod() + + +//******************************************************************************* +// Helper to copy an field record +//******************************************************************************* +HRESULT NEWMERGER::CopyField( + MergeImportData *pImportData, // [IN] import scope + FieldRec *pRecImp, // [IN] the record to import + FieldRec *pRecEmit) // [IN] the emit record to fill +{ + HRESULT hr; + CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + LPCUTF8 szName; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + MDTOKENMAP *pCurTkMap; + + pCurTkMap = pImportData->m_pMDTokenMap; + + // copy over the fix part of the record + pRecEmit->SetFlags(pRecImp->GetFlags()); + + // copy over the name + IfFailGo(pMiniMdImp->getNameOfField(pRecImp, &szName)); + IfFailGo(pMiniMdEmit->PutString(TBL_Field, FieldRec::COL_Name, pRecEmit, szName)); + + // copy over the signature + IfFailGo(pMiniMdImp->getSignatureOfField(pRecImp, &pbSig, &cbSig)); + + // convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Emit assembly scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImp, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + IfFailGo(pMiniMdEmit->PutBlob(TBL_Field, FieldRec::COL_Signature, pRecEmit, qbSig.Ptr(), cbEmit)); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyField() + +//******************************************************************************* +// Helper to copy an field record +//******************************************************************************* +HRESULT NEWMERGER::CopyParam( + MergeImportData *pImportData, // [IN] import scope + ParamRec *pRecImp, // [IN] the record to import + ParamRec *pRecEmit) // [IN] the emit record to fill +{ + HRESULT hr; + CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + LPCUTF8 szName; + MDTOKENMAP *pCurTkMap; + + pCurTkMap = pImportData->m_pMDTokenMap; + + // copy over the fix part of the record + pRecEmit->Copy(pRecImp); + + // copy over the name + IfFailGo(pMiniMdImp->getNameOfParam(pRecImp, &szName)); + IfFailGo(pMiniMdEmit->PutString(TBL_Param, ParamRec::COL_Name, pRecEmit, szName)); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyParam() + +//******************************************************************************* +// Helper to copy an Event record +//******************************************************************************* +HRESULT NEWMERGER::CopyEvent( + MergeImportData *pImportData, // [IN] import scope + EventRec *pRecImp, // [IN] the record to import + EventRec *pRecEmit) // [IN] the emit record to fill +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + mdToken tkEventTypeImp; + mdToken tkEventTypeEmit; // could be TypeDef or TypeRef + LPCUTF8 szName; + MDTOKENMAP *pCurTkMap; + + pCurTkMap = pImportData->m_pMDTokenMap; + + pRecEmit->SetEventFlags(pRecImp->GetEventFlags()); + + //move over the event name + IfFailGo(pMiniMdImp->getNameOfEvent(pRecImp, &szName)); + IfFailGo( pMiniMdEmit->PutString(TBL_Event, EventRec::COL_Name, pRecEmit, szName) ); + + // move over the EventType + tkEventTypeImp = pMiniMdImp->getEventTypeOfEvent(pRecImp); + if ( !IsNilToken(tkEventTypeImp) ) + { + IfFailGo( pCurTkMap->Remap(tkEventTypeImp, &tkEventTypeEmit) ); + IfFailGo(pMiniMdEmit->PutToken(TBL_Event, EventRec::COL_EventType, pRecEmit, tkEventTypeEmit)); + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyEvent() + + +//******************************************************************************* +// Helper to copy a property record +//******************************************************************************* +HRESULT NEWMERGER::CopyProperty( + MergeImportData *pImportData, // [IN] import scope + PropertyRec *pRecImp, // [IN] the record to import + PropertyRec *pRecEmit) // [IN] the emit record to fill +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + LPCUTF8 szName; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + MDTOKENMAP *pCurTkMap; + + pCurTkMap = pImportData->m_pMDTokenMap; + + // move over the flag value + pRecEmit->SetPropFlags(pRecImp->GetPropFlags()); + + //move over the property name + IfFailGo(pMiniMdImp->getNameOfProperty(pRecImp, &szName)); + IfFailGo( pMiniMdEmit->PutString(TBL_Property, PropertyRec::COL_Name, pRecEmit, szName) ); + + // move over the type of the property + IfFailGo(pMiniMdImp->getTypeOfProperty(pRecImp, &pbSig, &cbSig)); + + // convert rid contained in signature to new scope + IfFailGo( ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImp, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit) ); // number of bytes write to cbEmit + + IfFailGo(pMiniMdEmit->PutBlob(TBL_Property, PropertyRec::COL_Type, pRecEmit, qbSig.Ptr(), cbEmit)); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyProperty() + + +//***************************************************************************** +// Copy MethodSemantics for an event or a property +//***************************************************************************** +HRESULT NEWMERGER::CopyMethodSemantics( + MergeImportData *pImportData, + mdToken tkImport, // Event or property in the import scope + mdToken tkEmit) // corresponding event or property in the emitting scope +{ + HRESULT hr = NOERROR; + MethodSemanticsRec *pRecImport = NULL; + MethodSemanticsRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + ULONG i; + ULONG msEmit; // MethodSemantics are just index not tokens + mdToken tkMethodImp; + mdToken tkMethodEmit; + MDTOKENMAP *pCurTkMap; + HENUMInternal hEnum; + + pCurTkMap = pImportData->m_pMDTokenMap; + + // copy over the associates + IfFailGo( pMiniMdImport->FindMethodSemanticsHelper(tkImport, &hEnum) ); + while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &i)) + { + IfFailGo(pMiniMdImport->GetMethodSemanticsRecord(i, &pRecImport)); + IfFailGo(pMiniMdEmit->AddMethodSemanticsRecord(&pRecEmit, &msEmit)); + pRecEmit->SetSemantic(pRecImport->GetSemantic()); + + // set the MethodSemantics + tkMethodImp = pMiniMdImport->getMethodOfMethodSemantics(pRecImport); + IfFailGo( pCurTkMap->Remap(tkMethodImp, &tkMethodEmit) ); + IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSemantics, MethodSemanticsRec::COL_Method, pRecEmit, tkMethodEmit)); + + // set the associate + _ASSERTE( pMiniMdImport->getAssociationOfMethodSemantics(pRecImport) == tkImport ); + IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, pRecEmit, tkEmit)); + + // no need to record the movement since it is not a token + IfFailGo( pMiniMdEmit->AddMethodSemanticsToHash(msEmit) ); + } +ErrExit: + HENUMInternal::ClearEnum(&hEnum); + return hr; +} // HRESULT NEWMERGER::CopyMethodSemantics() + + +//***************************************************************************** +// Copy Methods given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::CopyMethods( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + MethodRec *pRecImport = NULL; + MethodRec *pRecEmit = NULL; + TypeDefRec *pTypeDefRec; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG ridStart, ridEnd; + ULONG i; + mdMethodDef mdEmit; + mdMethodDef mdImp; + TOKENREC *pTokenRec; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec)); + ridStart = pMiniMdImport->getMethodListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMdImport->getEndMethodListOfTypeDef(RidFromToken(tdImport), &ridEnd)); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + // make sure we didn't count the methods yet + _ASSERTE(pMTD->m_cMethods == 0); + + // loop through all Methods + for (i = ridStart; i < ridEnd; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetMethodRid(i, (ULONG *)&mdImp)); + + // only merge those MethodDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(TokenFromRid(mdImp, mdtMethodDef)) == false) + continue; + + IfFailGo(pMiniMdImport->GetMethodRecord(mdImp, &pRecImport)); + IfFailGo(pMiniMdEmit->AddMethodRecord(&pRecEmit, (RID *)&mdEmit)); + + // copy the method content over + IfFailGo( CopyMethod(pImportData, pRecImport, pRecEmit) ); + + IfFailGo( pMiniMdEmit->AddMethodToTypeDef(RidFromToken(tdEmit), mdEmit)); + + // record the token movement + mdImp = TokenFromRid(mdImp, mdtMethodDef); + mdEmit = TokenFromRid(mdEmit, mdtMethodDef); + IfFailGo( pMiniMdEmit->AddMemberDefToHash( + mdEmit, + tdEmit) ); + + IfFailGo( pCurTkMap->InsertNotFound(mdImp, false, mdEmit, &pTokenRec) ); + + // copy over the children + IfFailGo( CopyParams(pImportData, mdImp, mdEmit) ); + IfFailGo( CopyGenericParams(pImportData, mdImp, mdEmit) ); + + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + mdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + + if (!bSuppressMergeCheck) { + pMTD->m_cMethods++; + } + } + + // make sure we don't count any methods if merge check is suppressed on the type + _ASSERTE(pMTD->m_cMethods == 0 || !pMTD->m_bSuppressMergeCheck); +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyMethods() + + +//***************************************************************************** +// Copy Fields given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::CopyFields( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + FieldRec *pRecImport = NULL; + FieldRec *pRecEmit = NULL; + TypeDefRec *pTypeDefRec; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG ridStart, ridEnd; + ULONG i; + mdFieldDef fdEmit; + mdFieldDef fdImp; + bool bDuplicate; + TOKENREC *pTokenRec; + PCCOR_SIGNATURE pvSigBlob; + ULONG cbSigBlob; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec)); + ridStart = pMiniMdImport->getFieldListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMdImport->getEndFieldListOfTypeDef(RidFromToken(tdImport), &ridEnd)); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + // make sure we didn't count the methods yet + _ASSERTE(pMTD->m_cFields == 0); + + // loop through all FieldDef of a TypeDef + for (i = ridStart; i < ridEnd; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetFieldRid(i, (ULONG *)&fdImp)); + + // only merge those FieldDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(fdImp, mdtFieldDef)) == false) + continue; + + + IfFailGo(pMiniMdImport->GetFieldRecord(fdImp, &pRecImport)); + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddFieldRecord(&pRecEmit, (RID *)&fdEmit)); + + // copy the field content over + IfFailGo( CopyField(pImportData, pRecImport, pRecEmit) ); + + IfFailGo( pMiniMdEmit->AddFieldToTypeDef(RidFromToken(tdEmit), fdEmit)); + + // record the token movement + fdImp = TokenFromRid(fdImp, mdtFieldDef); + fdEmit = TokenFromRid(fdEmit, mdtFieldDef); + IfFailGo(pMiniMdEmit->getSignatureOfField(pRecEmit, &pvSigBlob, &cbSigBlob)); + IfFailGo( pMiniMdEmit->AddMemberDefToHash( + fdEmit, + tdEmit) ); + + IfFailGo( pCurTkMap->InsertNotFound(fdImp, false, fdEmit, &pTokenRec) ); + + // count the number of fields that didn't suppress merge check + // non-static fields doesn't inherite the suppress merge check attribute from the type + bSuppressMergeCheck = + (IsFdStatic(pRecEmit->GetFlags()) && pMTD->m_bSuppressMergeCheck) || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + fdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) { + pMTD->m_cFields++; + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyFields() + + +//***************************************************************************** +// Copy Events given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::CopyEvents( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + RID ridEventMap; + EventMapRec *pEventMapRec; + EventRec *pRecImport; + EventRec *pRecEmit; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + mdEvent evImp; + mdEvent evEmit; + TOKENREC *pTokenRec; + ULONG iEventMap; + EventMapRec *pEventMap; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + mdCustomAttribute tkCA; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + pCurTkMap = pImportData->m_pMDTokenMap; + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + // make sure we didn't count the events yet + _ASSERTE(pMTD->m_cEvents == 0); + + IfFailGo(pMiniMdImport->FindEventMapFor(RidFromToken(tdImport), &ridEventMap)); + if (!InvalidRid(ridEventMap)) + { + IfFailGo(pMiniMdImport->GetEventMapRecord(ridEventMap, &pEventMapRec)); + ridStart = pMiniMdImport->getEventListOfEventMap(pEventMapRec); + IfFailGo(pMiniMdImport->getEndEventListOfEventMap(ridEventMap, &ridEnd)); + + if (ridEnd > ridStart) + { + // If there is any event, create the eventmap record in the emit scope + // Create new record. + IfFailGo(pMiniMdEmit->AddEventMapRecord(&pEventMap, &iEventMap)); + + // Set parent. + IfFailGo(pMiniMdEmit->PutToken(TBL_EventMap, EventMapRec::COL_Parent, pEventMap, tdEmit)); + } + + for (i = ridStart; i < ridEnd; i++) + { + // get the real event rid + IfFailGo(pMiniMdImport->GetEventRid(i, (ULONG *)&evImp)); + + // only merge those Events that are marked + if ( pMiniMdImport->GetFilterTable()->IsEventMarked(TokenFromRid(evImp, mdtEvent)) == false) + continue; + + IfFailGo(pMiniMdImport->GetEventRecord(evImp, &pRecImport)); + IfFailGo(pMiniMdEmit->AddEventRecord(&pRecEmit, (RID *)&evEmit)); + + // copy the event record over + IfFailGo( CopyEvent(pImportData, pRecImport, pRecEmit) ); + + // Add Event to the EventMap. + IfFailGo( pMiniMdEmit->AddEventToEventMap(iEventMap, evEmit) ); + + // record the token movement + evImp = TokenFromRid(evImp, mdtEvent); + evEmit = TokenFromRid(evEmit, mdtEvent); + + IfFailGo( pCurTkMap->InsertNotFound(evImp, false, evEmit, &pTokenRec) ); + + // copy over the method semantics + IfFailGo( CopyMethodSemantics(pImportData, evImp, evEmit) ); + + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + evImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) { + pMTD->m_cEvents++; + } + } + } + + // make sure we don't count any events if merge check is suppressed on the type + _ASSERTE(pMTD->m_cEvents == 0 || !pMTD->m_bSuppressMergeCheck); +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyEvents() + + +//***************************************************************************** +// Copy Properties given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::CopyProperties( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + RID ridPropertyMap; + PropertyMapRec *pPropertyMapRec; + PropertyRec *pRecImport; + PropertyRec *pRecEmit; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + mdProperty prImp; + mdProperty prEmit; + TOKENREC *pTokenRec; + ULONG iPropertyMap; + PropertyMapRec *pPropertyMap; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + mdCustomAttribute tkCA; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + pCurTkMap = pImportData->m_pMDTokenMap; + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + // make sure we didn't count the properties yet + _ASSERTE(pMTD->m_cProperties == 0); + + IfFailGo(pMiniMdImport->FindPropertyMapFor(RidFromToken(tdImport), &ridPropertyMap)); + if (!InvalidRid(ridPropertyMap)) + { + IfFailGo(pMiniMdImport->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); + ridStart = pMiniMdImport->getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailGo(pMiniMdImport->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); + + if (ridEnd > ridStart) + { + // If there is any event, create the PropertyMap record in the emit scope + // Create new record. + IfFailGo(pMiniMdEmit->AddPropertyMapRecord(&pPropertyMap, &iPropertyMap)); + + // Set parent. + IfFailGo(pMiniMdEmit->PutToken(TBL_PropertyMap, PropertyMapRec::COL_Parent, pPropertyMap, tdEmit)); + } + + for (i = ridStart; i < ridEnd; i++) + { + // get the property rid + IfFailGo(pMiniMdImport->GetPropertyRid(i, (ULONG *)&prImp)); + + // only merge those Properties that are marked + if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(TokenFromRid(prImp, mdtProperty)) == false) + continue; + + + IfFailGo(pMiniMdImport->GetPropertyRecord(prImp, &pRecImport)); + IfFailGo(pMiniMdEmit->AddPropertyRecord(&pRecEmit, (RID *)&prEmit)); + + // copy the property record over + IfFailGo( CopyProperty(pImportData, pRecImport, pRecEmit) ); + + // Add Property to the PropertyMap. + IfFailGo( pMiniMdEmit->AddPropertyToPropertyMap(iPropertyMap, prEmit) ); + + // record the token movement + prImp = TokenFromRid(prImp, mdtProperty); + prEmit = TokenFromRid(prEmit, mdtProperty); + + IfFailGo( pCurTkMap->InsertNotFound(prImp, false, prEmit, &pTokenRec) ); + + // copy over the method semantics + IfFailGo( CopyMethodSemantics(pImportData, prImp, prEmit) ); + + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + prImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (!bSuppressMergeCheck) { + pMTD->m_cProperties++; + } + } + } + + // make sure we don't count any properties if merge check is suppressed on the type + _ASSERTE(pMTD->m_cProperties == 0 || !pMTD->m_bSuppressMergeCheck); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyProperties() + + +//***************************************************************************** +// Copy Parameters given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::CopyParams( + MergeImportData *pImportData, + mdMethodDef mdImport, + mdMethodDef mdEmit) +{ + HRESULT hr = NOERROR; + ParamRec *pRecImport = NULL; + ParamRec *pRecEmit = NULL; + MethodRec *pMethodRec; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG ridStart, ridEnd; + ULONG i; + mdParamDef pdEmit; + mdParamDef pdImp; + TOKENREC *pTokenRec; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + + IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImport), &pMethodRec)); + ridStart = pMiniMdImport->getParamListOfMethod(pMethodRec); + IfFailGo(pMiniMdImport->getEndParamListOfMethod(RidFromToken(mdImport), &ridEnd)); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // loop through all InterfaceImpl + for (i = ridStart; i < ridEnd; i++) + { + // Get the param rid + IfFailGo(pMiniMdImport->GetParamRid(i, (ULONG *)&pdImp)); + + // only merge those Params that are marked + if ( pMiniMdImport->GetFilterTable()->IsParamMarked(TokenFromRid(pdImp, mdtParamDef)) == false) + continue; + + + IfFailGo(pMiniMdImport->GetParamRecord(pdImp, &pRecImport)); + IfFailGo(pMiniMdEmit->AddParamRecord(&pRecEmit, (RID *)&pdEmit)); + + // copy the Parameter record over + IfFailGo( CopyParam(pImportData, pRecImport, pRecEmit) ); + + // warning!! warning!! + // We cannot add paramRec to method list until it is fully set. + // AddParamToMethod will use the ulSequence in the record + IfFailGo( pMiniMdEmit->AddParamToMethod(RidFromToken(mdEmit), pdEmit)); + + // record the token movement + pdImp = TokenFromRid(pdImp, mdtParamDef); + pdEmit = TokenFromRid(pdEmit, mdtParamDef); + + IfFailGo( pCurTkMap->InsertNotFound(pdImp, false, pdEmit, &pTokenRec) ); + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyParams() + + +//***************************************************************************** +// Copy GenericParams given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::CopyGenericParams( + MergeImportData *pImportData, + mdToken tkImport, + mdToken tkEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + TOKENREC *pTokenRec; + GenericParamRec *pRecImport = NULL; + GenericParamRec *pRecEmit = NULL; + MDTOKENMAP *pCurTkMap; + HENUMInternal hEnum; + mdGenericParam gpImport; + mdGenericParam gpEmit; + LPCSTR szGenericParamName; + + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pMiniMdEmit = GetMiniMdEmit(); + pCurTkMap = pImportData->m_pMDTokenMap; + + IfFailGo( pMiniMdImport->FindGenericParamHelper(tkImport, &hEnum) ); + + while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &gpImport)) + { + // Get the import GenericParam record + _ASSERTE(TypeFromToken(gpImport) == mdtGenericParam); + IfFailGo(pMiniMdImport->GetGenericParamRecord(RidFromToken(gpImport), &pRecImport)); + + // Create new emit record. + IfFailGo(pMiniMdEmit->AddGenericParamRecord(&pRecEmit, (RID *)&gpEmit)); + + // copy the GenericParam content + pRecEmit->SetNumber( pRecImport->GetNumber()); + pRecEmit->SetFlags( pRecImport->GetFlags()); + + IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParam, GenericParamRec::COL_Owner, pRecEmit, tkEmit)); + + IfFailGo(pMiniMdImport->getNameOfGenericParam(pRecImport, &szGenericParamName)); + IfFailGo( pMiniMdEmit->PutString(TBL_GenericParam, GenericParamRec::COL_Name, pRecEmit, szGenericParamName)); + + // record the token movement + gpImport = TokenFromRid(gpImport, mdtGenericParam); + gpEmit = TokenFromRid(gpEmit, mdtGenericParam); + + IfFailGo( pCurTkMap->InsertNotFound(gpImport, false, gpEmit, &pTokenRec) ); + + // copy over any constraints + IfFailGo( CopyGenericParamConstraints(pImportData, gpImport, gpEmit) ); + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyGenericParams() + + +//***************************************************************************** +// Copy GenericParamConstraints given a GenericParam +//***************************************************************************** +HRESULT NEWMERGER::CopyGenericParamConstraints( + MergeImportData *pImportData, + mdGenericParamConstraint tkImport, + mdGenericParamConstraint tkEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + TOKENREC *pTokenRec; + GenericParamConstraintRec *pRecImport = NULL; + GenericParamConstraintRec *pRecEmit = NULL; + MDTOKENMAP *pCurTkMap; + HENUMInternal hEnum; + mdGenericParamConstraint gpImport; + mdGenericParamConstraint gpEmit; + mdToken tkConstraint; + + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pMiniMdEmit = GetMiniMdEmit(); + pCurTkMap = pImportData->m_pMDTokenMap; + + IfFailGo( pMiniMdImport->FindGenericParamConstraintHelper(tkImport, &hEnum) ); + + while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &gpImport)) + { + // Get the import GenericParam record + _ASSERTE(TypeFromToken(gpImport) == mdtGenericParamConstraint); + IfFailGo(pMiniMdImport->GetGenericParamConstraintRecord(RidFromToken(gpImport), &pRecImport)); + + // Translate the constraint before creating new record. + tkConstraint = pMiniMdImport->getConstraintOfGenericParamConstraint(pRecImport); + if (pCurTkMap->Find(tkConstraint, &pTokenRec) == false) + { + // This should never fire unless the TypeDefs/Refs weren't merged + // before this code runs. + _ASSERTE(!"GenericParamConstraint Constraint not found in MERGER::CopyGenericParamConstraints. Bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + tkConstraint = pTokenRec->m_tkTo; + + // Create new emit record. + IfFailGo(pMiniMdEmit->AddGenericParamConstraintRecord(&pRecEmit, (RID *)&gpEmit)); + + // copy the GenericParamConstraint content + IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParamConstraint, GenericParamConstraintRec::COL_Owner, pRecEmit, tkEmit)); + + IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParamConstraint, GenericParamConstraintRec::COL_Constraint, pRecEmit, tkConstraint)); + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyGenericParamConstraints() + + +//***************************************************************************** +// Verify GenericParams given a TypeDef +//***************************************************************************** +HRESULT NEWMERGER::VerifyGenericParams( + MergeImportData *pImportData, + mdToken tkImport, + mdToken tkEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + TOKENREC *pTokenRec; + MDTOKENMAP *pCurTkMap; + HENUMInternal hEnumImport; // Enumerator for import scope. + HENUMInternal hEnumEmit; // Enumerator for emit scope. + ULONG cImport, cEmit; // Count of import & emit records. + ULONG i; // Enumerating records in import scope. + ULONG iEmit; // Tracking records in emit scope. + mdGenericParam gpImport; // Import scope GenericParam token. + mdGenericParam gpEmit; // Emit scope GenericParam token. + GenericParamRec *pRecImport = NULL; + GenericParamRec *pRecEmit = NULL; + LPCSTR szNameImport; // Name of param in import scope. + LPCSTR szNameEmit; // Name of param in emit scope. + + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pMiniMdEmit = GetMiniMdEmit(); + pCurTkMap = pImportData->m_pMDTokenMap; + + // Get enumerators for the input and output scopes. + IfFailGo(pMiniMdImport->FindGenericParamHelper(tkImport, &hEnumImport)); + IfFailGo(pMiniMdEmit->FindGenericParamHelper(tkEmit, &hEnumEmit)); + + // The counts should be the same. + IfFailGo(HENUMInternal::GetCount(&hEnumImport, &cImport)); + IfFailGo(HENUMInternal::GetCount(&hEnumEmit, &cEmit)); + + if (cImport != cEmit) + { + CheckContinuableErrorEx(META_E_GENERICPARAM_INCONSISTENT, pImportData, tkImport); + // If we are here, the linker says this error is OK. + } + + for (i=iEmit=0; i<cImport; ++i) + { + // Get the import GenericParam record + IfFailGo(HENUMInternal::GetElement(&hEnumImport, i, &gpImport)); + _ASSERTE(TypeFromToken(gpImport) == mdtGenericParam); + IfFailGo(pMiniMdImport->GetGenericParamRecord(RidFromToken(gpImport), &pRecImport)); + + // Find the emit record. If the import and emit scopes are ordered the same + // this is easy; otherwise go looking for it. + // Get the "next" emit record. + if (iEmit < cEmit) + { + IfFailGo(HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit)); + _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParam); + IfFailGo(pMiniMdEmit->GetGenericParamRecord(RidFromToken(gpEmit), &pRecEmit)); + } + + // If the import and emit sequence numbers don't match, go looking. + // Also, if we would have walked off end of array, go looking. + if (iEmit >= cEmit || pRecImport->GetNumber() != pRecEmit->GetNumber()) + { + for (iEmit=0; iEmit<cEmit; ++iEmit) + { + IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit)); + _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParam); + IfFailGo(pMiniMdEmit->GetGenericParamRecord(RidFromToken(gpEmit), &pRecEmit)); + + // The one we want? + if (pRecImport->GetNumber() == pRecEmit->GetNumber()) + break; + } + if (iEmit >= cEmit) + goto Error; // Didn't find it + } + + // Check that these "n'th" GenericParam records match. + + // Flags. + if (pRecImport->GetFlags() != pRecEmit->GetFlags()) + goto Error; + + // Name. + IfFailGo(pMiniMdImport->getNameOfGenericParam(pRecImport, &szNameImport)); + IfFailGo(pMiniMdEmit->getNameOfGenericParam(pRecEmit, &szNameEmit)); + if (strcmp(szNameImport, szNameEmit) != 0) + goto Error; + + // Verify any constraints. + gpImport = TokenFromRid(gpImport, mdtGenericParam); + gpEmit = TokenFromRid(gpEmit, mdtGenericParam); + hr = VerifyGenericParamConstraints(pImportData, gpImport, gpEmit); + + if (SUCCEEDED(hr)) + { + // record the token movement + IfFailGo( pCurTkMap->InsertNotFound(gpImport, true, gpEmit, &pTokenRec) ); + } + else + { +Error: + // inconsistent in GenericParams + hr = S_OK; // discard old error; new error will be returned from CheckContinuableError + CheckContinuableErrorEx(META_E_GENERICPARAM_INCONSISTENT, pImportData, tkImport); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyGenericParams() + + +//***************************************************************************** +// Verify GenericParamConstraints given a GenericParam +//***************************************************************************** +HRESULT NEWMERGER::VerifyGenericParamConstraints( + MergeImportData *pImportData, // The import scope. + mdGenericParam gpImport, // Import GenericParam. + mdGenericParam gpEmit) // Emit GenericParam. +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + TOKENREC *pTokenRec; + HENUMInternal hEnumImport; // Enumerator for import scope. + HENUMInternal hEnumEmit; // Enumerator for emit scope. + ULONG cImport, cEmit; // Count of import & emit records. + ULONG i; // Enumerating records in import scope. + ULONG iEmit; // Tracking records in emit scope. + GenericParamConstraintRec *pRecImport = NULL; + GenericParamConstraintRec *pRecEmit = NULL; + MDTOKENMAP *pCurTkMap; + mdToken tkConstraintImport = mdTokenNil; + mdToken tkConstraintEmit = mdTokenNil; + + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pMiniMdEmit = GetMiniMdEmit(); + pCurTkMap = pImportData->m_pMDTokenMap; + + // Get enumerators for the input and output scopes. + IfFailGo(pMiniMdImport->FindGenericParamConstraintHelper(gpImport, &hEnumImport)); + IfFailGo(pMiniMdEmit->FindGenericParamConstraintHelper(gpEmit, &hEnumEmit)); + + // The counts should be the same. + IfFailGo(HENUMInternal::GetCount(&hEnumImport, &cImport)); + IfFailGo(HENUMInternal::GetCount(&hEnumEmit, &cEmit)); + + if (cImport != cEmit) + IfFailGo(META_E_GENERICPARAM_INCONSISTENT); // Different numbers of constraints. + + for (i=iEmit=0; i<cImport; ++i) + { + // Get the import GenericParam record + IfFailGo( HENUMInternal::GetElement(&hEnumImport, i, &gpImport)); + _ASSERTE(TypeFromToken(gpImport) == mdtGenericParamConstraint); + IfFailGo(pMiniMdImport->GetGenericParamConstraintRecord(RidFromToken(gpImport), &pRecImport)); + + // Get the constraint. + tkConstraintImport = pMiniMdImport->getConstraintOfGenericParamConstraint(pRecImport); + if (pCurTkMap->Find(tkConstraintImport, &pTokenRec) == false) + { + // This should never fire unless the TypeDefs/Refs weren't merged + // before this code runs. + _ASSERTE(!"GenericParamConstraint Constraint not found in MERGER::VerifyGenericParamConstraints. Bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + tkConstraintImport = pTokenRec->m_tkTo; + + // Find the emit record. If the import and emit scopes are ordered the same + // this is easy; otherwise go looking for it. + // Get the "next" emit record. + if (iEmit < cEmit) + { + IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit)); + _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParamConstraint); + IfFailGo(pMiniMdEmit->GetGenericParamConstraintRecord(RidFromToken(gpEmit), &pRecEmit)); + tkConstraintEmit = pMiniMdEmit->getConstraintOfGenericParamConstraint(pRecEmit); + } + + // If the import and emit constraints don't match, go looking. + if (iEmit >= cEmit || tkConstraintEmit != tkConstraintImport) + { + for (iEmit=0; iEmit<cEmit; ++iEmit) + { + IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit)); + _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParamConstraint); + IfFailGo(pMiniMdEmit->GetGenericParamConstraintRecord(RidFromToken(gpEmit), &pRecEmit)); + tkConstraintEmit = pMiniMdEmit->getConstraintOfGenericParamConstraint(pRecEmit); + + // The one we want? + if (tkConstraintEmit == tkConstraintImport) + break; + } + if (iEmit >= cEmit) + { + IfFailGo(META_E_GENERICPARAM_INCONSISTENT); // Didn't find the constraint + } + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyGenericParamConstraints() + + +//***************************************************************************** +// Verify Methods +//***************************************************************************** +HRESULT NEWMERGER::VerifyMethods( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + MethodRec *pRecImp; + MethodRec *pRecEmit; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + + TypeDefRec *pTypeDefRec; + LPCUTF8 szName; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + TOKENREC *pTokenRec; + mdMethodDef mdImp; + mdMethodDef mdEmit; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + ULONG cImport = 0; // count of non-merge check suppressed methods + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // Get a count of records in the import scope; prepare to enumerate them. + IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec)); + ridStart = pMiniMdImport->getMethodListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMdImport->getEndMethodListOfTypeDef(RidFromToken(tdImport), &ridEnd)); + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + // loop through all Methods of the TypeDef + for (i = ridStart; i < ridEnd; i++) + { + IfFailGo(pMiniMdImport->GetMethodRid(i, (ULONG *)&mdImp)); + + // only verify those Methods that are marked + if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(TokenFromRid(mdImp, mdtMethodDef)) == false) + continue; + + IfFailGo(pMiniMdImport->GetMethodRecord(mdImp, &pRecImp)); + + if (m_fDupCheck == FALSE && tdImport == pImportData->m_pRegMetaImport->m_tdModule) // TokenFromRid(1, mdtTypeDef)) + { + // No dup check. This is the scenario that we only have one import scope. Just copy over the + // globals. + goto CopyMethodLabel; + } + + IfFailGo(pMiniMdImport->getNameOfMethod(pRecImp, &szName)); + IfFailGo(pMiniMdImport->getSignatureOfMethod(pRecImp, &pbSig, &cbSig)); + + mdImp = TokenFromRid(mdImp, mdtMethodDef); + + if ( IsMdPrivateScope( pRecImp->GetFlags() ) ) + { + // Trigger additive merge + goto CopyMethodLabel; + } + + // convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImport, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + hr = ImportHelper::FindMethod( + pMiniMdEmit, + tdEmit, + szName, + (const COR_SIGNATURE *)qbSig.Ptr(), + cbEmit, + &mdEmit); + + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + mdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (bSuppressMergeCheck || (tdImport == pImportData->m_pRegMetaImport->m_tdModule)) + { + // global functions! Make sure that we move over the non-duplicate global function + // declaration + // + if (hr == S_OK) + { + // found the duplicate + IfFailGo( VerifyMethod(pImportData, mdImp, mdEmit) ); + } + else + { +CopyMethodLabel: + // not a duplicate! Copy over the + IfFailGo(pMiniMdEmit->AddMethodRecord(&pRecEmit, (RID *)&mdEmit)); + + // copy the method content over + IfFailGo( CopyMethod(pImportData, pRecImp, pRecEmit) ); + + IfFailGo( pMiniMdEmit->AddMethodToTypeDef(RidFromToken(tdEmit), mdEmit)); + + // record the token movement + mdEmit = TokenFromRid(mdEmit, mdtMethodDef); + IfFailGo( pMiniMdEmit->AddMemberDefToHash( + mdEmit, + tdEmit) ); + + mdImp = TokenFromRid(mdImp, mdtMethodDef); + IfFailGo( pCurTkMap->InsertNotFound(mdImp, false, mdEmit, &pTokenRec) ); + + // copy over the children + IfFailGo( CopyParams(pImportData, mdImp, mdEmit) ); + IfFailGo( CopyGenericParams(pImportData, mdImp, mdEmit) ); + + } + } + else + { + if (hr == S_OK) + { + // Good! We are supposed to find a duplicate + IfFailGo( VerifyMethod(pImportData, mdImp, mdEmit) ); + } + else + { + // Oops! The typedef is duplicated but the method is not!! + hr = S_OK; // discard old error; new error will be returned from CheckContinuableError + CheckContinuableErrorEx(META_E_METHD_NOT_FOUND, pImportData, mdImp); + } + + cImport++; + } + } + + // The counts should be the same, unless this is <module> + if (cImport != pMTD->m_cMethods && tdImport != pImportData->m_pRegMetaImport->m_tdModule) + { + CheckContinuableErrorEx(META_E_METHOD_COUNTS, pImportData, tdImport); + // If we are here, the linker says this error is OK. + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyMethods() + + +//***************************************************************************** +// verify a duplicated method +//***************************************************************************** +HRESULT NEWMERGER::VerifyMethod( + MergeImportData *pImportData, + mdMethodDef mdImp, // [IN] the emit record to fill + mdMethodDef mdEmit) // [IN] the record to import +{ + HRESULT hr; + MethodRec *pRecImp; + MethodRec *pRecEmit; + TOKENREC *pTokenRec; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + IfFailGo( pCurTkMap->InsertNotFound(mdImp, true, mdEmit, &pTokenRec) ); + + IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImp), &pRecImp)); + + // We need to make sure that the impl flags are propagated . + // Rules are: if the first method has miForwardRef flag set but the new method does not, + // we want to disable the miForwardRef flag. If the one found in the emit scope does not have + // miForwardRef set and the second one doesn't either, we want to make sure that the rest of + // impl flags are the same. + // + if ( !IsMiForwardRef( pRecImp->GetImplFlags() ) ) + { + IfFailGo(pMiniMdEmit->GetMethodRecord(RidFromToken(mdEmit), &pRecEmit)); + if (!IsMiForwardRef(pRecEmit->GetImplFlags())) + { + // make sure the rest of ImplFlags are the same + if (pRecEmit->GetImplFlags() != pRecImp->GetImplFlags()) + { + // inconsistent in implflags + CheckContinuableErrorEx(META_E_METHDIMPL_INCONSISTENT, pImportData, mdImp); + } + } + else + { + // propagate the importing ImplFlags + pRecEmit->SetImplFlags(pRecImp->GetImplFlags()); + } + } + + // verify the children + IfFailGo( VerifyParams(pImportData, mdImp, mdEmit) ); + IfFailGo( VerifyGenericParams(pImportData, mdImp, mdEmit) ); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyMethod() + + +//***************************************************************************** +// Verify Fields +//***************************************************************************** +HRESULT NEWMERGER::VerifyFields( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + FieldRec *pRecImp; + FieldRec *pRecEmit; + mdFieldDef fdImp; + mdFieldDef fdEmit; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + + TypeDefRec *pTypeDefRec; + LPCUTF8 szName; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + TOKENREC *pTokenRec; + MDTOKENMAP *pCurTkMap; + + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + ULONG cImport = 0; // count of non-merge check suppressed fields + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // Get a count of records in the import scope; prepare to enumerate them. + IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec)); + ridStart = pMiniMdImport->getFieldListOfTypeDef(pTypeDefRec); + IfFailGo(pMiniMdImport->getEndFieldListOfTypeDef(RidFromToken(tdImport), &ridEnd)); + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + // loop through all fields of the TypeDef + for (i = ridStart; i < ridEnd; i++) + { + IfFailGo(pMiniMdImport->GetFieldRid(i, (ULONG *)&fdImp)); + + // only verify those fields that are marked + if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(fdImp, mdtFieldDef)) == false) + continue; + + IfFailGo(pMiniMdImport->GetFieldRecord(fdImp, &pRecImp)); + + if (m_fDupCheck == FALSE && tdImport == pImportData->m_pRegMetaImport->m_tdModule) + { + // No dup check. This is the scenario that we only have one import scope. Just copy over the + // globals. + goto CopyFieldLabel; + } + + IfFailGo(pMiniMdImport->getNameOfField(pRecImp, &szName)); + IfFailGo(pMiniMdImport->getSignatureOfField(pRecImp, &pbSig, &cbSig)); + + if ( IsFdPrivateScope(pRecImp->GetFlags())) + { + // Trigger additive merge + fdImp = TokenFromRid(fdImp, mdtFieldDef); + goto CopyFieldLabel; + } + + // convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImport, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + hr = ImportHelper::FindField( + pMiniMdEmit, + tdEmit, + szName, + (const COR_SIGNATURE *)qbSig.Ptr(), + cbEmit, + &fdEmit); + + fdImp = TokenFromRid(fdImp, mdtFieldDef); + + bSuppressMergeCheck = + (IsFdStatic(pRecImp->GetFlags()) && pMTD->m_bSuppressMergeCheck) || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + fdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (bSuppressMergeCheck || (tdImport == pImportData->m_pRegMetaImport->m_tdModule)) + { + // global data! Make sure that we move over the non-duplicate global function + // declaration + // + if (hr == S_OK) + { + // found the duplicate + IfFailGo( pCurTkMap->InsertNotFound(fdImp, true, fdEmit, &pTokenRec) ); + } + else + { +CopyFieldLabel: + // not a duplicate! Copy over the + IfFailGo(pMiniMdEmit->AddFieldRecord(&pRecEmit, (RID *)&fdEmit)); + + // copy the field record over + IfFailGo( CopyField(pImportData, pRecImp, pRecEmit) ); + + IfFailGo( pMiniMdEmit->AddFieldToTypeDef(RidFromToken(tdEmit), fdEmit)); + + // record the token movement + fdEmit = TokenFromRid(fdEmit, mdtFieldDef); + IfFailGo( pMiniMdEmit->AddMemberDefToHash( + fdEmit, + tdEmit) ); + + fdImp = TokenFromRid(fdImp, mdtFieldDef); + IfFailGo( pCurTkMap->InsertNotFound(fdImp, false, fdEmit, &pTokenRec) ); + } + } + else + { + if (hr == S_OK) + { + // Good! We are supposed to find a duplicate + IfFailGo( pCurTkMap->InsertNotFound(fdImp, true, fdEmit, &pTokenRec) ); + } + else + { + // Oops! The typedef is duplicated but the field is not!! + hr = S_OK; // discard old error; new error will be returned from CheckContinuableError + CheckContinuableErrorEx(META_E_FIELD_NOT_FOUND, pImportData, fdImp); + } + + cImport++; + } + } + + // The counts should be the same, unless this is <module> + if (cImport != pMTD->m_cFields && tdImport != pImportData->m_pRegMetaImport->m_tdModule) + { + CheckContinuableErrorEx(META_E_FIELD_COUNTS, pImportData, tdImport); + // If we are here, the linker says this error is OK. + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyFields() + + +//***************************************************************************** +// Verify Events +//***************************************************************************** +HRESULT NEWMERGER::VerifyEvents( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + RID ridEventMap, ridEventMapEmit; + EventMapRec *pEventMapRec; + EventRec *pRecImport; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + mdEvent evImport; + mdEvent evEmit; + TOKENREC *pTokenRec; + LPCUTF8 szName; + mdToken tkType; + MDTOKENMAP *pCurTkMap; + + EventMapRec *pEventMapEmit; + EventRec *pRecEmit; + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + ULONG cImport = 0; // count of non-merge check suppressed events + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + IfFailGo(pMiniMdImport->FindEventMapFor(RidFromToken(tdImport), &ridEventMap)); + if (!InvalidRid(ridEventMap)) + { + // Get a count of records already in emit scope. + IfFailGo(pMiniMdEmit->FindEventMapFor(RidFromToken(tdEmit), &ridEventMapEmit)); + + if (InvalidRid(ridEventMapEmit)) { + // If there is any event, create the eventmap record in the emit scope + // Create new record. + IfFailGo(pMiniMdEmit->AddEventMapRecord(&pEventMapEmit, &ridEventMapEmit)); + + // Set parent. + IfFailGo(pMiniMdEmit->PutToken(TBL_EventMap, EventMapRec::COL_Parent, pEventMapEmit, tdEmit)); + } + + // Get a count of records in the import scope; prepare to enumerate them. + IfFailGo(pMiniMdImport->GetEventMapRecord(ridEventMap, &pEventMapRec)); + ridStart = pMiniMdImport->getEventListOfEventMap(pEventMapRec); + IfFailGo(pMiniMdImport->getEndEventListOfEventMap(ridEventMap, &ridEnd)); + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + for (i = ridStart; i < ridEnd; i++) + { + // get the property rid + IfFailGo(pMiniMdImport->GetEventRid(i, (ULONG *)&evImport)); + + // only verify those Events that are marked + if ( pMiniMdImport->GetFilterTable()->IsEventMarked(TokenFromRid(evImport, mdtEvent)) == false) + continue; + + IfFailGo(pMiniMdImport->GetEventRecord(evImport, &pRecImport)); + IfFailGo(pMiniMdImport->getNameOfEvent(pRecImport, &szName)); + tkType = pMiniMdImport->getEventTypeOfEvent( pRecImport ); + IfFailGo( pCurTkMap->Remap(tkType, &tkType) ); + evImport = TokenFromRid( evImport, mdtEvent); + + hr = ImportHelper::FindEvent( + pMiniMdEmit, + tdEmit, + szName, + &evEmit); + + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + evImport, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (bSuppressMergeCheck) + { + + if (hr == S_OK ) + { + // Good. We found the matching event when we have a duplicate typedef + IfFailGo( pCurTkMap->InsertNotFound(evImport, true, evEmit, &pTokenRec) ); + } + else + { + // not a duplicate! Copy over the + IfFailGo(pMiniMdEmit->AddEventRecord(&pRecEmit, (RID *)&evEmit)); + + // copy the event record over + IfFailGo( CopyEvent(pImportData, pRecImport, pRecEmit) ); + + // Add Event to the EventMap. + IfFailGo( pMiniMdEmit->AddEventToEventMap(ridEventMapEmit, evEmit) ); + + // record the token movement + evEmit = TokenFromRid(evEmit, mdtEvent); + + IfFailGo( pCurTkMap->InsertNotFound(evImport, false, evEmit, &pTokenRec) ); + + // copy over the method semantics + IfFailGo( CopyMethodSemantics(pImportData, evImport, evEmit) ); + } + } + else + { + if (hr == S_OK ) + { + // Good. We found the matching event when we have a duplicate typedef + IfFailGo( pCurTkMap->InsertNotFound(evImport, true, evEmit, &pTokenRec) ); + } + else + { + // Oops! The typedef is duplicated but the event is not!! + hr = S_OK; // discard old error; new error will be returned from CheckContinuableError + CheckContinuableErrorEx(META_E_EVENT_NOT_FOUND, pImportData, evImport); + + } + + cImport++; + } + } + + // The counts should be the same, unless this is <module> + if (cImport != pMTD->m_cEvents && tdImport != pImportData->m_pRegMetaImport->m_tdModule) + { + CheckContinuableErrorEx(META_E_EVENT_COUNTS, pImportData, tdImport); + // If we are here, the linker says this error is OK. + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyEvents() + + +//***************************************************************************** +// Verify Properties +//***************************************************************************** +HRESULT NEWMERGER::VerifyProperties( + MergeImportData *pImportData, + mdTypeDef tdImport, + mdTypeDef tdEmit) +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + RID ridPropertyMap, ridPropertyMapEmit; + PropertyMapRec *pPropertyMapRec; + PropertyRec *pRecImport; + ULONG ridStart; + ULONG ridEnd; + ULONG i; + mdProperty prImp; + mdProperty prEmit; + TOKENREC *pTokenRec; + LPCUTF8 szName; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + MDTOKENMAP *pCurTkMap; + + PropertyMapRec *pPropertyMapEmit; + PropertyRec *pRecEmit; + MergeTypeData *pMTD; + BOOL bSuppressMergeCheck; + ULONG cImport = 0; // count of non-merge check suppressed properties + mdCustomAttribute tkCA; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + IfFailGo(pMiniMdImport->FindPropertyMapFor(RidFromToken(tdImport), &ridPropertyMap)); + if (!InvalidRid(ridPropertyMap)) + { + // Get a count of records already in emit scope. + IfFailGo(pMiniMdEmit->FindPropertyMapFor(RidFromToken(tdEmit), &ridPropertyMapEmit)); + + if (InvalidRid(ridPropertyMapEmit)) + { + // If there is any event, create the PropertyMap record in the emit scope + // Create new record. + IfFailGo(pMiniMdEmit->AddPropertyMapRecord(&pPropertyMapEmit, &ridPropertyMapEmit)); + + // Set parent. + IfFailGo(pMiniMdEmit->PutToken(TBL_PropertyMap, PropertyMapRec::COL_Parent, pPropertyMapEmit, tdEmit)); + } + + // Get a count of records in the import scope; prepare to enumerate them. + IfFailGo(pMiniMdImport->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec)); + ridStart = pMiniMdImport->getPropertyListOfPropertyMap(pPropertyMapRec); + IfFailGo(pMiniMdImport->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd)); + + pMTD = m_rMTDs.Get(RidFromToken(tdEmit)); + + for (i = ridStart; i < ridEnd; i++) + { + // get the property rid + IfFailGo(pMiniMdImport->GetPropertyRid(i, (ULONG *)&prImp)); + + // only verify those Properties that are marked + if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(TokenFromRid(prImp, mdtProperty)) == false) + continue; + + IfFailGo(pMiniMdImport->GetPropertyRecord(prImp, &pRecImport)); + IfFailGo(pMiniMdImport->getNameOfProperty(pRecImport, &szName)); + IfFailGo(pMiniMdImport->getTypeOfProperty(pRecImport, &pbSig, &cbSig)); + prImp = TokenFromRid( prImp, mdtProperty); + + // convert rid contained in signature to new scope + IfFailGo( ImportHelper::MergeUpdateTokenInSig( + NULL, // Emit assembly. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImport, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit) ); // number of bytes write to cbEmit + + hr = ImportHelper::FindProperty( + pMiniMdEmit, + tdEmit, + szName, + (PCCOR_SIGNATURE) qbSig.Ptr(), + cbEmit, + &prEmit); + + bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck || + ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) && + (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport, + prImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA))); + + if (bSuppressMergeCheck) + { + if (hr == S_OK) + { + // Good. We found the matching property when we have a duplicate typedef + IfFailGo( pCurTkMap->InsertNotFound(prImp, true, prEmit, &pTokenRec) ); + } + else + { + IfFailGo(pMiniMdEmit->AddPropertyRecord(&pRecEmit, (RID *)&prEmit)); + + // copy the property record over + IfFailGo( CopyProperty(pImportData, pRecImport, pRecEmit) ); + + // Add Property to the PropertyMap. + IfFailGo( pMiniMdEmit->AddPropertyToPropertyMap(ridPropertyMapEmit, prEmit) ); + + // record the token movement + prEmit = TokenFromRid(prEmit, mdtProperty); + + IfFailGo( pCurTkMap->InsertNotFound(prImp, false, prEmit, &pTokenRec) ); + + // copy over the method semantics + IfFailGo( CopyMethodSemantics(pImportData, prImp, prEmit) ); + } + } + else + { + if (hr == S_OK) + { + // Good. We found the matching property when we have a duplicate typedef + IfFailGo( pCurTkMap->InsertNotFound(prImp, true, prEmit, &pTokenRec) ); + } + else + { + hr = S_OK; // discard old error; new error will be returned from CheckContinuableError + CheckContinuableErrorEx(META_E_PROP_NOT_FOUND, pImportData, prImp); + } + + cImport++; + } + } + + // The counts should be the same, unless this is <module> + if (cImport != pMTD->m_cProperties && tdImport != pImportData->m_pRegMetaImport->m_tdModule) + { + CheckContinuableErrorEx(META_E_PROPERTY_COUNTS, pImportData, tdImport); + // If we are here, the linker says this error is OK. + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyProperties() + + +//***************************************************************************** +// Verify Parameters given a Method +//***************************************************************************** +HRESULT NEWMERGER::VerifyParams( + MergeImportData *pImportData, + mdMethodDef mdImport, + mdMethodDef mdEmit) +{ + HRESULT hr = NOERROR; + ParamRec *pRecImport = NULL; + ParamRec *pRecEmit = NULL; + MethodRec *pMethodRec; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG ridStart, ridEnd; + ULONG ridStartEmit, ridEndEmit; + ULONG cImport, cEmit; + ULONG i, j; + mdParamDef pdEmit = 0; + mdParamDef pdImp; + TOKENREC *pTokenRec; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + pCurTkMap = pImportData->m_pMDTokenMap; + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // Get count of params in import scope; prepare to enumerate. + IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImport), &pMethodRec)); + ridStart = pMiniMdImport->getParamListOfMethod(pMethodRec); + IfFailGo(pMiniMdImport->getEndParamListOfMethod(RidFromToken(mdImport), &ridEnd)); + cImport = ridEnd - ridStart; + + // Get count of params in emit scope; prepare to enumerate. + IfFailGo(pMiniMdEmit->GetMethodRecord(RidFromToken(mdEmit), &pMethodRec)); + ridStartEmit = pMiniMdEmit->getParamListOfMethod(pMethodRec); + IfFailGo(pMiniMdEmit->getEndParamListOfMethod(RidFromToken(mdEmit), &ridEndEmit)); + cEmit = ridEndEmit - ridStartEmit; + + // The counts should be the same. + if (cImport != cEmit) + { + // That is, unless this is <module>, so get the method's parent. + mdTypeDef tdImport; + IfFailGo(pMiniMdImport->FindParentOfMethodHelper(mdImport, &tdImport)); + if (tdImport != pImportData->m_pRegMetaImport->m_tdModule) + CheckContinuableErrorEx(META_E_PARAM_COUNTS, pImportData, mdImport); + // If we are here, the linker says this error is OK. + } + + // loop through all Parameters + for (i = ridStart; i < ridEnd; i++) + { + // Get the importing param row + IfFailGo(pMiniMdImport->GetParamRid(i, (ULONG *)&pdImp)); + + // only verify those Params that are marked + if ( pMiniMdImport->GetFilterTable()->IsParamMarked(TokenFromRid(pdImp, mdtParamDef)) == false) + continue; + + + IfFailGo(pMiniMdImport->GetParamRecord(pdImp, &pRecImport)); + pdImp = TokenFromRid(pdImp, mdtParamDef); + + // It turns out when we merge a typelib with itself, the emit and import scope + // has different sequence of parameter + // + // find the corresponding emit param row + for (j = ridStartEmit; j < ridEndEmit; j++) + { + IfFailGo(pMiniMdEmit->GetParamRid(j, (ULONG *)&pdEmit)); + IfFailGo(pMiniMdEmit->GetParamRecord(pdEmit, &pRecEmit)); + if (pRecEmit->GetSequence() == pRecImport->GetSequence()) + break; + } + + if (j == ridEndEmit) + { + // did not find the corresponding parameter in the emiting scope + hr = S_OK; // discard old error; new error will be returned from CheckContinuableError + CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp); + } + + else + { + _ASSERTE( pRecEmit->GetSequence() == pRecImport->GetSequence() ); + + pdEmit = TokenFromRid(pdEmit, mdtParamDef); + + // record the token movement +#ifdef WE_DONT_NEED_TO_CHECK_NAMES__THEY_DONT_AFFECT_ANYTHING + LPCUTF8 szNameImp; + LPCUTF8 szNameEmit; + IfFailGo(pMiniMdImport->getNameOfParam(pRecImport, &szNameImp)); + IfFailGo(pMiniMdEmit->getNameOfParam(pRecEmit, &szNameEmit)); + if (szNameImp && szNameEmit && strcmp(szNameImp, szNameEmit) != 0) + { + // parameter name doesn't match + CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp); + } +#endif + if (pRecEmit->GetFlags() != pRecImport->GetFlags()) + { + // flags doesn't match + CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp); + } + + // record token movement. This is a duplicate. + IfFailGo( pCurTkMap->InsertNotFound(pdImp, true, pdEmit, &pTokenRec) ); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::VerifyParams() + + +//***************************************************************************** +// merging MemberRef +//***************************************************************************** +HRESULT NEWMERGER::MergeMemberRefs( ) +{ + HRESULT hr = NOERROR; + MemberRefRec *pRecImport = NULL; + MemberRefRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdMemberRef mrEmit; + mdMemberRef mrImp; + bool bDuplicate = false; + TOKENREC *pTokenRec; + mdToken tkParentImp; + mdToken tkParentEmit; + + LPCUTF8 szNameImp; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + + bool isRefOptimizedToDef; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + iCount = pMiniMdImport->getCountMemberRefs(); + + // loop through all MemberRef + for (i = 1; i <= iCount; i++) + { + + // only merge those MemberRefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsMemberRefMarked(TokenFromRid(i, mdtMemberRef)) == false) + continue; + + isRefOptimizedToDef = false; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetMemberRefRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getNameOfMemberRef(pRecImport, &szNameImp)); + IfFailGo(pMiniMdImport->getSignatureOfMemberRef(pRecImport, &pbSig, &cbSig)); + tkParentImp = pMiniMdImport->getClassOfMemberRef(pRecImport); + + IfFailGo( pCurTkMap->Remap(tkParentImp, &tkParentEmit) ); + + // convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly information. + pMiniMdImport, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + // We want to know if we can optimize this MemberRef to a FieldDef or MethodDef + if (TypeFromToken(tkParentEmit) == mdtTypeDef && RidFromToken(tkParentEmit) != 0) + { + // The parent of this MemberRef has been successfully optimized to a TypeDef. Then this MemberRef should be + // be able to optimized to a MethodDef or FieldDef unless one of the parent in the inheritance hierachy + // is through TypeRef. Then this MemberRef stay as MemberRef. If This is a VarArg calling convention, then + // we will remap the MemberRef's parent to a MethodDef or stay as TypeRef. + // + mdToken tkParent = tkParentEmit; + mdToken tkMethDefOrFieldDef; + PCCOR_SIGNATURE pbSigTmp = (const COR_SIGNATURE *) qbSig.Ptr(); + + while (TypeFromToken(tkParent) == mdtTypeDef && RidFromToken(tkParent) != 0) + { + TypeDefRec *pRec; + hr = ImportHelper::FindMember(pMiniMdEmit, tkParent, szNameImp, pbSigTmp, cbEmit, &tkMethDefOrFieldDef); + if (hr == S_OK) + { + // We have found a match!! + if (isCallConv(CorSigUncompressCallingConv(pbSigTmp), IMAGE_CEE_CS_CALLCONV_VARARG)) + { + // The found MethodDef token will replace this MemberRef's parent token + _ASSERTE(TypeFromToken(tkMethDefOrFieldDef) == mdtMethodDef); + tkParentEmit = tkMethDefOrFieldDef; + break; + } + else + { + // The found MethodDef/FieldDef token will replace this MemberRef token and we won't introduce a MemberRef + // record. + // + mrEmit = tkMethDefOrFieldDef; + isRefOptimizedToDef = true; + bDuplicate = true; + break; + } + } + + // now walk up to the parent class of tkParent and try to resolve this MemberRef + IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(tkParent), &pRec)); + tkParent = pMiniMdEmit->getExtendsOfTypeDef(pRec); + } + + // When we exit the loop, there are several possibilities: + // 1. We found a MethodDef/FieldDef to replace the MemberRef + // 2. We found a MethodDef matches the MemberRef but the MemberRef is VarArg, thus we want to use the MethodDef in the + // parent column but not replacing it. + // 3. We exit because we run out the TypeDef on the parent chain. If it is because we encounter a TypeRef, this TypeRef will + // replace the parent column of the MemberRef. Or we encounter nil token! (This can be unresolved global MemberRef or + // compiler error to put an undefined MemberRef. In this case, we should just use the old tkParentEmit + // on the parent column for the MemberRef. + + if (TypeFromToken(tkParent) == mdtTypeRef && RidFromToken(tkParent) != 0) + { + // we had walked up the parent's chain to resolve it but we have not been successful and got stopped by a TypeRef. + // Then we will use this TypeRef as the parent of the emit MemberRef record + // + tkParentEmit = tkParent; + } + } + else if ((TypeFromToken(tkParentEmit) == mdtMethodDef && + !isCallConv(CorSigUncompressCallingConv(pbSig), IMAGE_CEE_CS_CALLCONV_VARARG)) || + (TypeFromToken(tkParentEmit) == mdtFieldDef)) + { + // If the MemberRef's parent is already a non-vararg MethodDef or FieldDef, we can also + // safely drop the MemberRef + mrEmit = tkParentEmit; + isRefOptimizedToDef = true; + bDuplicate = true; + } + + // If the Ref cannot be optimized to a Def or MemberRef to Def optmization is turned off, do the following. + if (isRefOptimizedToDef == false || !((m_optimizeRefToDef & MDMemberRefToDef) == MDMemberRefToDef)) + { + // does this MemberRef already exist in the emit scope? + if ( m_fDupCheck && ImportHelper::FindMemberRef( + pMiniMdEmit, + tkParentEmit, + szNameImp, + (const COR_SIGNATURE *) qbSig.Ptr(), + cbEmit, + &mrEmit) == S_OK ) + { + // Yes, it does + bDuplicate = true; + } + else + { + // No, it doesn't. Copy it over. + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddMemberRefRecord(&pRecEmit, (RID *)&mrEmit)); + mrEmit = TokenFromRid( mrEmit, mdtMemberRef ); + + // Copy over the MemberRef context + IfFailGo(pMiniMdEmit->PutString(TBL_MemberRef, MemberRefRec::COL_Name, pRecEmit, szNameImp)); + IfFailGo(pMiniMdEmit->PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pRecEmit, tkParentEmit)); + IfFailGo(pMiniMdEmit->PutBlob(TBL_MemberRef, MemberRefRec::COL_Signature, pRecEmit, + qbSig.Ptr(), cbEmit)); + IfFailGo(pMiniMdEmit->AddMemberRefToHash(mrEmit) ); + } + } + // record the token movement + mrImp = TokenFromRid(i, mdtMemberRef); + IfFailGo( pCurTkMap->InsertNotFound(mrImp, bDuplicate, mrEmit, &pTokenRec) ); + } + } + + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeMemberRefs() + + +//***************************************************************************** +// merge interface impl +//***************************************************************************** +HRESULT NEWMERGER::MergeInterfaceImpls( ) +{ + HRESULT hr = NOERROR; + InterfaceImplRec *pRecImport = NULL; + InterfaceImplRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdTypeDef tkParent; + mdInterfaceImpl iiEmit; + bool bDuplicate; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountInterfaceImpls(); + + // loop through all InterfaceImpl + for (i = 1; i <= iCount; i++) + { + // only merge those InterfaceImpls that are marked + if ( pMiniMdImport->GetFilterTable()->IsInterfaceImplMarked(TokenFromRid(i, mdtInterfaceImpl)) == false) + continue; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetInterfaceImplRecord(i, &pRecImport)); + tkParent = pMiniMdImport->getClassOfInterfaceImpl(pRecImport); + + // does this TypeRef already exist in the emit scope? + if ( pCurTkMap->Find(tkParent, &pTokenRec) ) + { + if ( pTokenRec->m_isDuplicate ) + { + // parent in the emit scope + mdToken tkParentEmit; + mdToken tkInterface; + + // remap the typedef token + tkParentEmit = pTokenRec->m_tkTo; + + // remap the implemented interface token + tkInterface = pMiniMdImport->getInterfaceOfInterfaceImpl(pRecImport); + IfFailGo( pCurTkMap->Remap( tkInterface, &tkInterface) ); + + // Set duplicate flag + bDuplicate = true; + + // find the corresponding interfaceimpl in the emit scope + if ( ImportHelper::FindInterfaceImpl(pMiniMdEmit, tkParentEmit, tkInterface, &iiEmit) != S_OK ) + { + // bad state!! We have a duplicate typedef but the interface impl is not the same!! + + // continuable error + CheckContinuableErrorEx( + META_E_INTFCEIMPL_NOT_FOUND, + pImportData, + TokenFromRid(i, mdtInterfaceImpl)); + + iiEmit = mdTokenNil; + } + } + else + { + // No, it doesn't. Copy it over. + bDuplicate = false; + IfFailGo(pMiniMdEmit->AddInterfaceImplRecord(&pRecEmit, (RID *)&iiEmit)); + + // copy the interfaceimp record over + IfFailGo( CopyInterfaceImpl( pRecEmit, pImportData, pRecImport) ); + } + } + else + { + _ASSERTE( !"bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + + // record the token movement + IfFailGo( pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtInterfaceImpl), + bDuplicate, + TokenFromRid( iiEmit, mdtInterfaceImpl ), + &pTokenRec) ); + } + } + + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeInterfaceImpls() + + +//***************************************************************************** +// merge all of the constant for field, property, and parameter +//***************************************************************************** +HRESULT NEWMERGER::MergeConstants() +{ + HRESULT hr = NOERROR; + ConstantRec *pRecImport = NULL; + ConstantRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + ULONG csEmit; // constant value is not a token + mdToken tkParentImp; + TOKENREC *pTokenRec; + void const *pValue; + ULONG cbBlob; +#if _DEBUG + ULONG typeParent; +#endif // _DEBUG + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountConstants(); + + // loop through all Constants + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetConstantRecord(i, &pRecImport)); + tkParentImp = pMiniMdImport->getParentOfConstant(pRecImport); + + // only move those constant over if their parents are marked + // If MDTOKENMAP::Find returns false, we don't need to copy the constant value over + if ( pCurTkMap->Find(tkParentImp, &pTokenRec) ) + { + // If the parent is duplicated, no need to move over the constant value + if ( !pTokenRec->m_isDuplicate ) + { + IfFailGo(pMiniMdEmit->AddConstantRecord(&pRecEmit, &csEmit)); + pRecEmit->SetType(pRecImport->GetType()); + + // set the parent + IfFailGo( pMiniMdEmit->PutToken(TBL_Constant, ConstantRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo) ); + + // move over the constant blob value + IfFailGo(pMiniMdImport->getValueOfConstant(pRecImport, (const BYTE **)&pValue, &cbBlob)); + IfFailGo( pMiniMdEmit->PutBlob(TBL_Constant, ConstantRec::COL_Value, pRecEmit, pValue, cbBlob) ); + IfFailGo( pMiniMdEmit->AddConstantToHash(csEmit) ); + } + else + { + // <TODO>@FUTURE: more verification on the duplicate??</TODO> + } + } +#if _DEBUG + // Include this block only under Debug build. The reason is that + // the linker chooses all the errors that we report (such as unmatched MethodDef or FieldDef) + // as a continuable error. It is likely to hit this else while the tkparentImp is marked if there + // is any error reported earlier!! + else + { + typeParent = TypeFromToken(tkParentImp); + if (typeParent == mdtFieldDef) + { + // FieldDef should not be marked. + if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkParentImp) == false) + continue; + } + else if (typeParent == mdtParamDef) + { + // ParamDef should not be marked. + if ( pMiniMdImport->GetFilterTable()->IsParamMarked(tkParentImp) == false) + continue; + } + else + { + _ASSERTE(typeParent == mdtProperty); + // Property should not be marked. + if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(tkParentImp) == false) + continue; + } + + // If we come to here, we have a constant whose parent is marked but we could not + // find it in the map!! Bad state. + + _ASSERTE(!"Ignore this error if you have seen error reported earlier! Otherwise bad token map or bad metadata!"); + } +#endif // _DEBUG + // Note that we don't need to record the token movement since constant is not a valid token kind. + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeConstants() + + +//***************************************************************************** +// Merge field marshal information +//***************************************************************************** +HRESULT NEWMERGER::MergeFieldMarshals() +{ + HRESULT hr = NOERROR; + FieldMarshalRec *pRecImport = NULL; + FieldMarshalRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + ULONG fmEmit; // FieldMarhsal is not a token + mdToken tkParentImp; + TOKENREC *pTokenRec; + void const *pValue; + ULONG cbBlob; +#if _DEBUG + ULONG typeParent; +#endif // _DEBUG + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountFieldMarshals(); + + // loop through all TypeRef + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetFieldMarshalRecord(i, &pRecImport)); + tkParentImp = pMiniMdImport->getParentOfFieldMarshal(pRecImport); + + // We want to merge only those field marshals that parents are marked. + // Find will return false if the parent is not marked + // + if ( pCurTkMap->Find(tkParentImp, &pTokenRec) ) + { + // If the parent is duplicated, no need to move over the constant value + if ( !pTokenRec->m_isDuplicate ) + { + IfFailGo(pMiniMdEmit->AddFieldMarshalRecord(&pRecEmit, &fmEmit)); + + // set the parent + IfFailGo( pMiniMdEmit->PutToken( + TBL_FieldMarshal, + FieldMarshalRec::COL_Parent, + pRecEmit, + pTokenRec->m_tkTo) ); + + // move over the constant blob value + IfFailGo(pMiniMdImport->getNativeTypeOfFieldMarshal(pRecImport, (const BYTE **)&pValue, &cbBlob)); + IfFailGo( pMiniMdEmit->PutBlob(TBL_FieldMarshal, FieldMarshalRec::COL_NativeType, pRecEmit, pValue, cbBlob) ); + IfFailGo( pMiniMdEmit->AddFieldMarshalToHash(fmEmit) ); + + } + else + { + // <TODO>@FUTURE: more verification on the duplicate??</TODO> + } + } +#if _DEBUG + else + { + typeParent = TypeFromToken(tkParentImp); + + if (typeParent == mdtFieldDef) + { + // FieldDefs should not be marked + if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkParentImp) == false) + continue; + } + else + { + _ASSERTE(typeParent == mdtParamDef); + // ParamDefs should not be marked + if ( pMiniMdImport->GetFilterTable()->IsParamMarked(tkParentImp) == false) + continue; + } + + // If we come to here, that is we have a FieldMarshal whose parent is marked and we don't find it + // in the map!!! + + // either bad lookup map or bad metadata + _ASSERTE(!"Ignore this assert if you have seen error reported earlier. Otherwise, it is bad state!"); + } +#endif // _DEBUG + } + // Note that we don't need to record the token movement since FieldMarshal is not a valid token kind. + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeFieldMarshals() + + +//***************************************************************************** +// Merge class layout information +//***************************************************************************** +HRESULT NEWMERGER::MergeClassLayouts() +{ + HRESULT hr = NOERROR; + ClassLayoutRec *pRecImport = NULL; + ClassLayoutRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + ULONG iRecord; // class layout is not a token + mdToken tkParentImp; + TOKENREC *pTokenRec; + RID ridClassLayout; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountClassLayouts(); + + // loop through all TypeRef + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetClassLayoutRecord(i, &pRecImport)); + tkParentImp = pMiniMdImport->getParentOfClassLayout(pRecImport); + + // only merge those TypeDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(tkParentImp) == false) + continue; + + if ( pCurTkMap->Find(tkParentImp, &pTokenRec) ) + { + if ( !pTokenRec->m_isDuplicate ) + { + // If the parent is not duplicated, just copy over the classlayout information + IfFailGo(pMiniMdEmit->AddClassLayoutRecord(&pRecEmit, &iRecord)); + + // copy over the fix part information + pRecEmit->Copy(pRecImport); + IfFailGo( pMiniMdEmit->PutToken(TBL_ClassLayout, ClassLayoutRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo)); + IfFailGo( pMiniMdEmit->AddClassLayoutToHash(iRecord) ); + } + else + { + + IfFailGo(pMiniMdEmit->FindClassLayoutHelper(pTokenRec->m_tkTo, &ridClassLayout)); + + if (InvalidRid(ridClassLayout)) + { + // class is duplicated but not class layout info + CheckContinuableErrorEx(META_E_CLASS_LAYOUT_INCONSISTENT, pImportData, tkParentImp); + } + else + { + IfFailGo(pMiniMdEmit->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRecEmit)); + if (pMiniMdImport->getPackingSizeOfClassLayout(pRecImport) != pMiniMdEmit->getPackingSizeOfClassLayout(pRecEmit) || + pMiniMdImport->getClassSizeOfClassLayout(pRecImport) != pMiniMdEmit->getClassSizeOfClassLayout(pRecEmit) ) + { + CheckContinuableErrorEx(META_E_CLASS_LAYOUT_INCONSISTENT, pImportData, tkParentImp); + } + } + } + } + else + { + // bad lookup map + _ASSERTE( !"bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + // no need to record the index movement. Classlayout is not a token. + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeClassLayouts() + +//***************************************************************************** +// Merge field layout information +//***************************************************************************** +HRESULT NEWMERGER::MergeFieldLayouts() +{ + HRESULT hr = NOERROR; + FieldLayoutRec *pRecImport = NULL; + FieldLayoutRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + ULONG iRecord; // field layout2 is not a token. + mdToken tkFieldImp; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountFieldLayouts(); + + // loop through all FieldLayout records. + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetFieldLayoutRecord(i, &pRecImport)); + tkFieldImp = pMiniMdImport->getFieldOfFieldLayout(pRecImport); + + // only merge those FieldDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkFieldImp) == false) + continue; + + if ( pCurTkMap->Find(tkFieldImp, &pTokenRec) ) + { + if ( !pTokenRec->m_isDuplicate ) + { + // If the Field is not duplicated, just copy over the FieldLayout information + IfFailGo(pMiniMdEmit->AddFieldLayoutRecord(&pRecEmit, &iRecord)); + + // copy over the fix part information + pRecEmit->Copy(pRecImport); + IfFailGo( pMiniMdEmit->PutToken(TBL_FieldLayout, FieldLayoutRec::COL_Field, pRecEmit, pTokenRec->m_tkTo)); + IfFailGo( pMiniMdEmit->AddFieldLayoutToHash(iRecord) ); + } + else + { + // <TODO>@FUTURE: more verification??</TODO> + } + } + else + { + // bad lookup map + _ASSERTE( !"bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + // no need to record the index movement. fieldlayout2 is not a token. + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeFieldLayouts() + + +//***************************************************************************** +// Merge field RVAs +//***************************************************************************** +HRESULT NEWMERGER::MergeFieldRVAs() +{ + HRESULT hr = NOERROR; + FieldRVARec *pRecImport = NULL; + FieldRVARec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + ULONG iRecord; // FieldRVA is not a token. + mdToken tkFieldImp; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountFieldRVAs(); + + // loop through all FieldRVA records. + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetFieldRVARecord(i, &pRecImport)); + tkFieldImp = pMiniMdImport->getFieldOfFieldRVA(pRecImport); + + // only merge those FieldDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(tkFieldImp, mdtFieldDef)) == false) + continue; + + if ( pCurTkMap->Find(tkFieldImp, &pTokenRec) ) + { + if ( !pTokenRec->m_isDuplicate ) + { + // If the Field is not duplicated, just copy over the FieldRVA information + IfFailGo(pMiniMdEmit->AddFieldRVARecord(&pRecEmit, &iRecord)); + + // copy over the fix part information + pRecEmit->Copy(pRecImport); + IfFailGo( pMiniMdEmit->PutToken(TBL_FieldRVA, FieldRVARec::COL_Field, pRecEmit, pTokenRec->m_tkTo)); + IfFailGo( pMiniMdEmit->AddFieldRVAToHash(iRecord) ); + } + else + { + // <TODO>@FUTURE: more verification??</TODO> + } + } + else + { + // bad lookup map + _ASSERTE( !"bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + // no need to record the index movement. FieldRVA is not a token. + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeFieldRVAs() + + +//***************************************************************************** +// Merge MethodImpl information +//***************************************************************************** +HRESULT NEWMERGER::MergeMethodImpls() +{ + HRESULT hr = NOERROR; + MethodImplRec *pRecImport = NULL; + MethodImplRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + RID iRecord; + mdTypeDef tkClassImp; + mdToken tkBodyImp; + mdToken tkDeclImp; + TOKENREC *pTokenRecClass; + mdToken tkBodyEmit; + mdToken tkDeclEmit; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountMethodImpls(); + + // loop through all the MethodImpls. + for (i = 1; i <= iCount; i++) + { + // only merge those MethodImpls that are marked. + if ( pMiniMdImport->GetFilterTable()->IsMethodImplMarked(i) == false) + continue; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetMethodImplRecord(i, &pRecImport)); + tkClassImp = pMiniMdImport->getClassOfMethodImpl(pRecImport); + tkBodyImp = pMiniMdImport->getMethodBodyOfMethodImpl(pRecImport); + tkDeclImp = pMiniMdImport->getMethodDeclarationOfMethodImpl(pRecImport); + + if ( pCurTkMap->Find(tkClassImp, &pTokenRecClass)) + { + // If the TypeDef is duplicated, no need to move over the MethodImpl record. + if ( !pTokenRecClass->m_isDuplicate ) + { + // Create a new record and set the data. + + // <TODO>@FUTURE: We might want to consider changing the error for the remap into a continuable error. + // Because we probably can continue merging for more data...</TODO> + + IfFailGo( pCurTkMap->Remap(tkBodyImp, &tkBodyEmit) ); + IfFailGo( pCurTkMap->Remap(tkDeclImp, &tkDeclEmit) ); + IfFailGo(pMiniMdEmit->AddMethodImplRecord(&pRecEmit, &iRecord)); + IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_Class, pRecEmit, pTokenRecClass->m_tkTo) ); + IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodBody, pRecEmit, tkBodyEmit) ); + IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodDeclaration, pRecEmit, tkDeclEmit) ); + IfFailGo( pMiniMdEmit->AddMethodImplToHash(iRecord) ); + } + else + { + // <TODO>@FUTURE: more verification on the duplicate??</TODO> + } + // No need to record the token movement, MethodImpl is not a token. + } + else + { + // either bad lookup map or bad metadata + _ASSERTE(!"bad state"); + IfFailGo( META_E_BADMETADATA ); + } + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeMethodImpls() + + +//***************************************************************************** +// Merge PInvoke +//***************************************************************************** +HRESULT NEWMERGER::MergePinvoke() +{ + HRESULT hr = NOERROR; + ImplMapRec *pRecImport = NULL; + ImplMapRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdModuleRef mrImp; + mdModuleRef mrEmit; + mdMethodDef mdImp; + RID mdImplMap; + TOKENREC *pTokenRecMR; + TOKENREC *pTokenRecMD; + + USHORT usMappingFlags; + LPCUTF8 szImportName; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountImplMaps(); + + // loop through all ImplMaps + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetImplMapRecord(i, &pRecImport)); + + // Get the MethodDef token in the new space. + mdImp = pMiniMdImport->getMemberForwardedOfImplMap(pRecImport); + + // only merge those MethodDefs that are marked + if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(mdImp) == false) + continue; + + // Get the ModuleRef token in the new space. + mrImp = pMiniMdImport->getImportScopeOfImplMap(pRecImport); + + // map the token to the new scope + if (pCurTkMap->Find(mrImp, &pTokenRecMR) == false) + { + // This should never fire unless the module refs weren't merged + // before this code ran. + _ASSERTE(!"Parent ModuleRef not found in MERGER::MergePinvoke. Bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + + // If the ModuleRef has been remapped to the "module token", we need to undo that + // for the pinvokeimpl. A pinvoke can only have a ModuleRef for the ImportScope. + mrEmit = pTokenRecMR->m_tkTo; + if (mrEmit == MODULEDEFTOKEN) + { // Yes, the ModuleRef has been remapped to the module token. So, + // find the ModuleRef in the output scope; if it is not found, add + // it. + ModuleRefRec *pModRefImport; + LPCUTF8 szNameImp; + IfFailGo(pMiniMdImport->GetModuleRefRecord(RidFromToken(mrImp), &pModRefImport)); + IfFailGo(pMiniMdImport->getNameOfModuleRef(pModRefImport, &szNameImp)); + + // does this ModuleRef already exist in the emit scope? + hr = ImportHelper::FindModuleRef(pMiniMdEmit, + szNameImp, + &mrEmit); + + if (hr == CLDB_E_RECORD_NOTFOUND) + { // No, it doesn't. Copy it over. + ModuleRefRec *pModRefEmit; + IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pModRefEmit, (RID*)&mrEmit)); + mrEmit = TokenFromRid(mrEmit, mdtModuleRef); + + // Set ModuleRef Name. + IfFailGo( pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, pModRefEmit, szNameImp) ); + } + else + IfFailGo(hr); + } + + + if (pCurTkMap->Find(mdImp, &pTokenRecMD) == false) + { + // This should never fire unless the method defs weren't merged + // before this code ran. + _ASSERTE(!"Parent MethodDef not found in MERGER::MergePinvoke. Bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + + + // Get copy of rest of data. + usMappingFlags = pMiniMdImport->getMappingFlagsOfImplMap(pRecImport); + IfFailGo(pMiniMdImport->getImportNameOfImplMap(pRecImport, &szImportName)); + + // If the method associated with PInvokeMap is not duplicated, then don't bother to look up the + // duplicated PInvokeMap information. + if (pTokenRecMD->m_isDuplicate == true) + { + // Does the correct ImplMap entry exist in the emit scope? + IfFailGo(pMiniMdEmit->FindImplMapHelper(pTokenRecMD->m_tkTo, &mdImplMap)); + } + else + { + mdImplMap = mdTokenNil; + } + if (!InvalidRid(mdImplMap)) + { + // Verify that the rest of the data is identical, else it's an error. + IfFailGo(pMiniMdEmit->GetImplMapRecord(mdImplMap, &pRecEmit)); + _ASSERTE(pMiniMdEmit->getMemberForwardedOfImplMap(pRecEmit) == pTokenRecMD->m_tkTo); + LPCSTR szImplMapImportName; + IfFailGo(pMiniMdEmit->getImportNameOfImplMap(pRecEmit, &szImplMapImportName)); + if (pMiniMdEmit->getImportScopeOfImplMap(pRecEmit) != mrEmit || + pMiniMdEmit->getMappingFlagsOfImplMap(pRecEmit) != usMappingFlags || + strcmp(szImplMapImportName, szImportName)) + { + // Mismatched p-invoke entries are found. + _ASSERTE(!"Mismatched P-invoke entries during merge. Bad State!"); + IfFailGo(E_FAIL); + } + } + else + { + IfFailGo(pMiniMdEmit->AddImplMapRecord(&pRecEmit, &mdImplMap)); + + // Copy rest of data. + IfFailGo( pMiniMdEmit->PutToken(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, pRecEmit, pTokenRecMD->m_tkTo) ); + IfFailGo( pMiniMdEmit->PutToken(TBL_ImplMap, ImplMapRec::COL_ImportScope, pRecEmit, mrEmit) ); + IfFailGo( pMiniMdEmit->PutString(TBL_ImplMap, ImplMapRec::COL_ImportName, pRecEmit, szImportName) ); + pRecEmit->SetMappingFlags(usMappingFlags); + IfFailGo( pMiniMdEmit->AddImplMapToHash(mdImplMap) ); + } + } + } + + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergePinvoke() + + +//***************************************************************************** +// Merge StandAloneSigs +//***************************************************************************** +HRESULT NEWMERGER::MergeStandAloneSigs() +{ + HRESULT hr = NOERROR; + StandAloneSigRec *pRecImport = NULL; + StandAloneSigRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + TOKENREC *pTokenRec; + mdSignature saImp; + mdSignature saEmit; + bool fDuplicate; + PCCOR_SIGNATURE pbSig; + ULONG cbSig; + ULONG cbEmit; + CQuickBytes qbSig; + PCOR_SIGNATURE rgSig; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountStandAloneSigs(); + + // loop through all Signatures + for (i = 1; i <= iCount; i++) + { + // only merge those Signatures that are marked + if ( pMiniMdImport->GetFilterTable()->IsSignatureMarked(TokenFromRid(i, mdtSignature)) == false) + continue; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetStandAloneSigRecord(i, &pRecImport)); + IfFailGo(pMiniMdImport->getSignatureOfStandAloneSig(pRecImport, &pbSig, &cbSig)); + + // This is a signature containing the return type after count of args + // convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Assembly import scope info. + pMiniMdImport, // The scope to merge into the emit scope. + pbSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + rgSig = ( PCOR_SIGNATURE ) qbSig.Ptr(); + + hr = ImportHelper::FindStandAloneSig( + pMiniMdEmit, + rgSig, + cbEmit, + &saEmit ); + if ( hr == S_OK ) + { + // find a duplicate + fDuplicate = true; + } + else + { + // copy over + fDuplicate = false; + IfFailGo(pMiniMdEmit->AddStandAloneSigRecord(&pRecEmit, (ULONG *)&saEmit)); + saEmit = TokenFromRid(saEmit, mdtSignature); + IfFailGo( pMiniMdEmit->PutBlob(TBL_StandAloneSig, StandAloneSigRec::COL_Signature, pRecEmit, rgSig, cbEmit)); + } + saImp = TokenFromRid(i, mdtSignature); + + // Record the token movement + IfFailGo( pCurTkMap->InsertNotFound(saImp, fDuplicate, saEmit, &pTokenRec) ); + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeStandAloneSigs() + +//***************************************************************************** +// Merge MethodSpecs +//***************************************************************************** +HRESULT NEWMERGER::MergeMethodSpecs() +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdToken tk; + ULONG iRecord; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + // Loop through all MethodSpec + iCount = pMiniMdImport->getCountMethodSpecs(); + for (i=1; i<=iCount; ++i) + { + MethodSpecRec *pRecImport; + MethodSpecRec *pRecEmit; + TOKENREC *pTokenRecMethod; + TOKENREC *pTokenRecMethodNew; + PCCOR_SIGNATURE pvSig; + ULONG cbSig; + CQuickBytes qbSig; + ULONG cbEmit; + + // Only copy marked records. + if (!pMiniMdImport->GetFilterTable()->IsMethodSpecMarked(i)) + continue; + + IfFailGo(pMiniMdImport->GetMethodSpecRecord(i, &pRecImport)); + tk = pMiniMdImport->getMethodOfMethodSpec(pRecImport); + + // Map the token to the new scope. + if (pCurTkMap->Find(tk, &pTokenRecMethod) == false) + { + // This should never fire unless the TypeDefs/Refs weren't merged + // before this code runs. + _ASSERTE(!"MethodSpec method not found in MERGER::MergeGenericsInfo. Bad state!"); + IfFailGo( META_E_BADMETADATA ); + } + // Copy to output scope. + IfFailGo(pMiniMdEmit->AddMethodSpecRecord(&pRecEmit, &iRecord)); + IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSpec, MethodSpecRec::COL_Method, pRecEmit, pTokenRecMethod->m_tkTo)); + + // Copy the signature, translating any embedded tokens. + IfFailGo(pMiniMdImport->getInstantiationOfMethodSpec(pRecImport, &pvSig, &cbSig)); + + // ...convert rid contained in signature to new scope + IfFailGo(ImportHelper::MergeUpdateTokenInSig( + NULL, // Assembly emit scope. + pMiniMdEmit, // The emit scope. + NULL, NULL, 0, // Import assembly scope information. + pMiniMdImport, // The scope to merge into the emit scope. + pvSig, // signature from the imported scope + pCurTkMap, // Internal token mapping structure. + &qbSig, // [OUT] translated signature + 0, // start from first byte of the signature + 0, // don't care how many bytes consumed + &cbEmit)); // number of bytes write to cbEmit + + // ...persist the converted signature + IfFailGo( pMiniMdEmit->PutBlob(TBL_MethodSpec, MethodSpecRec::COL_Instantiation, pRecEmit, qbSig.Ptr(), cbEmit) ); + + IfFailGo( pCurTkMap->InsertNotFound(TokenFromRid(i, mdtMethodSpec), false, + TokenFromRid(iRecord, mdtMethodSpec), &pTokenRecMethodNew) ); + } + } + + ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeMethodSpecs() + +//***************************************************************************** +// Merge DeclSecuritys +//***************************************************************************** +HRESULT NEWMERGER::MergeDeclSecuritys() +{ + HRESULT hr = NOERROR; + DeclSecurityRec *pRecImport = NULL; + DeclSecurityRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdToken tkParentImp; + TOKENREC *pTokenRec; + void const *pValue; + ULONG cbBlob; + mdPermission pmImp; + mdPermission pmEmit; + bool fDuplicate; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountDeclSecuritys(); + + // loop through all DeclSecurity + for (i = 1; i <= iCount; i++) + { + // only merge those DeclSecurities that are marked + if ( pMiniMdImport->GetFilterTable()->IsDeclSecurityMarked(TokenFromRid(i, mdtPermission)) == false) + continue; + + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetDeclSecurityRecord(i, &pRecImport)); + tkParentImp = pMiniMdImport->getParentOfDeclSecurity(pRecImport); + if ( pCurTkMap->Find(tkParentImp, &pTokenRec) ) + { + if ( !pTokenRec->m_isDuplicate ) + { + // If the parent is not duplicated, just copy over the custom value + goto CopyPermission; + } + else + { + // Try to see if the Permission is there in the emit scope or not. + // If not, move it over still + if ( ImportHelper::FindPermission( + pMiniMdEmit, + pTokenRec->m_tkTo, + pRecImport->GetAction(), + &pmEmit) == S_OK ) + { + // found a match + // <TODO>@FUTURE: more verification??</TODO> + fDuplicate = true; + } + else + { + // Parent is duplicated but the Permission is not. Still copy over the + // Permission. +CopyPermission: + fDuplicate = false; + IfFailGo(pMiniMdEmit->AddDeclSecurityRecord(&pRecEmit, (ULONG *)&pmEmit)); + pmEmit = TokenFromRid(pmEmit, mdtPermission); + + pRecEmit->Copy(pRecImport); + + // set the parent + IfFailGo( pMiniMdEmit->PutToken( + TBL_DeclSecurity, + DeclSecurityRec::COL_Parent, + pRecEmit, + pTokenRec->m_tkTo) ); + + // move over the CustomAttribute blob value + IfFailGo(pMiniMdImport->getPermissionSetOfDeclSecurity(pRecImport, (const BYTE **)&pValue, &cbBlob)); + IfFailGo(pMiniMdEmit->PutBlob( + TBL_DeclSecurity, + DeclSecurityRec::COL_PermissionSet, + pRecEmit, + pValue, + cbBlob)); + } + } + pmEmit = TokenFromRid(pmEmit, mdtPermission); + pmImp = TokenFromRid(i, mdtPermission); + + // Record the token movement + IfFailGo( pCurTkMap->InsertNotFound(pmImp, fDuplicate, pmEmit, &pTokenRec) ); + } + else + { + // bad lookup map + _ASSERTE(!"bad state"); + IfFailGo( META_E_BADMETADATA ); + } + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeDeclSecuritys() + + +//***************************************************************************** +// Merge Strings +//***************************************************************************** +HRESULT NEWMERGER::MergeStrings() +{ + HRESULT hr = NOERROR; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + for (UINT32 nIndex = 0; ;) + { + MetaData::DataBlob userString; + UINT32 nNextIndex; + UINT32 nEmitIndex; + + hr = pMiniMdImport->GetUserStringAndNextIndex( + nIndex, + &userString, + &nNextIndex); + IfFailGo(hr); + if (hr == S_FALSE) + { // We reached the last user string + hr = S_OK; + break; + } + _ASSERTE(hr == S_OK); + + // Skip empty strings + if (userString.IsEmpty()) + { + nIndex = nNextIndex; + continue; + } + + if (pMiniMdImport->GetFilterTable()->IsUserStringMarked(TokenFromRid(nIndex, mdtString)) == false) + { + // Process next user string in the heap + nIndex = nNextIndex; + continue; + } + + IfFailGo(pMiniMdEmit->PutUserString( + userString, + &nEmitIndex)); + + IfFailGo(pCurTkMap->InsertNotFound( + TokenFromRid(nIndex, mdtString), + false, + TokenFromRid(nEmitIndex, mdtString), + &pTokenRec)); + + // Process next user string in the heap + nIndex = nNextIndex; + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeStrings() + +// Helper method to merge the module-level security critical attributes +// Strips all module-level security critical attribute [that won't be ultimately needed] +// Returns: +// FAILED(hr): Failure occurred retrieving metadata or parsing scopes +// S_OK: Attribute should be merged into final output scope +// S_FALSE: Attribute should be ignored/dropped from output scope +HRESULT NEWMERGER::MergeSecurityCriticalModuleLevelAttributes( + MergeImportData* pImportData, // import scope + mdToken tkParentImp, // parent token with attribute + TOKENREC* pTypeRec, // token record of attribute ctor + mdToken mrSecurityTreatAsSafeAttributeCtor, // 'generic' TAS attribute token + mdToken mrSecurityTransparentAttributeCtor, // 'generic' Transparent attribute token + mdToken mrSecurityCriticalExplicitAttributeCtor, // 'generic' Critical attribute token + mdToken mrSecurityCriticalEverythingAttributeCtor) +{ + HRESULT hr = S_OK; + + // if ANY assembly-level critical attributes were specified, then we'll output + // one assembly-level Critical(Explicit) attribute only + // AND if this scope has tags + if (ISSCS_Unknown != pImportData->m_isscsSecurityCriticalStatus) + { + _ASSERTE(ISSCS_Unknown != m_isscsSecurityCritical); + // drop only assembly-level attributes + TypeRefRec* pTypeRefRec; + // metadata emitter + CMiniMdRW* pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // if compiler is generating a module - then this will be a module token + LPCSTR szTypeRefName; + if (tkParentImp == MODULEDEFTOKEN || + // otherwise, if merging assemblies, we have a fake type ref called MODULE_CA_LOCATION + (TypeFromToken(tkParentImp) == mdtTypeRef && + (IsAttributeFromNamespace(pMiniMdImport, tkParentImp, + COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME, + &pTypeRefRec) == S_OK) && + (pMiniMdImport->getNameOfTypeRef(pTypeRefRec, &szTypeRefName) == S_OK) && + (strcmp(MODULE_CA_TYPENAME, szTypeRefName) == 0))) + { + // drop the TAS attribute (unless all scopes have TAS) + if ( pTypeRec->m_tkTo == mrSecurityTreatAsSafeAttributeCtor ) + { + if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTreatAsSafe) == + ISSCS_SecurityTreatAsSafe) + { + _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityTreatAsSafe) == + ISSCS_SecurityTreatAsSafe); + return S_OK; + } + return S_FALSE; + } + // drop the Transparent attribute (unless all scopes have Transparent) + else if (pTypeRec->m_tkTo == mrSecurityTransparentAttributeCtor) + { + if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTransparent) == + ISSCS_SecurityTransparent) + { + _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityTransparent) == + ISSCS_SecurityTransparent); + return S_OK; + } + return S_FALSE; + } + else if (pTypeRec->m_tkTo == mrSecurityCriticalExplicitAttributeCtor) + { + // if NOT Critical Everything, then leave the Critical.Explicit attribute + // the Critical.Explicit attribute will be used as the final global attribute + if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) != + ISSCS_SecurityCriticalEverything) + { + _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityCriticalExplicit) == + ISSCS_SecurityCriticalExplicit); + return S_OK; + } + else + { + // drop this attribute + return S_FALSE; + } + } + else if (pTypeRec->m_tkTo == mrSecurityCriticalEverythingAttributeCtor) + { + // OPTIMIZATION: if all attributes are Critical.Everything, + // then leave the global Critical attribute + if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) == + ISSCS_SecurityCriticalEverything) + { + _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityCriticalEverything) == + ISSCS_SecurityCriticalEverything); + return S_OK; + } + else + { + // drop this attribute + return S_FALSE; + } + } + } + } + + return hr; +} // NEWMERGER::MergeSecurityCriticalModuleLevelAttributes + +// HELPER: Retrieve the meta-data info related to SecurityCritical +HRESULT NEWMERGER::RetrieveStandardSecurityCriticalMetaData( + mdAssemblyRef& tkMscorlib, + mdTypeRef& securityEnum, + BYTE*& rgSigBytesSecurityCriticalEverythingCtor, + DWORD& dwSigEverythingSize, + BYTE*& rgSigBytesSecurityCriticalExplicitCtor, + DWORD& dwSigExplicitSize) +{ + HRESULT hr = S_OK; + + CMiniMdRW* emit = GetMiniMdEmit(); + + // get typeref for mscorlib + BYTE pbMscorlibToken[] = COR_MSCORLIB_TYPEREF; + BYTE* pCurr = rgSigBytesSecurityCriticalEverythingCtor; + + IfFailGo(ImportHelper::FindAssemblyRef(emit, + COR_MSCORLIB_NAME, + NULL, + pbMscorlibToken, + sizeof(pbMscorlibToken), + asm_rmj, + asm_rmm, + asm_rup, + asm_rpt, + 0, + &tkMscorlib)); + + IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(tkMscorlib, + COR_SECURITYCRITICALSCOPE_ENUM_W, + &securityEnum)); + + // build the constructor sig that takes SecurityCriticalScope argument + if (rgSigBytesSecurityCriticalEverythingCtor) + { + *pCurr++ = IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS; + *pCurr++ = COR_SECURITYCRITICAL_CTOR_ARGCOUNT_SCOPE_EVERYTHING; // one argument to constructor + *pCurr++ = ELEMENT_TYPE_VOID; + *pCurr++ = ELEMENT_TYPE_VALUETYPE; + pCurr += CorSigCompressToken(securityEnum, pCurr); + dwSigEverythingSize = (DWORD)(pCurr - rgSigBytesSecurityCriticalEverythingCtor); + _ASSERTE(dwSigEverythingSize <= COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE); + } + + // if Explicit ctor is requested + if (rgSigBytesSecurityCriticalExplicitCtor) + { + // build the constructor sig that has NO arguments + pCurr = rgSigBytesSecurityCriticalExplicitCtor; + *pCurr++ = IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS; + *pCurr++ = COR_SECURITYCRITICAL_CTOR_ARGCOUNT_NO_SCOPE; // no arguments to constructor + *pCurr++ = ELEMENT_TYPE_VOID; + dwSigExplicitSize = (DWORD)(pCurr - rgSigBytesSecurityCriticalExplicitCtor); + _ASSERTE(dwSigExplicitSize <= COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE); + } + +ErrExit: + return hr; +} // NEWMERGER::RetrieveStandardSecurityCriticalMetaData + +//***************************************************************************** +// Merge CustomAttributes +//***************************************************************************** +HRESULT NEWMERGER::MergeCustomAttributes() +{ + + HRESULT hr = NOERROR; + CustomAttributeRec *pRecImport = NULL; + CustomAttributeRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + ULONG iCount; + ULONG i; + mdToken tkParentImp; // Token of attributed object (parent). + TOKENREC *pTokenRec; // Parent's remap. + mdToken tkType; // Token of attribute's type. + TOKENREC *pTypeRec; // Type's remap. + void const *pValue; // The actual value. + ULONG cbBlob; // Size of the value. + mdToken cvImp; + mdToken cvEmit; + bool fDuplicate; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + TypeRefRec *pTypeRefRec; + ULONG cTypeRefRecs; + mdToken mrSuppressMergeCheckAttributeCtor = mdTokenNil; + mdToken mrSecurityCriticalExplicitAttributeCtor = mdTokenNil; + mdToken mrSecurityCriticalEverythingAttributeCtor = mdTokenNil; + mdToken mrSecurityTransparentAttributeCtor = mdTokenNil; + mdToken mrSecurityTreatAsSafeAttributeCtor = mdTokenNil; + + pMiniMdEmit = GetMiniMdEmit(); + + // Find out the TypeRef referring to our library's System.CompilerServices.SuppressMergeCheckAttribute, + // System.Security.SecurityCriticalAttribute, System.Security.SecurityTransparentAttribute, and + // System.Security.SecurityTreatAsSafeAttibute + cTypeRefRecs = pMiniMdEmit->getCountTypeRefs(); + + { // retrieve global attribute TypeRefs + + mdAssemblyRef tkMscorlib = mdTokenNil; + mdTypeRef securityEnum = mdTokenNil; + + NewArrayHolder<BYTE> rgSigBytesSecurityCriticalEverythingCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE]); + BYTE* pSigBytesSecurityCriticalEverythingCtor = rgSigBytesSecurityCriticalEverythingCtor.GetValue(); + IfFailGo((pSigBytesSecurityCriticalEverythingCtor == NULL)?E_OUTOFMEMORY:S_OK); + DWORD dwSigEverythingSize = 0; + + NewArrayHolder<BYTE> rgSigBytesSecurityCriticalExplicitCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE]); + BYTE* pSigBytesSecurityCriticalExplicitCtor = rgSigBytesSecurityCriticalExplicitCtor.GetValue(); + IfFailGo((pSigBytesSecurityCriticalExplicitCtor == NULL)?E_OUTOFMEMORY:S_OK); + DWORD dwSigExplicitSize = 0; + + // retrieve security critical metadata info if necessary + if(ISSCS_Unknown != m_isscsSecurityCritical) + { + + hr = RetrieveStandardSecurityCriticalMetaData( + tkMscorlib, + securityEnum, + pSigBytesSecurityCriticalEverythingCtor, + dwSigEverythingSize, + pSigBytesSecurityCriticalExplicitCtor, + dwSigExplicitSize); + + } + + // Search for the TypeRef. + for (i = 1; i <= cTypeRefRecs; i++) + { + mdToken tkTmp = TokenFromRid(i,mdtTypeRef); + + if (IsAttributeFromNamespace(pMiniMdEmit, tkTmp, + COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME, + &pTypeRefRec) == S_OK) + { + LPCSTR szNameOfTypeRef; + IfFailGo(pMiniMdEmit->getNameOfTypeRef(pTypeRefRec, &szNameOfTypeRef)); + if (strcmp(szNameOfTypeRef, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE) == 0) + { + hr = ImportHelper::FindMemberRef( + pMiniMdEmit, tkTmp, + COR_CTOR_METHOD_NAME, + NULL, 0, + &mrSuppressMergeCheckAttributeCtor); + if (S_OK == hr) continue; + } + } + else + // if we are merging security critical attributes, then look for transparent-related attributes + if ((ISSCS_Unknown != m_isscsSecurityCritical) && + (IsAttributeFromNamespace(pMiniMdEmit, tkTmp, + COR_SECURITYCRITICAL_ATTRIBUTE_NAMESPACE, COR_MSCORLIB_NAME, + &pTypeRefRec) == S_OK)) + { + LPCSTR szNameOfTypeRef; + IfFailGo(pMiniMdEmit->getNameOfTypeRef(pTypeRefRec, &szNameOfTypeRef)); + + // look for the SecurityCritical attribute + if (strcmp(szNameOfTypeRef, COR_SECURITYCRITICAL_ATTRIBUTE) == 0) + { + // since the SecurityCritical attribute can be either + // parameterless constructor or SecurityCriticalScope constructor, we + // look for both + hr = ImportHelper::FindMemberRef( + pMiniMdEmit, tkTmp, + COR_CTOR_METHOD_NAME, + rgSigBytesSecurityCriticalEverythingCtor.GetValue(), dwSigEverythingSize, + &mrSecurityCriticalEverythingAttributeCtor); + if (S_OK == hr) continue; + hr = ImportHelper::FindMemberRef( + pMiniMdEmit, tkTmp, + COR_CTOR_METHOD_NAME, + rgSigBytesSecurityCriticalExplicitCtor.GetValue(), dwSigExplicitSize, + &mrSecurityCriticalExplicitAttributeCtor); + if (S_OK == hr) continue; + } + else + // look for the SecurityTransparent attribute + if (strcmp(szNameOfTypeRef, COR_SECURITYTRANSPARENT_ATTRIBUTE) == 0) + { + hr = ImportHelper::FindMemberRef( + pMiniMdEmit, tkTmp, + COR_CTOR_METHOD_NAME, + NULL, 0, + &mrSecurityTransparentAttributeCtor); + if (S_OK == hr) continue; + } + else + // look for the SecurityTreatAsSafe attribute + if (strcmp(szNameOfTypeRef, COR_SECURITYTREATASSAFE_ATTRIBUTE) == 0) + { + hr = ImportHelper::FindMemberRef( + pMiniMdEmit, tkTmp, + COR_CTOR_METHOD_NAME, + NULL, 0, + &mrSecurityTreatAsSafeAttributeCtor); + if (S_OK == hr) continue; + } + } + hr = S_OK; // ignore failures since the attribute may not be used + } + } + + // Loop over every module scope + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // We know that the filter table is not null here. Tell PREFIX that we know it. + PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL ); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountCustomAttributes(); + + // loop through all CustomAttribute + for (i = 1; i <= iCount; i++) + { + // compare it with the emit scope + IfFailGo(pMiniMdImport->GetCustomAttributeRecord(i, &pRecImport)); + tkParentImp = pMiniMdImport->getParentOfCustomAttribute(pRecImport); + tkType = pMiniMdImport->getTypeOfCustomAttribute(pRecImport); + IfFailGo(pMiniMdImport->getValueOfCustomAttribute(pRecImport, (const BYTE **)&pValue, &cbBlob)); + + // only merge those CustomAttributes that are marked + if ( pMiniMdImport->GetFilterTable()->IsCustomAttributeMarked(TokenFromRid(i, mdtCustomAttribute)) == false) + continue; + + // Check the type of the CustomAttribute. If it is not marked, then we don't need to move over the CustomAttributes. + // This will only occur for compiler defined discardable CAs during linking. + // + if ( pMiniMdImport->GetFilterTable()->IsTokenMarked(tkType) == false) + continue; + + if ( pCurTkMap->Find(tkParentImp, &pTokenRec) ) + { + // If the From token type is different from the To token's type, we have optimized the ref to def. + // In this case, we are dropping the CA associated with the Ref tokens. + // + if (TypeFromToken(tkParentImp) == TypeFromToken(pTokenRec->m_tkTo)) + { + + // If tkParentImp is a MemberRef and it is also mapped to a MemberRef in the merged scope with a MethodDef + // parent, then it is a MemberRef optimized to a MethodDef. We are keeping the MemberRef because it is a + // vararg call. So we can drop CAs on this MemberRef. + if (TypeFromToken(tkParentImp) == mdtMemberRef) + { + MemberRefRec *pTempRec; + IfFailGo(pMiniMdEmit->GetMemberRefRecord(RidFromToken(pTokenRec->m_tkTo), &pTempRec)); + if (TypeFromToken(pMiniMdEmit->getClassOfMemberRef(pTempRec)) == mdtMethodDef) + continue; + } + + + if (! pCurTkMap->Find(tkType, &pTypeRec) ) + { + _ASSERTE(!"CustomAttribute Type not found in output scope"); + IfFailGo(META_E_BADMETADATA); + } + + // Determine if we need to copy or ignore security-critical-related attributes + hr = MergeSecurityCriticalModuleLevelAttributes( + pImportData, tkParentImp, pTypeRec, + mrSecurityTreatAsSafeAttributeCtor, mrSecurityTransparentAttributeCtor, + mrSecurityCriticalExplicitAttributeCtor, + mrSecurityCriticalEverythingAttributeCtor); + IfFailGo(hr); + // S_FALSE means skip attribute + if (hr == S_FALSE) continue; + // S_OK means consider copying attribute + + // if it's the SuppressMergeCheckAttribute, don't copy it + if ( pTypeRec->m_tkTo == mrSuppressMergeCheckAttributeCtor ) + { + continue; + } + + if ( pTokenRec->m_isDuplicate) + { + // Try to see if the custom value is there in the emit scope or not. + // If not, move it over still + hr = ImportHelper::FindCustomAttributeByToken( + pMiniMdEmit, + pTokenRec->m_tkTo, + pTypeRec->m_tkTo, + pValue, + cbBlob, + &cvEmit); + + if ( hr == S_OK ) + { + // found a match + // <TODO>@FUTURE: more verification??</TODO> + fDuplicate = true; + } + else + { + TypeRefRec *pAttributeTypeRefRec; + // We need to allow additive merge on TypeRef for CustomAttributes because compiler + // could build module but not assembly. They are hanging of Assembly level CAs on a bogus + // TypeRef. + // Also allow additive merge for CAs from CompilerServices and Microsoft.VisualC + if (tkParentImp == MODULEDEFTOKEN + || TypeFromToken(tkParentImp) == mdtTypeRef + || (IsAttributeFromNamespace(pMiniMdImport, tkType, + COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME, + &pAttributeTypeRefRec) == S_OK) + || (IsAttributeFromNamespace(pMiniMdImport, tkType, + COR_MISCBITS_NAMESPACE, COR_MISCBITS_NAMESPACE, + &pAttributeTypeRefRec) == S_OK)) + { + // clear the error + hr = NOERROR; + + // custom value of module token! Copy over the custom value + goto CopyCustomAttribute; + } + + // another case to support additive merge if the CA on MehtodDef is + // HandleProcessCorruptedStateExceptionsAttribute + if ( TypeFromToken(tkParentImp) == mdtMethodDef && tkType == pImportData->m_tkHandleProcessCorruptedStateCtor) + { + // clear the error + hr = NOERROR; + + // custom value of module token! Copy over the custom value + goto CopyCustomAttribute; + } + CheckContinuableErrorEx(META_E_MD_INCONSISTENCY, pImportData, TokenFromRid(i, mdtCustomAttribute)); + } + } + else + { +CopyCustomAttribute: + if ((m_dwMergeFlags & DropMemberRefCAs) && TypeFromToken(pTokenRec->m_tkTo) == mdtMemberRef) + { + // CustomAttributes associated with MemberRef. If the parent of MemberRef is a MethodDef or FieldDef, drop + // the custom attribute. + MemberRefRec *pMemberRefRec; + IfFailGo(pMiniMdEmit->GetMemberRefRecord(RidFromToken(pTokenRec->m_tkTo), &pMemberRefRec)); + mdToken mrParent = pMiniMdEmit->getClassOfMemberRef(pMemberRefRec); + if (TypeFromToken(mrParent) == mdtMethodDef || TypeFromToken(mrParent) == mdtFieldDef) + { + // Don't bother to copy over + continue; + } + } + + // Parent is duplicated but the custom value is not. Still copy over the + // custom value. + fDuplicate = false; + IfFailGo(pMiniMdEmit->AddCustomAttributeRecord(&pRecEmit, (ULONG *)&cvEmit)); + cvEmit = TokenFromRid(cvEmit, mdtCustomAttribute); + + // set the parent + IfFailGo( pMiniMdEmit->PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo) ); + // set the type + IfFailGo( pMiniMdEmit->PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecEmit, pTypeRec->m_tkTo)); + + // move over the CustomAttribute blob value + IfFailGo(pMiniMdImport->getValueOfCustomAttribute(pRecImport, (const BYTE **)&pValue, &cbBlob)); + + IfFailGo( pMiniMdEmit->PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecEmit, pValue, cbBlob)); + IfFailGo( pMiniMdEmit->AddCustomAttributesToHash(cvEmit) ); + } + cvEmit = TokenFromRid(cvEmit, mdtCustomAttribute); + cvImp = TokenFromRid(i, mdtCustomAttribute); + + // Record the token movement + IfFailGo( pCurTkMap->InsertNotFound(cvImp, pTokenRec->m_isDuplicate, cvEmit, &pTokenRec) ); + } + } + else + { + + // either bad lookup map or bad metadata + _ASSERTE(!"Bad state"); + IfFailGo( META_E_BADMETADATA ); + } + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeCustomAttributes() + +//******************************************************************************* +// Helper to check if input scope has assembly-level security transparent awareness (either SecurityTransparent or SecurityCritical) +// SIDE EFFECT: pImportData->m_isscsSecurityCriticalStatus will be explicitly set [same value as return value] +// SecurityCritical.Explicit attribute injection occurs for all scopes that have tags (e.g. NOT ISSCS_Unknown) +// If the tagged scopes are all SecurityCritical.Everything, then the final attribute should be SecurityCritical.Everything +// anyway. Otherwise, at least one SecurityCritical.Explicit tag will be used/injected +//******************************************************************************* +InputScopeSecurityCriticalStatus NEWMERGER::CheckInputScopeIsCritical(MergeImportData* pImportData, HRESULT& hr) +{ + hr = S_OK; + + // the attribute should be in a known state no matter how we return from this function + // default to no attribute explicitly specified + pImportData->m_isscsSecurityCriticalStatus = ISSCS_Unknown; + + mdTypeRef fakeModuleTypeRef = mdTokenNil; + mdAssemblyRef tkMscorlib = mdTokenNil; + + // TODO: Should we remove the ability to disable merging critical attributes? + if (g_fRefShouldMergeCriticalChecked == FALSE) + { + // shouldn't require thread safety lock + g_fRefShouldMergeCritical = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MergeCriticalAttributes) != 0); + g_fRefShouldMergeCriticalChecked = TRUE; + } + + // return no merge needed, if the merge critical attribute setting is not enabled. + if (!g_fRefShouldMergeCritical) return ISSCS_Unknown; + + // get typeref for mscorlib + BYTE pbMscorlibToken[] = COR_MSCORLIB_TYPEREF; + + CMiniMdRW* pImportedMiniMd = &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd; + + if (S_OK != ImportHelper::FindAssemblyRef(pImportedMiniMd, + COR_MSCORLIB_NAME, + NULL, + pbMscorlibToken, + sizeof(pbMscorlibToken), + asm_rmj, + asm_rmm, + asm_rup, + asm_rpt, + 0, + &tkMscorlib)) + { + // there isn't an mscorlib ref here... we can't have the security critical attribute + return ISSCS_Unknown; + } + + if (S_OK != ImportHelper::FindTypeRefByName(pImportedMiniMd, + tkMscorlib, + COR_COMPILERSERVICE_NAMESPACE, + MODULE_CA_TYPENAME, + &fakeModuleTypeRef)) + { + // for now let use the fake module ref as the assembly def + fakeModuleTypeRef = 0x000001; + } + + // Check the input scope for TreatAsSafe + if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd, + fakeModuleTypeRef, // This is the assembly def token + COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL, + NULL, + NULL)) + { + pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityTreatAsSafe; + } + + // Check the input scope for security transparency awareness + // For example, the assembly is marked SecurityTransparent, SecurityCritical(Explicit), or SecurityCritical(Everything) + + + const void *pbData = NULL; // [OUT] Put pointer to data here. + ULONG cbData = 0; // number of bytes in pbData + + // Check if the SecurityTransparent attribute is present + if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd, + fakeModuleTypeRef, // This is the assembly def token + COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL, + NULL, + NULL)) + { + pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityTransparent; + } + else + // Check if the SecurityCritical attribute is present + if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd, + fakeModuleTypeRef, // This is the assembly def token + COR_SECURITYCRITICAL_ATTRIBUTE_FULL, + &pbData, + &cbData)) + { + // find out if critical everything or explicit + + // default to critical + pImportData->m_isscsSecurityCriticalStatus = ISSCS_SecurityCritical; + + BYTE rgSecurityCriticalEverythingCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING; + // if value is non-0 (i.e. 1), then mark as SecurityCritical everything, otherwise, explicit + if (NULL != pbData && cbData == 8 && + memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0) + { + pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityCriticalEverything; + } + else + { + pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityCriticalExplicit; + } + } + + return pImportData->m_isscsSecurityCriticalStatus; +} // HRESULT NEWMERGER::CheckInputScopeIsCritical() + +//******************************************************************************* +// Helper to merge security critical annotations across assemblies and types +//******************************************************************************* +HRESULT NEWMERGER::MergeSecurityCriticalAttributes() +{ + // if no assembly-level critical attributes were specified, then none are needed, + // and no need to do special attribute merging + if (ISSCS_Unknown == m_isscsSecurityCritical) + { + return S_OK; + } + // or if the global-scope already has TAS/Critical.Everything, then ignore individual type fixes + else if ((ISSCS_SECURITYCRITICAL_LEGACY & m_isscsSecurityCriticalAllScopes) == ISSCS_SECURITYCRITICAL_LEGACY) + { + return S_OK; + } + + HRESULT hr = S_OK; + + CMiniMdRW* emit = GetMiniMdEmit(); + // The attribute we want to decorate all of the types with has not been defined. + mdMemberRef tkSecurityCriticalEverythingAttribute = mdTokenNil; + mdMemberRef tkSecurityTreatAsSafeAttribute = mdTokenNil; + mdMemberRef tkSecuritySafeCriticalAttribute = mdTokenNil; + + mdAssemblyRef tkMscorlib = mdTokenNil; + mdTypeRef fakeModuleTypeRef = mdTokenNil; + mdTypeRef securityEnum = mdTokenNil; + + DWORD dwSigSize; + BYTE* rgSigBytesSecurityCriticalExplicitCtor = 0; + DWORD dwSigSize_TEMP; + + BYTE rgSigBytesTreatAsSafeCtor[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID}; + + BYTE rgSecurityCriticalEverythingCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING; + + + mdTypeRef tkSecurityCriticalEverythingAttributeType = mdTokenNil; + mdTypeRef tkSecurityTreatAsSafeAttributeType = mdTokenNil; + + NewArrayHolder<BYTE> rgSigBytesSecurityCriticalEverythingCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE]); + BYTE* pSigBytesSecurityCriticalEverythingCtor = rgSigBytesSecurityCriticalEverythingCtor.GetValue(); + IfFailGo((pSigBytesSecurityCriticalEverythingCtor == NULL)?E_OUTOFMEMORY:S_OK); + + IfFailGo(RetrieveStandardSecurityCriticalMetaData( + tkMscorlib, + securityEnum, + pSigBytesSecurityCriticalEverythingCtor, + dwSigSize, + rgSigBytesSecurityCriticalExplicitCtor, + dwSigSize_TEMP)); + + if (S_OK != ImportHelper::FindTypeRefByName(emit, + tkMscorlib, + COR_COMPILERSERVICE_NAMESPACE, + MODULE_CA_TYPENAME, + &fakeModuleTypeRef)) + { + // for now let use the fake module ref as the assembly def + fakeModuleTypeRef = 0x000001; + } + + IfFailGo(m_pRegMetaEmit->DefineTypeRefByName( + tkMscorlib, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, &tkSecurityCriticalEverythingAttributeType)); + + IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityCriticalEverythingAttributeType, + COR_CONSTRUCTOR_METADATA_IDENTIFIER, + rgSigBytesSecurityCriticalEverythingCtor.GetValue(), + dwSigSize, + &tkSecurityCriticalEverythingAttribute)); + + IfFailGo(m_pRegMetaEmit->DefineTypeRefByName( + tkMscorlib, COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W, + &tkSecurityTreatAsSafeAttributeType)); + + IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityTreatAsSafeAttributeType, + COR_CONSTRUCTOR_METADATA_IDENTIFIER, + rgSigBytesTreatAsSafeCtor, + sizeof(rgSigBytesTreatAsSafeCtor), + &tkSecurityTreatAsSafeAttribute)); + + + // place this block in a new scope so that we can safely goto past it + { + mdTypeRef tkSecuritySafeCriticalAttributeType = mdTokenNil; + if (FAILED (hr = m_pRegMetaEmit->DefineTypeRefByName(tkMscorlib, COR_SECURITYSAFECRITICAL_ATTRIBUTE_FULL_W, + &tkSecuritySafeCriticalAttributeType))) + { + _ASSERTE(!"Couldn't Emit a Typeref for SafeCritical attribute"); + return hr; + } + + BYTE rgSigBytesSafeCriticalCtor[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID}; + if (FAILED(hr = m_pRegMetaEmit->DefineMemberRef(tkSecuritySafeCriticalAttributeType, + W(".ctor"), + rgSigBytesSafeCriticalCtor, + sizeof(rgSigBytesSafeCriticalCtor), + &tkSecuritySafeCriticalAttribute))) + { + _ASSERTE(!"Couldn't Emit a MemberRef for SafeCritical attribute .ctor"); + return hr; + } + } + + + for (MergeImportData* pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // if the import is marked TAS, then we need to explicitly mark each type as TAS + // if the import is marked Crit/Everything, then we need to explicitly mark each type as Crit + // if the import is not marked at all, then we need to explicitly mark each type TAS/Crit + + // if the import is marked ONLY Crit/Explicit or ONLY Transparent then we can ignore it + if (ISSCS_SecurityTransparent == pImportData->m_isscsSecurityCriticalStatus || + ISSCS_SecurityCriticalExplicit == pImportData->m_isscsSecurityCriticalStatus) continue; + + // Run through the scopes that need to have their types decorated with this attribute + MDTOKENMAP*pCurTKMap = pImportData->m_pMDTokenMap; + BYTE rgTreatAsSafeCtorValue[] = COR_SECURITYTREATASSAFE_ATTRIBUTE_VALUE; + + BOOL fMarkEachTokenAsCritical = FALSE; + // if the import is unmarked or marked Crit/Everything, + // then we need to explicitly mark each token as Crit + // Unless the the global scope already has SecurityCritical.Everything + if (((ISSCS_SecurityCriticalEverything & m_isscsSecurityCriticalAllScopes) != ISSCS_SecurityCriticalEverything) && + (((ISSCS_SecurityCriticalEverything & pImportData->m_isscsSecurityCriticalStatus) == ISSCS_SecurityCriticalEverything ) || + + // OR this scope is NOT transparent or critical-explicit + (ISSCS_SecurityTransparent & pImportData->m_isscsSecurityCriticalStatus) == 0 || + (ISSCS_SecurityCritical & pImportData->m_isscsSecurityCriticalStatus) == 0 || + + // OR this scope is UNKNOWN + (ISSCS_Unknown == (ISSCS_SECURITYCRITICAL_FLAGS & pImportData->m_isscsSecurityCriticalStatus)))) + { + fMarkEachTokenAsCritical = TRUE; + } + + BOOL fMarkEachTokenAsSafe = FALSE; + // if the import is unmarked or marked TAS, + // then we need to explicitly mark each token as TAS + // Unless the the global scope already has SecurityTreatAsSafe + if (((ISSCS_SecurityTreatAsSafe & m_isscsSecurityCriticalAllScopes) != ISSCS_SecurityTreatAsSafe) && + ((ISSCS_SecurityTreatAsSafe & pImportData->m_isscsSecurityCriticalStatus) || + ISSCS_Unknown == (pImportData->m_isscsSecurityCriticalStatus & ISSCS_SECURITYCRITICAL_FLAGS))) + { + fMarkEachTokenAsSafe = TRUE; + } + + BYTE rgSafeCriticalCtorValue[] = {0x01, 0x00, 0x00 ,0x00}; + + for (int i = 0; i < pCurTKMap->Count(); i++) + { + TOKENREC* pRec = pCurTKMap->Get(i); + BOOL fInjectSecurityAttributes = FALSE; + + // skip empty records + if (pRec->IsEmpty()) continue; + + // If this scope contained a typeref that was resolved to a typedef, let's not mark it. We'll let the owner + // of the actual typedef decide if that type should be marked. + if ((TypeFromToken(pRec->m_tkFrom) == mdtTypeRef) && (TypeFromToken(pRec->m_tkTo) == mdtTypeDef)) + continue; + + // Same for method refs/method defs + if ((TypeFromToken(pRec->m_tkFrom) == mdtMemberRef) && (TypeFromToken(pRec->m_tkTo) == mdtMethodDef)) + continue; + + // check for typedefs, but don't put this on the global typedef + if ((TypeFromToken(pRec->m_tkTo) == mdtTypeDef) && (pRec->m_tkTo != TokenFromRid(1, mdtTypeDef))) + { + // by default we will inject + fInjectSecurityAttributes = TRUE; + // except for Enums + DWORD dwClassAttrs = 0; + mdTypeRef crExtends = mdTokenNil; + + if (FAILED(hr = m_pRegMetaEmit->GetTypeDefProps(pRec->m_tkTo, NULL, NULL, 0 , &dwClassAttrs, &crExtends))) + { + // TODO: should we fail ?? + } + + // check for Enum types + if (!IsNilToken(crExtends) && (TypeFromToken(crExtends)==mdtTypeRef)) + { + // get the namespace and the name for this token + CMiniMdRW *pMiniMd = GetMiniMdEmit(); + TypeRefRec *pTypeRefRec; + IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(crExtends), &pTypeRefRec)); + LPCSTR szNamespace; + LPCSTR szName; + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));; + IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName)); + // check for System.Enum + BOOL bIsEnum = (!strcmp(szNamespace,"System"))&&(!strcmp(szName,"Enum")); + if (bIsEnum) + { + fInjectSecurityAttributes = FALSE; + } + } + } + else // check for global method defs + if (TypeFromToken(pRec->m_tkTo) == mdtMethodDef) + { + int isGlobal = 0; + if (!FAILED(m_pRegMetaEmit->IsGlobal(pRec->m_tkTo, &isGlobal))) + { + // check for global methods + if (isGlobal != 0) + { + fInjectSecurityAttributes = TRUE; + } + } + } + + if (fInjectSecurityAttributes) + { + // check to see if the token already has a custom attribute + const void *pbData = NULL; // [OUT] Put pointer to data here. + ULONG cbData = 0; + + if (fMarkEachTokenAsCritical) + { + // Check if the Type already has SecurityCritical + BOOL fInjectSecurityCriticalEverything = TRUE; + if (S_OK == m_pRegMetaEmit->GetCustomAttributeByName(pRec->m_tkTo, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, &pbData, &cbData)) + { + // if value is non-0 (i.e. 1), then it is SecurityCritical.Everything - so do not inject another + fInjectSecurityCriticalEverything = !(NULL != pbData && cbData == 8 && + memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0); + } + + // either inject or overwrite SecurityCritical.Everything + if (fInjectSecurityCriticalEverything) + { + IfFailGo(m_pRegMetaEmit->DefineCustomAttribute( + pRec->m_tkTo, tkSecurityCriticalEverythingAttribute, + rgSecurityCriticalEverythingCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough) + sizeof(rgSecurityCriticalEverythingCtorValue), // Length of your custom attribute data + NULL)); + } + } + + // If the Type does NOT already have TAS then add it + if (fMarkEachTokenAsSafe && + S_OK != m_pRegMetaEmit->GetCustomAttributeByName(pRec->m_tkTo, COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W, &pbData, &cbData)) + { + IfFailGo(m_pRegMetaEmit->DefineCustomAttribute( + pRec->m_tkTo, tkSecurityTreatAsSafeAttribute, + rgTreatAsSafeCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough) + sizeof(rgTreatAsSafeCtorValue), // Length of your custom attribute data + NULL)); + } + + hr = m_pRegMetaEmit->DefineCustomAttribute(pRec->m_tkTo, tkSecuritySafeCriticalAttribute, + rgSafeCriticalCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough) + sizeof(rgSafeCriticalCtorValue), // Length of your custom attribute data + NULL); + + } + } + } + + // If the global scope is not Transparent, we should emit SecurityCritical.Explicit || Everything + if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTransparent) != ISSCS_SecurityTransparent && + (m_isscsSecurityCritical & ISSCS_SecurityCriticalEverything) != ISSCS_SecurityCriticalExplicit) + { + BOOL fEmitSecurityEverything = FALSE; + // in the case of Unmarked and TAS/Unmarked, we need to emit the SecurityCritical.Everything attribute + // if it hasn't already been emitted + if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) == + ISSCS_SecurityCriticalEverything) + { + fEmitSecurityEverything = TRUE; + } + // otherwise, emit the SecurityCritical.Explicit attribute + + BOOL fSecurityCriticalExists = FALSE; + // check to see if the assembly already has the appropriate SecurityCritical attribute + // [from one of the input scopes] + const void *pbData = NULL; + ULONG cbData = 0; + if (S_OK == ImportHelper::GetCustomAttributeByName(emit, + fakeModuleTypeRef, // This is the assembly def token + COR_SECURITYCRITICAL_ATTRIBUTE_FULL, + &pbData, + &cbData)) + { + // find out if critical everything or explicit + // default to critical + // if value is non-0 (i.e. 1), then mark as SecurityCritical everything, otherwise, explicit + if (NULL != pbData && cbData == 8 && + memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0) + { + if (!fEmitSecurityEverything) + { + _ASSERTE(!"Unexpected SecurityCritical.Everything attribute detected"); + IfFailGo(META_E_BADMETADATA); + } + } + else + { + if (fEmitSecurityEverything) + { + _ASSERTE(!"Unexpected SecurityCritical.Explicit attribute detected"); + IfFailGo(META_E_BADMETADATA); + } + } + fSecurityCriticalExists = TRUE; + } + + if (!fSecurityCriticalExists) + { + // retrieve the type and CustomAttribute + mdCustomAttribute tkSecurityCriticalAttributeExplicit; + + mdTypeRef tkSecurityCriticalExplicitAttributeType = mdTokenNil; + + IfFailGo(m_pRegMetaEmit->DefineTypeRefByName( + tkMscorlib, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, + &tkSecurityCriticalExplicitAttributeType)); + + BYTE rgSigBytesSecurityCriticalExplicitCtorLocal[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID}; + BYTE rgSecurityCriticalExplicitCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EXPLICIT; + + IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityCriticalExplicitAttributeType, + COR_CONSTRUCTOR_METADATA_IDENTIFIER, + rgSigBytesSecurityCriticalExplicitCtorLocal, + sizeof(rgSigBytesSecurityCriticalExplicitCtorLocal), + &tkSecurityCriticalAttributeExplicit)); + + IfFailGo(m_pRegMetaEmit->DefineCustomAttribute( + fakeModuleTypeRef, + fEmitSecurityEverything?tkSecurityCriticalEverythingAttribute:tkSecurityCriticalAttributeExplicit, + fEmitSecurityEverything?rgSecurityCriticalEverythingCtorValue:rgSecurityCriticalExplicitCtorValue, + fEmitSecurityEverything?sizeof(rgSecurityCriticalEverythingCtorValue):sizeof(rgSecurityCriticalExplicitCtorValue), + NULL)); + + } + } + +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeSecurityCriticalAttributes() + +//******************************************************************************* +// Helper to copy an InterfaceImpl record +//******************************************************************************* +HRESULT NEWMERGER::CopyInterfaceImpl( + InterfaceImplRec *pRecEmit, // [IN] the emit record to fill + MergeImportData *pImportData, // [IN] the importing context + InterfaceImplRec *pRecImp) // [IN] the record to import +{ + HRESULT hr; + mdToken tkParent; + mdToken tkInterface; + CMiniMdRW *pMiniMdEmit = GetMiniMdEmit(); + CMiniMdRW *pMiniMdImp; + MDTOKENMAP *pCurTkMap; + + pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + + tkParent = pMiniMdImp->getClassOfInterfaceImpl(pRecImp); + tkInterface = pMiniMdImp->getInterfaceOfInterfaceImpl(pRecImp); + + IfFailGo( pCurTkMap->Remap(tkParent, &tkParent) ); + IfFailGo( pCurTkMap->Remap(tkInterface, &tkInterface) ); + + IfFailGo( pMiniMdEmit->PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Class, pRecEmit, tkParent) ); + IfFailGo( pMiniMdEmit->PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Interface, pRecEmit, tkInterface) ); + +ErrExit: + return hr; +} // HRESULT NEWMERGER::CopyInterfaceImpl() + + +//***************************************************************************** +// Merge Assembly table +//***************************************************************************** +HRESULT NEWMERGER::MergeAssembly() +{ + HRESULT hr = NOERROR; + AssemblyRec *pRecImport = NULL; + AssemblyRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + LPCUTF8 szTmp; + const BYTE *pbTmp; + ULONG cbTmp; + ULONG iRecord; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + if (!pMiniMdImport->getCountAssemblys()) + goto ErrExit; // There is no Assembly in the import scope to merge. + + // Copy the Assembly map record to the Emit scope and send a token remap notifcation + // to the client. No duplicate checking needed since the Assembly can be present in + // only one scope and there can be atmost one entry. + IfFailGo(pMiniMdImport->GetAssemblyRecord(1, &pRecImport)); + IfFailGo(pMiniMdEmit->AddAssemblyRecord(&pRecEmit, &iRecord)); + + pRecEmit->Copy(pRecImport); + + IfFailGo(pMiniMdImport->getPublicKeyOfAssembly(pRecImport, &pbTmp, &cbTmp)); + IfFailGo(pMiniMdEmit->PutBlob(TBL_Assembly, AssemblyRec::COL_PublicKey, pRecEmit, + pbTmp, cbTmp)); + + IfFailGo(pMiniMdImport->getNameOfAssembly(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_Assembly, AssemblyRec::COL_Name, pRecEmit, szTmp)); + + IfFailGo(pMiniMdImport->getLocaleOfAssembly(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_Assembly, AssemblyRec::COL_Locale, pRecEmit, szTmp)); + + // record the token movement. + IfFailGo(pCurTkMap->InsertNotFound( + TokenFromRid(1, mdtAssembly), + false, + TokenFromRid(iRecord, mdtAssembly), + &pTokenRec)); + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeAssembly() + + + + +//***************************************************************************** +// Merge File table +//***************************************************************************** +HRESULT NEWMERGER::MergeFiles() +{ + HRESULT hr = NOERROR; + FileRec *pRecImport = NULL; + FileRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + LPCUTF8 szTmp; + const void *pbTmp; + ULONG cbTmp; + ULONG iCount; + ULONG i; + ULONG iRecord; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountFiles(); + + // Loop through all File records and copy them to the Emit scope. + // Since there can only be one File table in all the scopes combined, + // there isn't any duplicate checking that needs to be done. + for (i = 1; i <= iCount; i++) + { + IfFailGo(pMiniMdImport->GetFileRecord(i, &pRecImport)); + IfFailGo(pMiniMdEmit->AddFileRecord(&pRecEmit, &iRecord)); + + pRecEmit->Copy(pRecImport); + + IfFailGo(pMiniMdImport->getNameOfFile(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_File, FileRec::COL_Name, pRecEmit, szTmp)); + + IfFailGo(pMiniMdImport->getHashValueOfFile(pRecImport, (const BYTE **)&pbTmp, &cbTmp)); + IfFailGo(pMiniMdEmit->PutBlob(TBL_File, FileRec::COL_HashValue, pRecEmit, pbTmp, cbTmp)); + + // record the token movement. + IfFailGo(pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtFile), + false, + TokenFromRid(iRecord, mdtFile), + &pTokenRec)); + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeFiles() + + +//***************************************************************************** +// Merge ExportedType table +//***************************************************************************** +HRESULT NEWMERGER::MergeExportedTypes() +{ + HRESULT hr = NOERROR; + ExportedTypeRec *pRecImport = NULL; + ExportedTypeRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + LPCUTF8 szTmp; + mdToken tkTmp; + ULONG iCount; + ULONG i; + ULONG iRecord; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountExportedTypes(); + + // Loop through all ExportedType records and copy them to the Emit scope. + // Since there can only be one ExportedType table in all the scopes combined, + // there isn't any duplicate checking that needs to be done. + for (i = 1; i <= iCount; i++) + { + IfFailGo(pMiniMdImport->GetExportedTypeRecord(i, &pRecImport)); + IfFailGo(pMiniMdEmit->AddExportedTypeRecord(&pRecEmit, &iRecord)); + + pRecEmit->Copy(pRecImport); + + IfFailGo(pMiniMdImport->getTypeNameOfExportedType(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeName, pRecEmit, szTmp)); + + IfFailGo(pMiniMdImport->getTypeNamespaceOfExportedType(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeNamespace, pRecEmit, szTmp)); + + tkTmp = pMiniMdImport->getImplementationOfExportedType(pRecImport); + IfFailGo(pCurTkMap->Remap(tkTmp, &tkTmp)); + IfFailGo(pMiniMdEmit->PutToken(TBL_ExportedType, ExportedTypeRec::COL_Implementation, + pRecEmit, tkTmp)); + + + // record the token movement. + IfFailGo(pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtExportedType), + false, + TokenFromRid(iRecord, mdtExportedType), + &pTokenRec)); + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeExportedTypes() + + +//***************************************************************************** +// Merge ManifestResource table +//***************************************************************************** +HRESULT NEWMERGER::MergeManifestResources() +{ + HRESULT hr = NOERROR; + ManifestResourceRec *pRecImport = NULL; + ManifestResourceRec *pRecEmit = NULL; + CMiniMdRW *pMiniMdImport; + CMiniMdRW *pMiniMdEmit; + LPCUTF8 szTmp; + mdToken tkTmp; + ULONG iCount; + ULONG i; + ULONG iRecord; + TOKENREC *pTokenRec; + + MergeImportData *pImportData; + MDTOKENMAP *pCurTkMap; + + pMiniMdEmit = GetMiniMdEmit(); + + for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData) + { + // for each import scope + pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + + // set the current MDTokenMap + pCurTkMap = pImportData->m_pMDTokenMap; + iCount = pMiniMdImport->getCountManifestResources(); + + // Loop through all ManifestResource records and copy them to the Emit scope. + // Since there can only be one ManifestResource table in all the scopes combined, + // there isn't any duplicate checking that needs to be done. + for (i = 1; i <= iCount; i++) + { + IfFailGo(pMiniMdImport->GetManifestResourceRecord(i, &pRecImport)); + IfFailGo(pMiniMdEmit->AddManifestResourceRecord(&pRecEmit, &iRecord)); + + pRecEmit->Copy(pRecImport); + + IfFailGo(pMiniMdImport->getNameOfManifestResource(pRecImport, &szTmp)); + IfFailGo(pMiniMdEmit->PutString(TBL_ManifestResource, ManifestResourceRec::COL_Name, + pRecEmit, szTmp)); + + tkTmp = pMiniMdImport->getImplementationOfManifestResource(pRecImport); + IfFailGo(pCurTkMap->Remap(tkTmp, &tkTmp)); + IfFailGo(pMiniMdEmit->PutToken(TBL_ManifestResource, ManifestResourceRec::COL_Implementation, + pRecEmit, tkTmp)); + + // record the token movement. + IfFailGo(pCurTkMap->InsertNotFound( + TokenFromRid(i, mdtManifestResource), + false, + TokenFromRid(iRecord, mdtManifestResource), + &pTokenRec)); + } + } +ErrExit: + return hr; +} // HRESULT NEWMERGER::MergeManifestResources() + + + + + +//***************************************************************************** +// Error handling. Call back to host to see what they want to do. +//***************************************************************************** +HRESULT NEWMERGER::OnError( + HRESULT hrIn, // The error HR we're reporting. + MergeImportData *pImportData, // The input scope with the error. + mdToken token) // The token with the error. +{ + // This function does a QI and a Release on every call. However, it should be + // called very infrequently, and lets the scope just keep a generic handler. + IMetaDataError *pIErr = NULL; + IUnknown *pHandler = pImportData->m_pHandler; + CMiniMdRW *pMiniMd = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd); + CQuickArray<WCHAR> rName; // Name of the TypeDef in unicode. + LPCUTF8 szTypeName; + LPCUTF8 szNSName; + TypeDefRec *pTypeRec; + int iLen; // Length of a name. + mdToken tkParent; + HRESULT hr = NOERROR; + + if (pHandler && pHandler->QueryInterface(IID_IMetaDataError, (void**)&pIErr)==S_OK) + { + switch (hrIn) + { + + case META_E_PARAM_COUNTS: + case META_E_METHD_NOT_FOUND: + case META_E_METHDIMPL_INCONSISTENT: + { + LPCUTF8 szMethodName; + MethodRec *pMethodRec; + + // Method name. + _ASSERTE(TypeFromToken(token) == mdtMethodDef); + IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(token), &pMethodRec)); + IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName)); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName); + IfNullGo(wzMethodName); + + // Type and its name. + IfFailGo( pMiniMd->FindParentOfMethodHelper(token, &tkParent) ); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + PostError(hrIn, (LPWSTR) rName.Ptr(), wzMethodName, token); + break; + } + case META_E_FIELD_NOT_FOUND: + { + LPCUTF8 szFieldName; + FieldRec *pFieldRec; + + // Field name. + _ASSERTE(TypeFromToken(token) == mdtFieldDef); + IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(token), &pFieldRec)); + IfFailGo(pMiniMd->getNameOfField(pFieldRec, &szFieldName)); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzFieldName, szFieldName); + IfNullGo(wzFieldName); + + // Type and its name. + IfFailGo( pMiniMd->FindParentOfFieldHelper(token, &tkParent) ); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + PostError(hrIn, (LPWSTR) rName.Ptr(), wzFieldName, token); + break; + } + case META_E_EVENT_NOT_FOUND: + { + LPCUTF8 szEventName; + EventRec *pEventRec; + + // Event name. + _ASSERTE(TypeFromToken(token) == mdtEvent); + IfFailGo(pMiniMd->GetEventRecord(RidFromToken(token), &pEventRec)); + IfFailGo(pMiniMd->getNameOfEvent(pEventRec, &szEventName)); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzEventName, szEventName); + IfNullGo(wzEventName); + + // Type and its name. + IfFailGo( pMiniMd->FindParentOfEventHelper(token, &tkParent) ); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + PostError(hrIn, (LPWSTR) rName.Ptr(), wzEventName, token); + break; + } + case META_E_PROP_NOT_FOUND: + { + LPCUTF8 szPropertyName; + PropertyRec *pPropertyRec; + + // Property name. + _ASSERTE(TypeFromToken(token) == mdtProperty); + IfFailGo(pMiniMd->GetPropertyRecord(RidFromToken(token), &pPropertyRec)); + IfFailGo(pMiniMd->getNameOfProperty(pPropertyRec, &szPropertyName)); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzPropertyName, szPropertyName); + IfNullGo(wzPropertyName); + + // Type and its name. + IfFailGo( pMiniMd->FindParentOfPropertyHelper(token, &tkParent) ); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + PostError(hrIn, (LPWSTR) rName.Ptr(), wzPropertyName, token); + break; + } + case META_S_PARAM_MISMATCH: + { + LPCUTF8 szMethodName; + MethodRec *pMethodRec; + mdToken tkMethod; + + // Method name. + _ASSERTE(TypeFromToken(token) == mdtParamDef); + IfFailGo( pMiniMd->FindParentOfParamHelper(token, &tkMethod) ); + IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkMethod), &pMethodRec)); + IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName)); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName); + IfNullGo(wzMethodName); + + // Type and its name. + IfFailGo( pMiniMd->FindParentOfMethodHelper(token, &tkParent) ); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + // use the error hresult so that we can post the correct error. + PostError(META_E_PARAM_MISMATCH, wzMethodName, (LPWSTR) rName.Ptr(), token); + break; + } + case META_E_INTFCEIMPL_NOT_FOUND: + { + InterfaceImplRec *pRec; // The InterfaceImpl + mdToken tkIface; // Token of the implemented interface. + CQuickArray<WCHAR> rIface; // Name of the Implemented Interface in unicode. + TypeRefRec *pRef; // TypeRef record when II is a typeref. + InterfaceImplRec *pInterfaceImplRec; + + // Get the record. + _ASSERTE(TypeFromToken(token) == mdtInterfaceImpl); + IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(token), &pRec)); + // Get the name of the class. + tkParent = pMiniMd->getClassOfInterfaceImpl(pRec); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + // Get the name of the implemented interface. + IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(token), &pInterfaceImplRec)); + tkIface = pMiniMd->getInterfaceOfInterfaceImpl(pInterfaceImplRec); + if (TypeFromToken(tkIface) == mdtTypeDef) + { // If it is a typedef... + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkIface), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + } + else + { // If it is a typeref... + _ASSERTE(TypeFromToken(tkIface) == mdtTypeRef); + IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkIface), &pRef)); + IfFailGo(pMiniMd->getNameOfTypeRef(pRef, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRef, &szNSName)); + } + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rIface.ReSizeNoThrow(iLen+1)); + ns::MakePath(rIface.Ptr(), iLen+1, szNSName, szTypeName); + + + PostError(hrIn, (LPWSTR) rName.Ptr(), (LPWSTR)rIface.Ptr(), token); + break; + } + case META_E_CLASS_LAYOUT_INCONSISTENT: + case META_E_METHOD_COUNTS: + case META_E_FIELD_COUNTS: + case META_E_EVENT_COUNTS: + case META_E_PROPERTY_COUNTS: + { + // get the type name. + _ASSERTE(TypeFromToken(token) == mdtTypeDef); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + PostError(hrIn, (LPWSTR) rName.Ptr(), token); + break; + } + case META_E_GENERICPARAM_INCONSISTENT: + { + // If token is type, get type name; if method, get method name. + LPWSTR wzName; + LPCUTF8 szMethodName; + MethodRec *pMethodRec; + + if ((TypeFromToken(token) == mdtMethodDef)) + { + // Get the method name. + IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(token), &pMethodRec)); + IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName)); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName); + IfNullGo(wzMethodName); + wzName = wzMethodName; + } + else + { + // Get the type name. + _ASSERTE(TypeFromToken(token) == mdtTypeDef); + IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTypeRec)); + IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName)); + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + wzName = (LPWSTR)rName.Ptr(); + } + + PostError(hrIn, wzName, token); + break; + } + case META_E_TYPEDEF_MISSING: + { + TypeRefRec *pRef; // TypeRef record when II is a typeref. + + // Get the record. + _ASSERTE(TypeFromToken(token) == mdtTypeRef); + IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(token), &pRef)); + IfFailGo(pMiniMd->getNameOfTypeRef(pRef, &szTypeName)); + IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRef, &szNSName)); + + // Put namespace + name together. + iLen = ns::GetFullLength(szNSName, szTypeName); + IfFailGo(rName.ReSizeNoThrow(iLen+1)); + ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName); + + + PostError(hrIn, (LPWSTR) rName.Ptr(), token); + break; + } + default: + { + PostError(hrIn, token); + break; + } + } + hr = pIErr->OnError(hrIn, token); + } + else + hr = S_FALSE; +ErrExit: + if (pIErr) + pIErr->Release(); + return (hr); +} // NEWMERGER::OnError + +#endif //FEATURE_METADATA_EMIT_ALL |