[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