Skip to content

Instantly share code, notes, and snippets.

@jbevain
Created October 2, 2009 11:10
Show Gist options
  • Save jbevain/199666 to your computer and use it in GitHub Desktop.
Save jbevain/199666 to your computer and use it in GitHub Desktop.
A tool to rewrite generic constraints for enums and delegates
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SR = System.Reflection;
using Mono.Cecil;
class Program {
const string delegate_constraint = "DelegateConstraintAttribute";
const string enum_constraint = "EnumConstraintAttribute";
static void Main (string [] args)
{
if (args.Length == 0)
Usage ();
var assembly_file = args [0];
if (!File.Exists (assembly_file))
Usage ();
var key_pair_file = args.Length > 1 && File.Exists (args [1]) ? args [1] : null;
var key_pair = key_pair_file != null ? new SR.StrongNameKeyPair (key_pair_file) : null;
var module = ModuleDefinition.ReadModule (assembly_file);
ProcessModule (module);
var attributes = new [] {delegate_constraint, enum_constraint};
foreach (var attribute in attributes) {
var type = module.Types [attribute];
if (type != null)
module.Types.Remove (type);
}
module.Write (args [0], new WriterParameters {
StrongNameKeyPair = key_pair,
});
}
static void ProcessModule (ModuleDefinition module)
{
foreach (var type in module.Types) {
Process (type);
if (!type.HasMethods)
continue;
foreach (var method in type.Methods)
Process (method);
}
}
static void Process (IGenericParameterProvider provider)
{
if (!provider.HasGenericParameters)
return;
foreach (var parameter in provider.GenericParameters)
Process (parameter);
}
static void Process (GenericParameter generic_parameter)
{
if (!generic_parameter.HasCustomAttributes)
return;
var custom_attributes = generic_parameter.CustomAttributes;
for (int i = 0; i < custom_attributes.Count; i++) {
var attribute = custom_attributes [i];
if (IsDelegateConstraintAttribute (attribute)) {
generic_parameter.Attributes &= ~GenericParameterAttributes.ReferenceTypeConstraint;
generic_parameter.Constraints.Insert (0, CreateConstraint ("System", "Delegate", generic_parameter));
custom_attributes.RemoveAt (i--);
} else if (IsEnumConstraintAttribute (attribute)) {
generic_parameter.Attributes &= ~GenericParameterAttributes.NotNullableValueTypeConstraint;
generic_parameter.Constraints.Insert (0, CreateConstraint ("System", "Enum", generic_parameter));
custom_attributes.RemoveAt (i--);
}
}
}
static TypeReference CreateConstraint (string @namespace, string name, GenericParameter generic_parameter)
{
var module = generic_parameter.Module;
var corlib = module.AssemblyReferences.First (a => a.Name == "mscorlib");
return new TypeReference (@namespace, name, corlib, false);
}
static bool IsDelegateConstraintAttribute (CustomAttribute attribute)
{
return IsConstraintAttribute ("DelegateConstraintAttribute", attribute);
}
static bool IsEnumConstraintAttribute (CustomAttribute attribute)
{
return IsConstraintAttribute ("EnumConstraintAttribute", attribute);
}
static bool IsConstraintAttribute (string type, CustomAttribute attribute)
{
return attribute.Constructor.DeclaringType.Name == type;
}
static void Usage ()
{
Console.WriteLine ("patch-constraints assembly [keypair.snk]");
Environment.Exit (1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment