Skip to content
/ cecil Public
forked from jbevain/cecil

Commit

Permalink
Add support for custom attributes on generic constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
jbevain committed Jun 20, 2019
1 parent 749710a commit febbd65
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 27 deletions.
27 changes: 16 additions & 11 deletions Mono.Cecil/AssemblyReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1993,27 +1993,31 @@ public bool HasGenericConstraints (GenericParameter generic_parameter)
{
InitializeGenericConstraints ();

Collection<MetadataToken> mapping;
Collection<Row<uint, MetadataToken>> mapping;
if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
return false;

return mapping.Count > 0;
}

public Collection<TypeReference> ReadGenericConstraints (GenericParameter generic_parameter)
public GenericParameterConstraintCollection ReadGenericConstraints (GenericParameter generic_parameter)
{
InitializeGenericConstraints ();

Collection<MetadataToken> mapping;
Collection<Row<uint, MetadataToken>> mapping;
if (!metadata.TryGetGenericConstraintMapping (generic_parameter, out mapping))
return new Collection<TypeReference> ();
return new GenericParameterConstraintCollection (generic_parameter);

var constraints = new Collection<TypeReference> (mapping.Count);
var constraints = new GenericParameterConstraintCollection (generic_parameter, mapping.Count);

this.context = (IGenericContext) generic_parameter.Owner;

for (int i = 0; i < mapping.Count; i++)
constraints.Add (GetTypeDefOrRef (mapping [i]));
for (int i = 0; i < mapping.Count; i++) {
constraints.Add (
new GenericParameterConstraint (
GetTypeDefOrRef (mapping [i].Col2),
new MetadataToken (TokenType.GenericParamConstraint, mapping [i].Col1)));
}

metadata.RemoveGenericConstraintMapping (generic_parameter);

Expand All @@ -2027,15 +2031,16 @@ void InitializeGenericConstraints ()

var length = MoveTo (Table.GenericParamConstraint);

metadata.GenericConstraints = new Dictionary<uint, Collection<MetadataToken>> (length);
metadata.GenericConstraints = new Dictionary<uint, Collection<Row<uint, MetadataToken>>> (length);

for (int i = 1; i <= length; i++)
for (uint i = 1; i <= length; i++) {
AddGenericConstraintMapping (
ReadTableIndex (Table.GenericParam),
ReadMetadataToken (CodedIndex.TypeDefOrRef));
new Row<uint, MetadataToken> (i, ReadMetadataToken (CodedIndex.TypeDefOrRef)));
}
}

