// // Author: // Jb Evain (jbevain@gmail.com) // // Copyright (c) 2008 - 2015 Jb Evain // Copyright (c) 2008 - 2011 Novell, Inc. // // Licensed under the MIT/X11 license. // using MonoFN.Collections.Generic; using System; using System.Diagnostics; using System.Threading; namespace MonoFN.Cecil { public struct CustomAttributeArgument { public TypeReference Type { get; } public object Value { get; } public CustomAttributeArgument(TypeReference type, object value) { Mixin.CheckType(type); this.Type = type; this.Value = value; } } public struct CustomAttributeNamedArgument { public string Name { get; } public CustomAttributeArgument Argument { get; } public CustomAttributeNamedArgument(string name, CustomAttributeArgument argument) { Mixin.CheckName(name); this.Name = name; this.Argument = argument; } } public interface ICustomAttribute { TypeReference AttributeType { get; } bool HasFields { get; } bool HasProperties { get; } bool HasConstructorArguments { get; } Collection Fields { get; } Collection Properties { get; } Collection ConstructorArguments { get; } } [DebuggerDisplay("{AttributeType}")] public sealed class CustomAttribute : ICustomAttribute { internal CustomAttributeValueProjection projection; internal readonly uint signature; internal bool resolved; private byte[] blob; internal Collection arguments; internal Collection fields; internal Collection properties; public MethodReference Constructor { get; set; } public TypeReference AttributeType { get { return Constructor.DeclaringType; } } public bool IsResolved { get { return resolved; } } public bool HasConstructorArguments { get { Resolve(); return !arguments.IsNullOrEmpty(); } } public Collection ConstructorArguments { get { Resolve(); if (arguments == null) Interlocked.CompareExchange(ref arguments, new(), null); return arguments; } } public bool HasFields { get { Resolve(); return !fields.IsNullOrEmpty(); } } public Collection Fields { get { Resolve(); if (fields == null) Interlocked.CompareExchange(ref fields, new(), null); return fields; } } public bool HasProperties { get { Resolve(); return !properties.IsNullOrEmpty(); } } public Collection Properties { get { Resolve(); if (properties == null) Interlocked.CompareExchange(ref properties, new(), null); return properties; } } internal bool HasImage { get { return Constructor != null && Constructor.HasImage; } } internal ModuleDefinition Module { get { return Constructor.Module; } } internal CustomAttribute(uint signature, MethodReference constructor) { this.signature = signature; this.Constructor = constructor; resolved = false; } public CustomAttribute(MethodReference constructor) { this.Constructor = constructor; resolved = true; } public CustomAttribute(MethodReference constructor, byte[] blob) { this.Constructor = constructor; resolved = false; this.blob = blob; } public byte[] GetBlob() { if (blob != null) return blob; if (!HasImage) throw new NotSupportedException(); return Module.Read(ref blob, this, (attribute, reader) => reader.ReadCustomAttributeBlob(attribute.signature)); } private void Resolve() { if (resolved || !HasImage) return; lock (Module.SyncRoot) { if (resolved) return; Module.Read(this, (attribute, reader) => { try { reader.ReadCustomAttributeSignature(attribute); resolved = true; } catch (ResolutionException) { if (arguments != null) arguments.Clear(); if (fields != null) fields.Clear(); if (properties != null) properties.Clear(); resolved = false; } }); } } } }