Hi Eyal, The patch looks mostly good. Please use the new interface IRequireResolving I've just commited for the changes in CustomAttribute.
Please also follow the coding guideline used in Cecil. I would also prefer a patch using a parameter instead of the ForceResolving property. Also please send me the patch once it's done instead of commiting, I have to check that everything works fine on the writing part. 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 <[EMAIL PROTECTED]> >> To: Eyal Alaluf <[EMAIL PROTECTED]> >> Cc: mono-devel-list@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 <[EMAIL PROTECTED]> >>> + >>> + 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 <[EMAIL PROTECTED]> >>> * 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@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 <[EMAIL PROTECTED]> > + > + 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 <[EMAIL PROTECTED]> > > * 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@lists.ximian.com > http://lists.ximian.com/mailman/listinfo/mono-devel-list _______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list