[Mono-dev] Parch for Enum support in Custom attributes

Eyal Alaluf eyala at mainsoft.com
Mon Oct 9 08:33:46 EDT 2006


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
>
-------------- next part --------------
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);
 		}
 	}
 }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mytests.zip
Type: application/zip
Size: 1716 bytes
Desc: 
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20061009/288a139a/attachment.zip 


More information about the Mono-devel-list mailing list