void AddGenericConstraintMapping (uint generic_parameter, MetadataToken constraint)
void AddGenericConstraintMapping (uint generic_parameter, Row<uint, MetadataToken> constraint)
{
metadata.SetGenericConstraintMapping (
generic_parameter,
Expand Down
18 changes: 13 additions & 5 deletions Mono.Cecil/AssemblyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1513,12 +1513,20 @@ void AddConstraints (GenericParameter generic_parameter, GenericParamConstraintT
{
var constraints = generic_parameter.Constraints;

var rid = generic_parameter.token.RID;
var gp_rid = generic_parameter.token.RID;

for (int i = 0; i < constraints.Count; i++)
table.AddRow (new GenericParamConstraintRow (
rid,
MakeCodedRID (GetTypeToken (constraints [i]), CodedIndex.TypeDefOrRef)));
for (int i = 0; i < constraints.Count; i++) {
var constraint = constraints [i];

var rid = table.AddRow (new GenericParamConstraintRow (
gp_rid,
MakeCodedRID (GetTypeToken (constraint.ConstraintType), CodedIndex.TypeDefOrRef)));

constraint.token = new MetadataToken (TokenType.GenericParamConstraint, rid);

if (constraint.HasCustomAttributes)
AddCustomAttributes (constraint);
}
}

void AddInterfaces (TypeDefinition type)
Expand Down
96 changes: 93 additions & 3 deletions Mono.Cecil/GenericParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public sealed class GenericParameter : TypeReference, ICustomAttributeProvider {
internal IGenericParameterProvider owner;

ushort attributes;
Collection<TypeReference> constraints;
GenericParameterConstraintCollection constraints;
Collection<CustomAttribute> custom_attributes;

public GenericParameterAttributes Attributes {
Expand Down Expand Up @@ -52,15 +52,15 @@ public bool HasConstraints {
}
}

public Collection<TypeReference> Constraints {
public Collection<GenericParameterConstraint> Constraints {
get {
if (constraints != null)
return constraints;

if (HasImage)
return Module.Read (ref constraints, this, (generic_parameter, reader) => reader.ReadGenericConstraints (generic_parameter));

return constraints = new Collection<TypeReference> ();
return constraints = new GenericParameterConstraintCollection (this);
}
}

Expand Down Expand Up @@ -265,4 +265,94 @@ protected override void OnRemove (GenericParameter item, int index)
items[i].position = i - 1;
}
}

public sealed class GenericParameterConstraint : ICustomAttributeProvider {

internal GenericParameter generic_parameter;
internal MetadataToken token;

TypeReference constraint_type;
Collection<CustomAttribute> custom_attributes;

public TypeReference ConstraintType {
get { return constraint_type; }
set { constraint_type = value; }
}

public bool HasCustomAttributes {
get {
if (custom_attributes != null)
return custom_attributes.Count > 0;

if (generic_parameter == null)
return false;

return this.GetHasCustomAttributes (generic_parameter.Module);
}
}

public Collection<CustomAttribute> CustomAttributes {
get {
if (generic_parameter == null)
return custom_attributes = new Collection<CustomAttribute> ();

return custom_attributes ?? (this.GetCustomAttributes (ref custom_attributes, generic_parameter.Module));
}
}

public MetadataToken MetadataToken {
get { return token; }
set { token = value; }
}

internal GenericParameterConstraint (TypeReference constraintType, MetadataToken token)
{
this.constraint_type = constraintType;
this.token = token;
}

public GenericParameterConstraint (TypeReference constraintType)
{
Mixin.CheckType (constraintType, Mixin.Argument.constraintType);

this.constraint_type = constraintType;
this.token = new MetadataToken (TokenType.GenericParamConstraint);
}
}

class GenericParameterConstraintCollection : Collection<GenericParameterConstraint>
{
readonly GenericParameter generic_parameter;

internal GenericParameterConstraintCollection (GenericParameter genericParameter)
{
this.generic_parameter = genericParameter;
}

internal GenericParameterConstraintCollection (GenericParameter genericParameter, int length)
: base (length)
{
this.generic_parameter = genericParameter;
}

protected override void OnAdd (GenericParameterConstraint item, int index)
{
item.generic_parameter = generic_parameter;
}

protected override void OnInsert (GenericParameterConstraint item, int index)
{
item.generic_parameter = generic_parameter;
}

protected override void OnSet (GenericParameterConstraint item, int index)
{
item.generic_parameter = generic_parameter;
}

protected override void OnRemove (GenericParameterConstraint item, int index)
{
item.generic_parameter = null;
}
}
}
8 changes: 4 additions & 4 deletions Mono.Cecil/MetadataSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ sealed class MetadataSystem {
internal Dictionary<uint, Row<MethodSemanticsAttributes, MetadataToken>> Semantics;
internal Dictionary<uint, Row<PInvokeAttributes, uint, uint>> PInvokes;
internal Dictionary<MetadataToken, Range []> GenericParameters;
internal Dictionary<uint, Collection<MetadataToken>> GenericConstraints;
internal Dictionary<uint, Collection<Row<uint, MetadataToken>>> GenericConstraints;

internal Document [] Documents;
internal Dictionary<uint, Collection<Row<uint, Range, Range, uint, uint, uint>>> LocalScopes;
Expand Down Expand Up @@ -149,7 +149,7 @@ public void Clear ()
if (Semantics != null) Semantics = new Dictionary<uint, Row<MethodSemanticsAttributes, MetadataToken>> (capacity: 0);
if (PInvokes != null) PInvokes = new Dictionary<uint, Row<PInvokeAttributes, uint, uint>> (capacity: 0);
if (GenericParameters != null) GenericParameters = new Dictionary<MetadataToken, Range []> (capacity: 0);
if (GenericConstraints != null) GenericConstraints = new Dictionary<uint, Collection<MetadataToken>> (capacity: 0);
if (GenericConstraints != null) GenericConstraints = new Dictionary<uint, Collection<Row<uint, MetadataToken>>> (capacity: 0);

Documents = Empty<Document>.Array;
ImportScopes = Empty<ImportDebugInformation>.Array;
Expand Down Expand Up @@ -335,12 +335,12 @@ public void RemoveSecurityDeclarationRange (ISecurityDeclarationProvider owner)
SecurityDeclarations.Remove (owner.MetadataToken);
}

public bool TryGetGenericConstraintMapping (GenericParameter generic_parameter, out Collection<MetadataToken> mapping)
public bool TryGetGenericConstraintMapping (GenericParameter generic_parameter, out Collection<Row<uint, MetadataToken>> mapping)
{
return GenericConstraints.TryGetValue (generic_parameter.token.RID, out mapping);
}

public void SetGenericConstraintMapping (uint gp_rid, Collection<MetadataToken> mapping)
public void SetGenericConstraintMapping (uint gp_rid, Collection<Row<uint, MetadataToken>> mapping)
{
GenericConstraints [gp_rid] = mapping;
}
Expand Down
1 change: 1 addition & 0 deletions Mono.Cecil/ModuleDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,7 @@ public enum Argument {
returnType,
propertyType,
interfaceType,
constraintType,
}

public static void CheckName (object name)
Expand Down
8 changes: 4 additions & 4 deletions Test/Mono.Cecil.Tests/TypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ public void ConstrainedGenericType ()
Assert.IsTrue (t.HasConstraints);
Assert.AreEqual (2, t.Constraints.Count);

Assert.AreEqual ("Zap", t.Constraints [0].FullName);
Assert.AreEqual ("IZoom", t.Constraints [1].FullName);
Assert.AreEqual ("Zap", t.Constraints [0].ConstraintType.FullName);
Assert.AreEqual ("IZoom", t.Constraints [1].ConstraintType.FullName);
});
}

Expand Down Expand Up @@ -132,8 +132,8 @@ public void GenericConstraintOnGenericParameter ()
var t2 = duel.GenericParameters [1];
var t3 = duel.GenericParameters [2];

Assert.AreEqual (t1, t2.Constraints [0]);
Assert.AreEqual (t2, t3.Constraints [0]);
Assert.AreEqual (t1, t2.Constraints [0].ConstraintType);
Assert.AreEqual (t2, t3.Constraints [0].ConstraintType);
});
}

Expand Down

0 comments on commit febbd65

Please sign in to comment.