[Mono-dev] Parch for Enum support in Custom attributes
Jb Evain
mono at evain.net
Tue Oct 10 09:35:10 EDT 2006
Hi Eyal,
Your patch is in SVN, I've just adapted coding style.
Thanks a lot,
Jb
Eyal Alaluf wrote:
> Hi, JB.
>
> I worked a bit further on the patch and implemented the ForceRead logic
> for custom attributes.
> I aded a ForceResolving property to SignatureReader (it was the easiest way
> with the previous patch I made). If the patch if acceptable I'll prepare a
> separate and smaller patch to simplify SignatureReader abit and remove this
> property (pass it as a parameter).
> Attached is the patch and slightly modified test case.
>
> Eyal.
>
> On Thu, 5 Oct 2006, Jb Evain wrote:
>
>> Date: Thu, 05 Oct 2006 19:16:47 +0200
>> From: Jb Evain <mono at evain.net>
>> To: Eyal Alaluf <eyala at mainsoft.com>
>> Cc: mono-devel-list at lists.ximian.com
>> Subject: Re: [Mono-dev] Parch for Enum support in Custom attributes
>>
>> 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
>>
>
> ------------------------------------------------------------------------
>
> Index: Mono.Cecil/CustomAttribute.cs
>
> ===================================================================
>
> --- Mono.Cecil/CustomAttribute.cs (revision 66447)
>
> +++ Mono.Cecil/CustomAttribute.cs (working copy)
>
> @@ -102,6 +102,19 @@
>
> set { m_blob = value; }
> }
>
> + public bool ForceRead ()
> + {
> + if (IsReadable)
> + return true;
> +
> + ReflectionReader r = m_ctor.DeclaringType.Module.Controller.Reader;
> + CustomAttribute newCa = r.GetCustomAttribute (m_ctor, Blob, true);
> + if (!newCa.IsReadable)
> + return false;
> + newCa.CopyTo (this);
> + return true;
> + }
> +
> public CustomAttribute (MethodReference ctor)
> {
> m_ctor = ctor;
> @@ -135,6 +148,7 @@
>
>
> static void Clone (IDictionary original, IDictionary target)
> {
> + target.Clear ();
> foreach (DictionaryEntry entry in original)
> target.Add (entry.Key, entry.Value);
> }
> @@ -142,19 +156,24 @@
>
> internal static CustomAttribute Clone (CustomAttribute custattr, ImportContext context)
> {
> CustomAttribute ca = new CustomAttribute (context.Import (custattr.Constructor));
> - if (!custattr.IsReadable) {
> - ca.IsReadable = false;
> - ca.Blob = custattr.Blob;
> - return ca;
> + custattr.CopyTo(ca);
> + return ca;
> + }
> +
> + private void CopyTo (CustomAttribute target)
> + {
> + target.IsReadable = IsReadable;
> + if (!IsReadable) {
> + target.Blob = Blob;
> + return;
> }
>
> - foreach (object o in custattr.ConstructorParameters)
> - ca.ConstructorParameters.Add (o);
> - Clone (custattr.Fields, ca.Fields);
> - Clone (custattr.FieldTypes, ca.FieldTypes);
> - Clone (custattr.Properties, ca.Properties);
> - Clone (custattr.PropertyTypes, ca.PropertyTypes);
> - return ca;
> + foreach (object o in ConstructorParameters)
> + target.ConstructorParameters.Add (o);
> + Clone (Fields, target.Fields);
> + Clone (FieldTypes, target.FieldTypes);
> + Clone (Properties, target.Properties);
> + Clone (PropertyTypes, target.PropertyTypes);
> }
>
> public void Accept (IReflectionVisitor visitor)
> Index: Mono.Cecil/ReflectionReader.cs
>
> ===================================================================
>
> --- Mono.Cecil/ReflectionReader.cs (revision 66447)
>
> +++ 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) {
> @@ -355,12 +364,20 @@
>
> }
> }
>
> - public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data)
> + public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data, bool forceResolving)
> {
> + bool keepForceResolving = m_sigReader.ForceResolving;
> + m_sigReader.ForceResolving = forceResolving;
> CustomAttrib sig = m_sigReader.GetCustomAttrib (data, ctor);
> + m_sigReader.ForceResolving = keepForceResolving;
> return BuildCustomAttribute (ctor, sig);
> }
>
> + public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data)
> + {
> + return GetCustomAttribute (ctor, data, false);
> + }
> +
> public override void VisitModuleDefinition (ModuleDefinition mod)
> {
> VisitTypeDefinitionCollection (mod.Types);
> Index: ChangeLog
>
> ===================================================================
>
> --- ChangeLog (revision 66447)
>
> +++ ChangeLog (working copy)
>
> @@ -1,3 +1,17 @@
>
> +2006-10-09 Eyal Alaluf <eyala at mainsoft.com>
> +
> + Mono.Cecil.Signatures/SignatureReader.cs:
> + Added support for enums in custom attributes ctors, properties and
> + fields.
> + Mono.Cecil/CustomAttribute.cs:
> + Add support for rereading custom attributes that contain references
> + to enum in other assemblies.
> + Mono.Cecil/ReflectionReader.cs:
> + Add support for reading custom attributes while resolving enums from
> + other assemblies then the current one.
> + Mono.Cecil/ReflectionReader.cs:
> + Expose Corlib assembly refereice so SignatureReader can ise it.
> +
> 2006-10-09 Jb Evain <jbevain at gmail.com>
>
> * Mono.Cecil/SecurityDeclarationReader.cs:
> @@ -8,7 +22,6 @@
>
>
> * Mono.Cecil/StructureReader.cs:
> 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:
> Allow "PublicToken=null" when parsing an assembly full name.
>
> Index: Mono.Cecil.Signatures/SignatureReader.cs
>
> ===================================================================
>
> --- Mono.Cecil.Signatures/SignatureReader.cs (revision 66447)
>
> +++ Mono.Cecil.Signatures/SignatureReader.cs (working copy)
>
> @@ -41,6 +41,7 @@
>
> MetadataRoot m_root;
> ReflectionReader m_reflectReader;
> byte [] m_blobData;
> + bool m_forceResolving = false;
>
> IDictionary m_signatures;
>
> @@ -54,6 +55,12 @@
>
> m_signatures = new Hashtable ();
> }
>
> + public bool ForceResolving
> + {
> + get { return m_forceResolving; }
> + set { m_forceResolving = value; }
> + }
> +
> public FieldSig GetFieldSig (uint index)
> {
> FieldSig f = m_signatures [index] as FieldSig;
> @@ -587,7 +594,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 +603,7 @@
>
>
> if (fa.NumElem == 0 || fa.NumElem == 0xffffffff) {
> fa.Elems = new CustomAttrib.Elem [0];
> + fa.NumElem = 0;
> return fa;
> }
>
> @@ -611,6 +619,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 +722,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 +738,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 +773,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 && ForceResolving && 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 +849,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 +902,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