Skip to content

Commit 67bfe04

Browse files
authored
Add processing of type modifiers (#221)
1 parent f11a3f0 commit 67bfe04

File tree

3 files changed

+166
-42
lines changed

3 files changed

+166
-42
lines changed

MetadataProcessor.Shared/Extensions/TypeReferenceExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,26 @@ public static string TypeSignatureAsString(this TypeReference type)
7474
}
7575
}
7676

77+
if (type is RequiredModifierType requiredModifier)
78+
{
79+
StringBuilder reqModSig = new StringBuilder();
80+
reqModSig.Append(requiredModifier.ElementType.TypeSignatureAsString());
81+
reqModSig.Append(" modreq(");
82+
reqModSig.Append(requiredModifier.ModifierType.FullName);
83+
reqModSig.Append(")");
84+
return reqModSig.ToString();
85+
}
86+
87+
if (type is OptionalModifierType optionalModifier)
88+
{
89+
StringBuilder optModSig = new StringBuilder();
90+
optModSig.Append(optionalModifier.ElementType.TypeSignatureAsString());
91+
optModSig.Append(" modopt(");
92+
optModSig.Append(optionalModifier.ModifierType.FullName);
93+
optModSig.Append(")");
94+
return optModSig.ToString();
95+
}
96+
7797
if (type.MetadataType == MetadataType.Class)
7898
{
7999
StringBuilder classSig = new StringBuilder("CLASS ");

MetadataProcessor.Shared/Tables/nanoSignaturesTable.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,30 @@ public void WriteDataType(
372372
//Debug.Fail("Gotcha!");
373373
}
374374

375+
if (typeDefinition is RequiredModifierType requiredModifier)
376+
{
377+
if (alsoWriteSubType)
378+
{
379+
writer.WriteByte((byte)nanoSerializationType.ELEMENT_TYPE_CMOD_REQD);
380+
WriteSubTypeInfo(requiredModifier.ModifierType, writer);
381+
}
382+
383+
WriteDataType(requiredModifier.ElementType, writer, alsoWriteSubType, expandEnumType, isTypeDefinition);
384+
return;
385+
}
386+
387+
if (typeDefinition is OptionalModifierType optionalModifier)
388+
{
389+
if (alsoWriteSubType)
390+
{
391+
writer.WriteByte((byte)nanoSerializationType.ELEMENT_TYPE_CMOD_OPT);
392+
WriteSubTypeInfo(optionalModifier.ModifierType, writer);
393+
}
394+
395+
WriteDataType(optionalModifier.ElementType, writer, alsoWriteSubType, expandEnumType, isTypeDefinition);
396+
return;
397+
}
398+
375399
if (typeDefinition.MetadataType == MetadataType.Class)
376400
{
377401
writer.WriteByte((byte)NanoCLRDataType.DATATYPE_CLASS);
@@ -893,7 +917,17 @@ private void WriteTypeInfo(
893917
// If there is modifier on type record of local variable, we put it before type of local variable.
894918
if (typeReference.IsOptionalModifier)
895919
{
896-
writer.WriteByte(0x0); // OpTypeModifier ???
920+
var optMod = typeReference as OptionalModifierType;
921+
writer.WriteByte((byte)nanoSerializationType.ELEMENT_TYPE_CMOD_OPT);
922+
WriteSubTypeInfo(optMod.ModifierType, writer);
923+
typeReference = optMod.ElementType;
924+
}
925+
else if (typeReference.IsRequiredModifier)
926+
{
927+
var reqMod = typeReference as RequiredModifierType;
928+
writer.WriteByte((byte)nanoSerializationType.ELEMENT_TYPE_CMOD_REQD);
929+
WriteSubTypeInfo(reqMod.ModifierType, writer);
930+
typeReference = reqMod.ElementType;
897931
}
898932

899933
var byReference = typeReference as ByReferenceType;

MetadataProcessor.Shared/nanoAssemblyBuilder.cs

Lines changed: 111 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -381,43 +381,79 @@ private HashSet<MetadataToken> BuildDependencyList(MetadataToken token)
381381
}
382382
}
383383

384-
if (mr.MethodReturnType.ReturnType.IsValueType &&
385-
!mr.MethodReturnType.ReturnType.IsPrimitive)
384+
// return type modifiers - handle modifiers properly
385+
TypeReference mrReturnType = mr.ReturnType;
386+
387+
// Unwrap any modifiers and add them to dependencies
388+
while (mrReturnType is RequiredModifierType mrReqMod)
389+
{
390+
set.Add(mrReqMod.ModifierType.MetadataToken);
391+
mrReturnType = mrReqMod.ElementType;
392+
}
393+
394+
while (mrReturnType is OptionalModifierType mrOptMod)
395+
{
396+
set.Add(mrOptMod.ModifierType.MetadataToken);
397+
mrReturnType = mrOptMod.ElementType;
398+
}
399+
400+
// Handle by-reference types
401+
if (mrReturnType is ByReferenceType mrByRef)
402+
{
403+
mrReturnType = mrByRef.ElementType;
404+
405+
// Check again for modifiers inside the by-reference
406+
while (mrReturnType is RequiredModifierType mrReqMod2)
407+
{
408+
set.Add(mrReqMod2.ModifierType.MetadataToken);
409+
mrReturnType = mrReqMod2.ElementType;
410+
}
411+
412+
while (mrReturnType is OptionalModifierType mrOptMod2)
413+
{
414+
set.Add(mrOptMod2.ModifierType.MetadataToken);
415+
mrReturnType = mrOptMod2.ElementType;
416+
}
417+
}
418+
419+
// Now process the actual return type
420+
if (mrReturnType.IsValueType &&
421+
!mrReturnType.IsPrimitive)
386422
{
387-
set.Add(mr.MethodReturnType.ReturnType.MetadataToken);
423+
set.Add(mrReturnType.MetadataToken);
388424
}
389-
else if (mr.ReturnType.IsArray)
425+
else if (mrReturnType.IsArray)
390426
{
391-
if (mr.ReturnType.DeclaringType != null)
427+
if (mrReturnType.DeclaringType != null)
392428
{
393-
set.Add(mr.ReturnType.DeclaringType.MetadataToken);
429+
set.Add(mrReturnType.DeclaringType.MetadataToken);
394430
}
395431
else
396432
{
397-
if (mr.ReturnType.GetElementType().FullName != "System.Void" &&
398-
mr.ReturnType.GetElementType().FullName != "System.String" &&
399-
mr.ReturnType.GetElementType().FullName != "System.Object" &&
400-
!mr.ReturnType.GetElementType().IsPrimitive)
433+
if (mrReturnType.GetElementType().FullName != "System.Void" &&
434+
mrReturnType.GetElementType().FullName != "System.String" &&
435+
mrReturnType.GetElementType().FullName != "System.Object" &&
436+
!mrReturnType.GetElementType().IsPrimitive)
401437
{
402-
set.Add(mr.ReturnType.GetElementType().MetadataToken);
438+
set.Add(mrReturnType.GetElementType().MetadataToken);
403439
}
404440
}
405441
}
406442
else
407443
{
408-
if (mr.ReturnType.MetadataType == MetadataType.ValueType)
444+
if (mrReturnType.MetadataType == MetadataType.ValueType)
409445
{
410-
if (mr.ReturnType.FullName != "System.Void" &&
411-
mr.ReturnType.FullName != "System.String" &&
412-
mr.ReturnType.FullName != "System.Object" &&
413-
!mr.ReturnType.IsPrimitive)
446+
if (mrReturnType.FullName != "System.Void" &&
447+
mrReturnType.FullName != "System.String" &&
448+
mrReturnType.FullName != "System.Object" &&
449+
!mrReturnType.IsPrimitive)
414450
{
415-
set.Add(mr.ReturnType.MetadataToken);
451+
set.Add(mrReturnType.MetadataToken);
416452
}
417453
}
418-
if (mr.ReturnType.MetadataType == MetadataType.Class)
454+
if (mrReturnType.MetadataType == MetadataType.Class)
419455
{
420-
set.Add(mr.ReturnType.MetadataToken);
456+
set.Add(mrReturnType.MetadataToken);
421457
}
422458
}
423459

@@ -684,37 +720,71 @@ private HashSet<MetadataToken> BuildDependencyList(MetadataToken token)
684720
case TokenType.Method:
685721
MethodDefinition md = _tablesContext.MethodDefinitionTable.Items.FirstOrDefault(i => i.MetadataToken == token);
686722

687-
// return value
688-
if (md.ReturnType.IsValueType
689-
&& !md.ReturnType.IsPrimitive)
723+
// return value - handle modifiers properly
724+
TypeReference mdReturnType = md.ReturnType;
725+
726+
// Unwrap any modifiers and add them to dependencies
727+
while (mdReturnType is RequiredModifierType mdReqMod)
728+
{
729+
set.Add(mdReqMod.ModifierType.MetadataToken);
730+
mdReturnType = mdReqMod.ElementType;
731+
}
732+
733+
while (mdReturnType is OptionalModifierType mdOptMod)
734+
{
735+
set.Add(mdOptMod.ModifierType.MetadataToken);
736+
mdReturnType = mdOptMod.ElementType;
737+
}
738+
739+
// Handle by-reference types
740+
if (mdReturnType is ByReferenceType mdByRef)
741+
{
742+
mdReturnType = mdByRef.ElementType;
743+
744+
// Check again for modifiers inside the by-reference
745+
while (mdReturnType is RequiredModifierType mdReqMod2)
746+
{
747+
set.Add(mdReqMod2.ModifierType.MetadataToken);
748+
mdReturnType = mdReqMod2.ElementType;
749+
}
750+
751+
while (mdReturnType is OptionalModifierType mdOptMod2)
752+
{
753+
set.Add(mdOptMod2.ModifierType.MetadataToken);
754+
mdReturnType = mdOptMod2.ElementType;
755+
}
756+
}
757+
758+
// Now process the actual return type
759+
if (mdReturnType.IsValueType
760+
&& !mdReturnType.IsPrimitive)
690761
{
691-
set.Add(md.ReturnType.MetadataToken);
762+
set.Add(mdReturnType.MetadataToken);
692763
}
693-
else if (md.ReturnType.IsArray)
764+
else if (mdReturnType.IsArray)
694765
{
695-
if (md.ReturnType.DeclaringType != null)
766+
if (mdReturnType.DeclaringType != null)
696767
{
697-
set.Add(md.ReturnType.DeclaringType.MetadataToken);
768+
set.Add(mdReturnType.DeclaringType.MetadataToken);
698769
}
699770
else
700771
{
701-
if (md.ReturnType.GetElementType().FullName != "System.Void" &&
702-
md.ReturnType.GetElementType().FullName != "System.String" &&
703-
md.ReturnType.GetElementType().FullName != "System.Object" &&
704-
!md.ReturnType.GetElementType().IsPrimitive)
772+
if (mdReturnType.GetElementType().FullName != "System.Void" &&
773+
mdReturnType.GetElementType().FullName != "System.String" &&
774+
mdReturnType.GetElementType().FullName != "System.Object" &&
775+
!mdReturnType.GetElementType().IsPrimitive)
705776
{
706-
set.Add(md.ReturnType.GetElementType().MetadataToken);
777+
set.Add(mdReturnType.GetElementType().MetadataToken);
707778
}
708779
}
709780
}
710-
else if (!md.ReturnType.IsValueType &&
711-
!md.ReturnType.IsPrimitive &&
712-
!md.ReturnType.IsByReference &&
713-
md.ReturnType.FullName != "System.Void" &&
714-
md.ReturnType.FullName != "System.String" &&
715-
md.ReturnType.FullName != "System.Object")
781+
else if (!mdReturnType.IsValueType &&
782+
!mdReturnType.IsPrimitive &&
783+
mdReturnType.FullName != "System.Void" &&
784+
mdReturnType.FullName != "System.String" &&
785+
mdReturnType.FullName != "System.Object")
716786
{
717-
set.Add(md.ReturnType.MetadataToken);
787+
set.Add(mdReturnType.MetadataToken);
718788
}
719789

720790
// generic parameters
@@ -1352,18 +1422,18 @@ private string TokenToString(MetadataToken token)
13521422

13531423
output.Append($"[GenericParam 0x{token.ToUInt32().ToString("X8")}]");
13541424

1355-
if (gp.DeclaringType != null)
1425+
if (gp?.DeclaringType != null)
13561426
{
13571427
output.Append(TokenToString(gp.DeclaringType.MetadataToken));
13581428
output.Append("::");
13591429
}
1360-
else if (gp.DeclaringMethod != null)
1430+
else if (gp?.DeclaringMethod != null)
13611431
{
13621432
output.Append(TokenToString(gp.DeclaringMethod.MetadataToken));
13631433
output.Append("::");
13641434
}
13651435

1366-
output.Append(gp.Name);
1436+
output.Append(gp?.Name);
13671437

13681438
break;
13691439

0 commit comments

Comments
 (0)