40b32ebdb1a7504b49cf53beb8ff106204b07d53
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil / CustomAttribute.cs
1 //
2 // CustomAttribute.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2010 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30
31 using Mono.Collections.Generic;
32
33 namespace Mono.Cecil {
34
35         public struct CustomAttributeArgument {
36
37                 readonly TypeReference type;
38                 readonly object value;
39
40                 public TypeReference Type {
41                         get { return type; }
42                 }
43
44                 public object Value {
45                         get { return value; }
46                 }
47
48                 public CustomAttributeArgument (TypeReference type, object value)
49                 {
50                         Mixin.CheckType (type);
51                         this.type = type;
52                         this.value = value;
53                 }
54         }
55
56         public struct CustomAttributeNamedArgument {
57
58                 readonly string name;
59                 readonly CustomAttributeArgument argument;
60
61                 public string Name {
62                         get { return name; }
63                 }
64
65                 public CustomAttributeArgument Argument {
66                         get { return argument; }
67                 }
68
69                 public CustomAttributeNamedArgument (string name, CustomAttributeArgument argument)
70                 {
71                         Mixin.CheckName (name);
72                         this.name = name;
73                         this.argument = argument;
74                 }
75         }
76
77         public interface ICustomAttribute {
78
79                 TypeReference AttributeType { get; }
80
81                 bool HasFields { get; }
82                 bool HasProperties { get; }
83                 Collection<CustomAttributeNamedArgument> Fields { get; }
84                 Collection<CustomAttributeNamedArgument> Properties { get; }
85         }
86
87         public sealed class CustomAttribute : ICustomAttribute {
88
89                 readonly internal uint signature;
90                 internal bool resolved;
91                 MethodReference constructor;
92                 byte [] blob;
93                 internal Collection<CustomAttributeArgument> arguments;
94                 internal Collection<CustomAttributeNamedArgument> fields;
95                 internal Collection<CustomAttributeNamedArgument> properties;
96
97                 public MethodReference Constructor {
98                         get { return constructor; }
99                         set { constructor = value; }
100                 }
101
102                 public TypeReference AttributeType {
103                         get { return constructor.DeclaringType; }
104                 }
105
106                 public bool IsResolved {
107                         get { return resolved; }
108                 }
109
110                 public bool HasConstructorArguments {
111                         get {
112                                 Resolve ();
113
114                                 return !arguments.IsNullOrEmpty ();
115                         }
116                 }
117
118                 public Collection<CustomAttributeArgument> ConstructorArguments {
119                         get {
120                                 Resolve ();
121
122                                 return arguments ?? (arguments = new Collection<CustomAttributeArgument> ());
123                         }
124                 }
125
126                 public bool HasFields {
127                         get {
128                                 Resolve ();
129
130                                 return !fields.IsNullOrEmpty ();
131                         }
132                 }
133
134                 public Collection<CustomAttributeNamedArgument> Fields {
135                         get {
136                                 Resolve ();
137
138                                 return fields ?? (fields = new Collection<CustomAttributeNamedArgument> ());
139                         }
140                 }
141
142                 public bool HasProperties {
143                         get {
144                                 Resolve ();
145
146                                 return !properties.IsNullOrEmpty ();
147                         }
148                 }
149
150                 public Collection<CustomAttributeNamedArgument> Properties {
151                         get {
152                                 Resolve ();
153
154                                 return properties ?? (properties = new Collection<CustomAttributeNamedArgument> ());
155                         }
156                 }
157
158                 internal bool HasImage {
159                         get { return constructor != null && constructor.HasImage; }
160                 }
161
162                 internal ModuleDefinition Module {
163                         get { return constructor.Module; }
164                 }
165
166                 internal CustomAttribute (uint signature, MethodReference constructor)
167                 {
168                         this.signature = signature;
169                         this.constructor = constructor;
170                         this.resolved = false;
171                 }
172
173                 public CustomAttribute (MethodReference constructor)
174                 {
175                         this.constructor = constructor;
176                         this.resolved = true;
177                 }
178
179                 public CustomAttribute (MethodReference constructor, byte [] blob)
180                 {
181                         this.constructor = constructor;
182                         this.resolved = false;
183                         this.blob = blob;
184                 }
185
186                 public byte [] GetBlob ()
187                 {
188                         if (blob != null)
189                                 return blob;
190
191                         if (!HasImage || signature == 0)
192                                 throw new NotSupportedException ();
193
194                         return blob = Module.Read (this, (attribute, reader) => reader.ReadCustomAttributeBlob (attribute.signature));
195                 }
196
197                 void Resolve ()
198                 {
199                         if (resolved || !HasImage)
200                                 return;
201
202                         try {
203                                 Module.Read (this, (attribute, reader) => {
204                                         reader.ReadCustomAttributeSignature (attribute);
205                                         return this;
206                                 });
207
208                                 resolved = true;
209                         } catch (ResolutionException) {
210                                 if (arguments != null)
211                                         arguments.Clear ();
212                                 if (fields != null)
213                                         fields.Clear ();
214                                 if (properties != null)
215                                         properties.Clear ();
216
217                                 resolved = false;
218                         }
219                 }
220         }
221
222         static partial class Mixin {
223
224                 public static void CheckName (string name)
225                 {
226                         if (name == null)
227                                 throw new ArgumentNullException ("name");
228                         if (name.Length == 0)
229                                 throw new ArgumentException ("Empty name");
230                 }
231         }
232 }