[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