[Mono-dev] Parch for Enum support in Custom attributes
Jb Evain
mono at evain.net
Thu Oct 5 13:16:47 EDT 2006
Hi Eyal,
Thanks for working on this. I don't want to commit it as it is, but I'll
surely use part of it. I don't want to load the assembly referenced only
for reading a custom attribute body. Instead, I'll create an interface
that CustomAttribute and SecurityDeclaration will share, and will allow
one to load the content of something that needs to load a reference.
Something like:
CustomAttribute ca = ...;
if (!ca.Read) {
ca.ForceRead ();
}
Otherwise, for a lot of assemblies, Cecil will have to load the corelib
while the user don't necessary need to read the content of the custom
attribute.
Jb
Eyal Alaluf wrote:
> Hi, JB.
>
> Attached is patch for supporting enums in cutom attributes. Support is
> added
> for enums as ctor parameters as fields and as properties.
>
> The main problem with Enums is to identify their underlying integral type.
> Without this integral type the custom attribute cannot be read. The patch
> uses the assembly resolver for this purpose.
>
> I have attached a simple test scenraio with 3 C# files.
> * Test1.cs is a DLL defining enums and an attribute that has enums as
> field properties and ctor params.
> * Test2.cs is another DLL that uses the attribute and enums from Test1.
> This exercise the new code that resolves enum types from another DLL.
> * ReadTest2.cs is an EXE written using Cecil that parses test2.dll and
> prints the custom attributes of its types. It gets as argument the
> path
> to the dll it parses.
> Note that Test1 uses ClassUsageAttaribute from mscorlib. For some reason
> the
> assembly resolver didn't find mscorlib.dll from the GAC when I ran
> ReadTest2
> on Test2 until I put mscorlib.dll in the same dir as Test2 & ReadTest2.
>
> Eyal.
>
>
> ------------------------------------------------------------------------
>
> Index: Mono.Cecil/ReflectionReader.cs
> ===================================================================
> --- Mono.Cecil/ReflectionReader.cs (revision 66216)
> +++ Mono.Cecil/ReflectionReader.cs (working copy)
> @@ -65,7 +65,24 @@
> protected CodeReader m_codeReader;
> protected ISymbolReader m_symbolReader;
>
> - public ModuleDefinition Module {
> + internal AssemblyNameReference Corlib
> + {
> + get
> + {
> + if (m_corlib == null) {
> + foreach (AssemblyNameReference ar in m_module.AssemblyReferences) {
> + if (ar.Name == Constants.Corlib) {
> + m_corlib = ar;
> + break;
> + }
> + }
> + }
> + return m_corlib;
> + }
> + }
> +
> + public ModuleDefinition Module
> + {
> get { return m_module; }
> }
>
> @@ -295,19 +312,11 @@
>
> TypeReference coreType = m_module.TypeReferences [fullName];
> if (coreType == null) {
> - if (m_corlib == null) {
> - foreach (AssemblyNameReference ar in m_module.AssemblyReferences) {
> - if (ar.Name == Constants.Corlib) {
> - m_corlib = ar;
> - break;
> - }
> - }
> - }
>
> string [] parts = fullName.Split ('.');
> if (parts.Length != 2)
> throw new ReflectionException ("Unvalid core type name");
> - coreType = new TypeReference (parts [1], parts [0], m_corlib);
> + coreType = new TypeReference (parts [1], parts [0], Corlib);
> m_module.TypeReferences.Add (coreType);
> }
> if (!coreType.IsValueType) {
> Index: ChangeLog
> ===================================================================
> --- ChangeLog (revision 66226)
> +++ ChangeLog (working copy)
> @@ -1,3 +1,11 @@
> +2006-10-05 Eyal Alaluf <eyala at mainsoft.com>
> +
> + Mono.Cecil/ReflectionReader.cs:
> + Expose Corlib assembly refereice so SignatureReader can ise it.
> + Mono.Cecil.Signatures/SignatureReader.cs:
> + Added support for enums in custom attributes ctors, properties and
> + fields.
> +
> 2006-10-04 Eyal Alaluf <eyala at mainsoft.com>
>
> * Mono.Cecil/StructureReader.cs:
> @@ -2,3 +10,2 @@
> Visit the module we load when a DLL has more then 1 module.
> - Visit the module we load when a DLL has more then 1 module.
> Mono.Cecil/AssemblyNameReference.cs:
> Index: Mono.Cecil.Signatures/SignatureReader.cs
> ===================================================================
> --- Mono.Cecil.Signatures/SignatureReader.cs (revision 66216)
> +++ Mono.Cecil.Signatures/SignatureReader.cs (working copy)
> @@ -587,7 +587,7 @@
> }
>
> CustomAttrib.FixedArg ReadFixedArg (byte [] data, BinaryReader br,
> - bool array, object param, ref bool read)
> + bool array, TypeReference param, ref bool read)
> {
> CustomAttrib.FixedArg fa = new CustomAttrib.FixedArg ();
> if (array) {
> @@ -596,6 +596,7 @@
>
> if (fa.NumElem == 0 || fa.NumElem == 0xffffffff) {
> fa.Elems = new CustomAttrib.Elem [0];
> + fa.NumElem = 0;
> return fa;
> }
>
> @@ -611,6 +612,95 @@
> return fa;
> }
>
> + TypeReference CreateEnumTypeReference (string enumName)
> + {
> + string asmName = null;
> + int asmStart = enumName.IndexOf (',');
> + if (asmStart != -1) {
> + asmName = enumName.Substring (asmStart + 1);
> + enumName = enumName.Substring (0, asmStart);
> + }
> + // Inner class style is reflection style.
> + enumName = enumName.Replace ('+', '/');
> + AssemblyNameReference asm = null;
> + if (asmName == null) {
> + // If no assembly is given then the ECMA standard says the
> + // assembly is either the current one or mscorlib.
> + if (m_reflectReader.Module.Types[enumName] != null)
> + return m_reflectReader.Module.Types[enumName];
> + asm = m_reflectReader.Corlib;
> + }
> + else
> + asm = AssemblyNameReference.Parse (asmName);
> +
> + string[] outers = enumName.Split ('/');
> + string outerfullname = outers[0];
> + string ns = null;
> + int nsIndex = outerfullname.LastIndexOf ('.');
> + if (nsIndex != -1)
> + ns = outerfullname.Substring(0, nsIndex);
> + string name = outerfullname.Substring (nsIndex + 1);
> + TypeReference decType = new TypeReference (name, ns, asm);
> + for (int i = 1; i < outers.Length; i++)
> + {
> + TypeReference t = new TypeReference (outers[i], null, asm);
> + t.DeclaringType = decType;
> + decType = t;
> + }
> + decType.IsValueType = true;
> +
> + return decType;
> + }
> +
> + TypeReference ReadTypeReference (byte[] data, BinaryReader br, out ElementType elemType, out bool array)
> + {
> + array = false;
> + elemType = (ElementType) br.ReadByte ();
> + if (elemType == ElementType.SzArray)
> + {
> + elemType = (ElementType) br.ReadByte ();
> + array = true;
> + }
> +
> + switch (elemType) {
> + case ElementType.Enum :
> + return CreateEnumTypeReference (ReadUTF8String (data, br));
> + case ElementType.Boxed :
> + return m_reflectReader.SearchCoreType (Constants.Object);
> + case ElementType.String :
> + return m_reflectReader.SearchCoreType (Constants.String);
> + case ElementType.Type :
> + return m_reflectReader.SearchCoreType (Constants.Type);
> + case ElementType.Boolean :
> + return m_reflectReader.SearchCoreType (Constants.Boolean);
> + case ElementType.Char :
> + return m_reflectReader.SearchCoreType (Constants.Char);
> + case ElementType.R4 :
> + return m_reflectReader.SearchCoreType (Constants.Single);
> + case ElementType.R8 :
> + return m_reflectReader.SearchCoreType (Constants.Double);
> + case ElementType.I1 :
> + return m_reflectReader.SearchCoreType (Constants.SByte);
> + case ElementType.I2 :
> + return m_reflectReader.SearchCoreType (Constants.Int16);
> + case ElementType.I4 :
> + return m_reflectReader.SearchCoreType (Constants.Int32);
> + case ElementType.I8 :
> + return m_reflectReader.SearchCoreType (Constants.Int64);
> + case ElementType.U1 :
> + return m_reflectReader.SearchCoreType (Constants.Byte);
> + case ElementType.U2 :
> + return m_reflectReader.SearchCoreType (Constants.UInt16);
> + case ElementType.U4 :
> + return m_reflectReader.SearchCoreType (Constants.UInt32);
> + case ElementType.U8 :
> + return m_reflectReader.SearchCoreType (Constants.UInt64);
> + default :
> + throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem: 0x{0}",
> + ((byte) elemType).ToString("x2"));
> + }
> + }
> +
> internal CustomAttrib.NamedArg ReadNamedArg (byte [] data, BinaryReader br, ref bool read)
> {
> CustomAttrib.NamedArg na = new CustomAttrib.NamedArg ();
> @@ -625,42 +715,15 @@
> throw new MetadataFormatException ("Wrong kind of namedarg found: 0x" + kind.ToString("x2"));
>
> bool array = false;
> - na.FieldOrPropType = (ElementType) br.ReadByte ();
> - if (na.FieldOrPropType == ElementType.SzArray) {
> - na.FieldOrPropType = (ElementType) br.ReadByte ();
> - array = true;
> - }
>
> - int next, length;
> + TypeReference elemType = ReadTypeReference (data, br, out na.FieldOrPropType, out array);
>
> - if (na.FieldOrPropType == ElementType.Enum) {
> - read = false;
> - return na;
> - }
> + na.FieldOrPropName = ReadUTF8String (data, br);
> + na.FixedArg = ReadFixedArg (data, br, array, elemType, ref read);
>
> - length = Utilities.ReadCompressedInteger (data, (int) br.BaseStream.Position, out next);
> - br.BaseStream.Position = next;
> -
> - // COMPACT FRAMEWORK NOTE: Encoding.GetString(byte[]) is not supported.
> - byte [] bytes = br.ReadBytes (length);
> - na.FieldOrPropName = Encoding.UTF8.GetString (bytes, 0, bytes.Length);
> -
> - na.FixedArg = ReadFixedArg (data, br, array, na.FieldOrPropType, ref read);
> -
> return na;
> }
>
> - // i hate this construction, should find something better
> - CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, object param, ref bool read)
> - {
> - if (param is TypeReference)
> - return ReadElem (data, br, param as TypeReference, ref read);
> - else if (param is ElementType)
> - return ReadElem (data, br, (ElementType) param, ref read);
> - else
> - throw new MetadataFormatException ("Wrong parameter for ReadElem: " + param.GetType ().FullName);
> - }
> -
> CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, TypeReference elemType, ref bool read)
> {
> CustomAttrib.Elem elem = new CustomAttrib.Elem ();
> @@ -668,11 +731,20 @@
> string elemName = elemType.FullName;
>
> if (elemName == Constants.Object) {
> - ElementType elementType = (ElementType) br.ReadByte ();
> - elem = ReadElem (data, br, elementType, ref read);
> + bool array;
> + elemType = ReadTypeReference (data, br, out elem.FieldOrPropType, out array);
> +
> + if (array) {
> + read = false; // Don't know how to represent arrays as an object value.
> + return elem;
> + }
> + else if (elemType.FullName == Constants.Object)
> + throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem after boxed prefix: 0x{0}",
> + ((byte) elem.FieldOrPropType).ToString("x2"));
> +
> + elem = ReadElem (data, br, elemType, ref read);
> elem.String = elem.Simple = elem.Type = false;
> elem.BoxedValueType = true;
> - elem.FieldOrPropType = elementType;
> return elem;
> }
>
> @@ -694,19 +766,45 @@
> elem.Value = null;
> br.BaseStream.Position++;
> } else {
> - int next, length = Utilities.ReadCompressedInteger (data, (int) br.BaseStream.Position, out next);
> - br.BaseStream.Position = next;
> - // COMPACT FRAMEWORK NOTE: Encoding.GetString(byte[]) is not supported.
> - byte [] bytes = br.ReadBytes (length);
> - elem.Value = Encoding.UTF8.GetString (bytes, 0, bytes.Length);
> + elem.Value = ReadUTF8String (data, br);
> }
> -
> return elem;
> }
>
> elem.String = elem.Type = elem.BoxedValueType = false;
> + if (!readSimpleValue (br, ref elem, elem.ElemType)) {
> + TypeReference typeRef = GetEnumUnderlyingType (elem.ElemType);
> + if (typeRef == null || !readSimpleValue (br, ref elem, typeRef))
> + read = false;
> + }
>
> - switch (elemName) {
> + return elem;
> + }
> +
> + private IAssemblyResolver AssemblyResolver
> + {
> + get
> + {
> + return m_reflectReader.Module.Assembly.Resolver;
> + }
> + }
> +
> + private TypeReference GetEnumUnderlyingType (TypeReference enumType)
> + {
> + TypeDefinition type = enumType as TypeDefinition;
> + if (type == null && AssemblyResolver != null)
> + {
> + AssemblyDefinition asm = AssemblyResolver.Resolve (enumType.Scope.Name);
> + type = asm.MainModule.Types[enumType.FullName];
> + }
> + if (type != null && type.IsEnum)
> + return type.Fields.GetField ("value__").FieldType;
> + return null;
> + }
> +
> + bool readSimpleValue (BinaryReader br, ref CustomAttrib.Elem elem, TypeReference type)
> + {
> + switch (type.FullName) {
> case Constants.Boolean :
> elem.Value = br.ReadByte () == 1;
> break;
> @@ -744,120 +842,12 @@
> elem.Value = br.ReadUInt64 ();
> break;
> default : // enum
> - read = false;
> - return elem;
> + return false;
> }
> -
> elem.Simple = true;
> - return elem;
> + return true;
> }
>
> - // elem in named args, only have an ElementType
> - CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, ElementType elemType, ref bool read)
> - {
> - CustomAttrib.Elem elem = new CustomAttrib.Elem ();
> -
> - if (elemType == ElementType.Boxed) {
> - ElementType elementType = (ElementType) br.ReadByte ();
> - elem = ReadElem (data, br, elementType, ref read);
> - elem.String = elem.Simple = elem.Type = false;
> - elem.BoxedValueType = true;
> - elem.FieldOrPropType = elementType;
> - return elem;
> - }
> -
> - if (elemType == ElementType.Type || elemType == ElementType.String) { // type or string
> - switch (elemType) {
> - case ElementType.String :
> - elem.String = true;
> - elem.BoxedValueType = elem.Simple = elem.Type = false;
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.String);
> - break;
> - case ElementType.Type :
> - elem.Type = true;
> - elem.BoxedValueType = elem.Simple = elem.String = false;
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Type);
> - break;
> - }
> -
> - if (data [br.BaseStream.Position] == 0xff) { // null
> - elem.Value = null;
> - br.BaseStream.Position++;
> - } else {
> - int next, length = Utilities.ReadCompressedInteger (data, (int) br.BaseStream.Position, out next);
> - br.BaseStream.Position = next;
> - // COMPACT FRAMEWORK NOTE: Encoding.GetString(byte[]) is not supported.
> - byte [] bytes = br.ReadBytes (length);
> - elem.Value = Encoding.UTF8.GetString (bytes, 0, bytes.Length);
> - }
> -
> - return elem;
> - }
> -
> - elem.String = elem.Type = elem.BoxedValueType = false;
> -
> - switch (elemType) {
> - case ElementType.Boolean :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Boolean);
> - elem.Value = br.ReadByte () == 1;
> - break;
> - case ElementType.Char :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Char);
> - elem.Value = (char) br.ReadUInt16 ();
> - break;
> - case ElementType.R4 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Single);
> - elem.Value = br.ReadSingle ();
> - break;
> - case ElementType.R8 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Double);
> - elem.Value = br.ReadDouble ();
> - break;
> - case ElementType.I1 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.SByte);
> - elem.Value = br.ReadSByte ();
> - break;
> - case ElementType.I2 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Int16);
> - elem.Value = br.ReadInt16 ();
> - break;
> - case ElementType.I4 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Int32);
> - elem.Value = br.ReadInt32 ();
> - break;
> - case ElementType.I8 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Int64);
> - elem.Value = br.ReadInt64 ();
> - break;
> - case ElementType.U1 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.Byte);
> - elem.Value = br.ReadByte ();
> - break;
> - case ElementType.U2 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.UInt16);
> - elem.Value = br.ReadUInt16 ();
> - break;
> - case ElementType.U4 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.UInt32);
> - elem.Value = br.ReadUInt32 ();
> - break;
> - case ElementType.U8 :
> - elem.ElemType = m_reflectReader.SearchCoreType (Constants.UInt64);
> - elem.Value = br.ReadUInt64 ();
> - break;
> - case ElementType.Enum :
> - read = false;
> - return elem;
> - default :
> - throw new MetadataFormatException ("Non valid type in CustomAttrib.Elem: 0x{0}",
> - ((byte) elemType).ToString("x2"));
> - }
> -
> - read = true;
> - elem.Simple = true;
> - return elem;
> - }
> -
> MarshalSig ReadMarshalSig (byte [] data)
> {
> int start;
> @@ -905,14 +895,21 @@
> return ms;
> }
>
> + static internal string ReadUTF8String (byte [] data, BinaryReader br)
> + {
> + int start = (int)br.BaseStream.Position;
> + string val = ReadUTF8String (data, start, out start);
> + br.BaseStream.Position = start;
> + return val;
> + }
> +
> static internal string ReadUTF8String (byte [] data, int pos, out int start)
> {
> int length = Utilities.ReadCompressedInteger (data, pos, out start);
> - byte [] str = new byte [length];
> - Buffer.BlockCopy (data, start, str, 0, length);
> + pos = start;
> start += length;
> - // COMPACT FRAMEWORK NOTE: Encoding.GetString(byte[]) is not supported.
> - return Encoding.UTF8.GetString (str, 0, str.Length);
> + // COMPACT FRAMEWORK NOTE: Encoding.GetString (byte[]) is not supported.
> + return Encoding.UTF8.GetString (data, pos, length);
> }
> }
> }
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Mono-devel-list mailing list
> Mono-devel-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list
More information about the Mono-devel-list
mailing list