do not check order sequence if option /order was not used
[mono.git] / mcs / class / IKVM.Reflection / Emit / PropertyBuilder.cs
1 /*
2   Copyright (C) 2008-2011 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Runtime.CompilerServices;
27 using IKVM.Reflection.Writer;
28 using IKVM.Reflection.Metadata;
29
30 namespace IKVM.Reflection.Emit
31 {
32         public sealed class PropertyBuilder : PropertyInfo
33         {
34                 private readonly TypeBuilder typeBuilder;
35                 private readonly string name;
36                 private PropertyAttributes attributes;
37                 private PropertySignature sig;
38                 private MethodBuilder getter;
39                 private MethodBuilder setter;
40                 private readonly List<Accessor> accessors = new List<Accessor>();
41                 private int lazyPseudoToken;
42                 private bool patchCallingConvention;
43
44                 private struct Accessor
45                 {
46                         internal short Semantics;
47                         internal MethodBuilder Method;
48                 }
49
50                 internal PropertyBuilder(TypeBuilder typeBuilder, string name, PropertyAttributes attributes, PropertySignature sig, bool patchCallingConvention)
51                 {
52                         this.typeBuilder = typeBuilder;
53                         this.name = name;
54                         this.attributes = attributes;
55                         this.sig = sig;
56                         this.patchCallingConvention = patchCallingConvention;
57                 }
58
59                 internal override PropertySignature PropertySignature
60                 {
61                         get { return sig; }
62                 }
63
64                 public void SetGetMethod(MethodBuilder mdBuilder)
65                 {
66                         getter = mdBuilder;
67                         Accessor acc;
68                         acc.Semantics = MethodSemanticsTable.Getter;
69                         acc.Method = mdBuilder;
70                         accessors.Add(acc);
71                 }
72
73                 public void SetSetMethod(MethodBuilder mdBuilder)
74                 {
75                         setter = mdBuilder;
76                         Accessor acc;
77                         acc.Semantics = MethodSemanticsTable.Setter;
78                         acc.Method = mdBuilder;
79                         accessors.Add(acc);
80                 }
81
82                 public void AddOtherMethod(MethodBuilder mdBuilder)
83                 {
84                         Accessor acc;
85                         acc.Semantics = MethodSemanticsTable.Other;
86                         acc.Method = mdBuilder;
87                         accessors.Add(acc);
88                 }
89
90                 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
91                 {
92                         SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
93                 }
94
95                 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
96                 {
97                         Universe u = typeBuilder.ModuleBuilder.universe;
98                         if (customBuilder.Constructor.DeclaringType == u.System_Runtime_CompilerServices_SpecialNameAttribute)
99                         {
100                                 attributes |= PropertyAttributes.SpecialName;
101                         }
102                         else
103                         {
104                                 if (lazyPseudoToken == 0)
105                                 {
106                                         lazyPseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
107                                 }
108                                 typeBuilder.ModuleBuilder.SetCustomAttribute(lazyPseudoToken, customBuilder);
109                         }
110                 }
111
112                 public override object GetRawConstantValue()
113                 {
114                         if (lazyPseudoToken != 0)
115                         {
116                                 return typeBuilder.ModuleBuilder.Constant.GetRawConstantValue(typeBuilder.ModuleBuilder, lazyPseudoToken);
117                         }
118                         throw new InvalidOperationException();
119                 }
120
121                 public override PropertyAttributes Attributes
122                 {
123                         get { return attributes; }
124                 }
125
126                 public override bool CanRead
127                 {
128                         get { return getter != null; }
129                 }
130
131                 public override bool CanWrite
132                 {
133                         get { return setter != null; }
134                 }
135
136                 public override MethodInfo GetGetMethod(bool nonPublic)
137                 {
138                         return nonPublic || (getter != null && getter.IsPublic) ? getter : null;
139                 }
140
141                 public override MethodInfo GetSetMethod(bool nonPublic)
142                 {
143                         return nonPublic || (setter != null && setter.IsPublic) ? setter : null;
144                 }
145
146                 public override MethodInfo[] GetAccessors(bool nonPublic)
147                 {
148                         List<MethodInfo> list = new List<MethodInfo>();
149                         foreach (Accessor acc in accessors)
150                         {
151                                 AddAccessor(list, nonPublic, acc.Method);
152                         }
153                         return list.ToArray();
154                 }
155
156                 private static void AddAccessor(List<MethodInfo> list, bool nonPublic, MethodInfo method)
157                 {
158                         if (method != null && (nonPublic || method.IsPublic))
159                         {
160                                 list.Add(method);
161                         }
162                 }
163
164                 public override Type DeclaringType
165                 {
166                         get { return typeBuilder; }
167                 }
168
169                 public override string Name
170                 {
171                         get { return name; }
172                 }
173
174                 public override Module Module
175                 {
176                         get { return typeBuilder.Module; }
177                 }
178
179                 public void SetConstant(object defaultValue)
180                 {
181                         if (lazyPseudoToken == 0)
182                         {
183                                 lazyPseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
184                         }
185                         attributes |= PropertyAttributes.HasDefault;
186                         typeBuilder.ModuleBuilder.AddConstant(lazyPseudoToken, defaultValue);
187                 }
188
189                 internal void Bake()
190                 {
191                         if (patchCallingConvention)
192                         {
193                                 sig.HasThis = !this.IsStatic;
194                         }
195
196                         PropertyTable.Record rec = new PropertyTable.Record();
197                         rec.Flags = (short)attributes;
198                         rec.Name = typeBuilder.ModuleBuilder.Strings.Add(name);
199                         rec.Type = typeBuilder.ModuleBuilder.GetSignatureBlobIndex(sig);
200                         int token = 0x17000000 | typeBuilder.ModuleBuilder.Property.AddRecord(rec);
201
202                         if (lazyPseudoToken == 0)
203                         {
204                                 lazyPseudoToken = token;
205                         }
206                         else
207                         {
208                                 typeBuilder.ModuleBuilder.RegisterTokenFixup(lazyPseudoToken, token);
209                         }
210
211                         foreach (Accessor acc in accessors)
212                         {
213                                 AddMethodSemantics(acc.Semantics, acc.Method.MetadataToken, token);
214                         }
215                 }
216
217                 private void AddMethodSemantics(short semantics, int methodToken, int propertyToken)
218                 {
219                         MethodSemanticsTable.Record rec = new MethodSemanticsTable.Record();
220                         rec.Semantics = semantics;
221                         rec.Method = methodToken;
222                         rec.Association = propertyToken;
223                         typeBuilder.ModuleBuilder.MethodSemantics.AddRecord(rec);
224                 }
225
226                 internal override bool IsPublic
227                 {
228                         get
229                         {
230                                 foreach (Accessor acc in accessors)
231                                 {
232                                         if (acc.Method.IsPublic)
233                                         {
234                                                 return true;
235                                         }
236                                 }
237                                 return false;
238                         }
239                 }
240
241                 internal override bool IsNonPrivate
242                 {
243                         get
244                         {
245                                 foreach (Accessor acc in accessors)
246                                 {
247                                         if ((acc.Method.Attributes & MethodAttributes.MemberAccessMask) > MethodAttributes.Private)
248                                         {
249                                                 return true;
250                                         }
251                                 }
252                                 return false;
253                         }
254                 }
255
256                 internal override bool IsStatic
257                 {
258                         get
259                         {
260                                 foreach (Accessor acc in accessors)
261                                 {
262                                         if (acc.Method.IsStatic)
263                                         {
264                                                 return true;
265                                         }
266                                 }
267                                 return false;
268                         }
269                 }
270
271                 internal override bool IsBaked
272                 {
273                         get { return typeBuilder.IsBaked; }
274                 }
275
276                 internal override int GetCurrentToken()
277                 {
278                         if (typeBuilder.ModuleBuilder.IsSaved && typeBuilder.ModuleBuilder.IsPseudoToken(lazyPseudoToken))
279                         {
280                                 return typeBuilder.ModuleBuilder.ResolvePseudoToken(lazyPseudoToken);
281                         }
282                         else
283                         {
284                                 return lazyPseudoToken;
285                         }
286                 }
287         }
288 }