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 
PropertyBuilder(TypeBuilder typeBuilder, string name, PropertyAttributes attributes, PropertySignature sig, bool patchCallingConvention)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 
SetGetMethod(MethodBuilder mdBuilder)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 
SetSetMethod(MethodBuilder mdBuilder)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 
AddOtherMethod(MethodBuilder mdBuilder)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 
SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)90 		public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
91 		{
92 			SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
93 		}
94 
SetCustomAttribute(CustomAttributeBuilder customBuilder)95 		public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
96 		{
97 			if (customBuilder.KnownCA == KnownCA.SpecialNameAttribute)
98 			{
99 				attributes |= PropertyAttributes.SpecialName;
100 			}
101 			else
102 			{
103 				if (lazyPseudoToken == 0)
104 				{
105 					lazyPseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
106 				}
107 				typeBuilder.ModuleBuilder.SetCustomAttribute(lazyPseudoToken, customBuilder);
108 			}
109 		}
110 
GetRawConstantValue()111 		public override object GetRawConstantValue()
112 		{
113 			if (lazyPseudoToken != 0)
114 			{
115 				return typeBuilder.ModuleBuilder.Constant.GetRawConstantValue(typeBuilder.ModuleBuilder, lazyPseudoToken);
116 			}
117 			throw new InvalidOperationException();
118 		}
119 
120 		public override PropertyAttributes Attributes
121 		{
122 			get { return attributes; }
123 		}
124 
125 		public override bool CanRead
126 		{
127 			get { return getter != null; }
128 		}
129 
130 		public override bool CanWrite
131 		{
132 			get { return setter != null; }
133 		}
134 
GetGetMethod(bool nonPublic)135 		public override MethodInfo GetGetMethod(bool nonPublic)
136 		{
137 			return nonPublic || (getter != null && getter.IsPublic) ? getter : null;
138 		}
139 
GetSetMethod(bool nonPublic)140 		public override MethodInfo GetSetMethod(bool nonPublic)
141 		{
142 			return nonPublic || (setter != null && setter.IsPublic) ? setter : null;
143 		}
144 
GetAccessors(bool nonPublic)145 		public override MethodInfo[] GetAccessors(bool nonPublic)
146 		{
147 			List<MethodInfo> list = new List<MethodInfo>();
148 			foreach (Accessor acc in accessors)
149 			{
150 				AddAccessor(list, nonPublic, acc.Method);
151 			}
152 			return list.ToArray();
153 		}
154 
AddAccessor(List<MethodInfo> list, bool nonPublic, MethodInfo method)155 		private static void AddAccessor(List<MethodInfo> list, bool nonPublic, MethodInfo method)
156 		{
157 			if (method != null && (nonPublic || method.IsPublic))
158 			{
159 				list.Add(method);
160 			}
161 		}
162 
163 		public override Type DeclaringType
164 		{
165 			get { return typeBuilder; }
166 		}
167 
168 		public override string Name
169 		{
170 			get { return name; }
171 		}
172 
173 		public override Module Module
174 		{
175 			get { return typeBuilder.Module; }
176 		}
177 
SetConstant(object defaultValue)178 		public void SetConstant(object defaultValue)
179 		{
180 			if (lazyPseudoToken == 0)
181 			{
182 				lazyPseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
183 			}
184 			attributes |= PropertyAttributes.HasDefault;
185 			typeBuilder.ModuleBuilder.AddConstant(lazyPseudoToken, defaultValue);
186 		}
187 
Bake()188 		internal void Bake()
189 		{
190 			if (patchCallingConvention)
191 			{
192 				sig.HasThis = !this.IsStatic;
193 			}
194 
195 			PropertyTable.Record rec = new PropertyTable.Record();
196 			rec.Flags = (short)attributes;
197 			rec.Name = typeBuilder.ModuleBuilder.Strings.Add(name);
198 			rec.Type = typeBuilder.ModuleBuilder.GetSignatureBlobIndex(sig);
199 			int token = 0x17000000 | typeBuilder.ModuleBuilder.Property.AddRecord(rec);
200 
201 			if (lazyPseudoToken == 0)
202 			{
203 				lazyPseudoToken = token;
204 			}
205 			else
206 			{
207 				typeBuilder.ModuleBuilder.RegisterTokenFixup(lazyPseudoToken, token);
208 			}
209 
210 			foreach (Accessor acc in accessors)
211 			{
212 				AddMethodSemantics(acc.Semantics, acc.Method.MetadataToken, token);
213 			}
214 		}
215 
AddMethodSemantics(short semantics, int methodToken, int propertyToken)216 		private void AddMethodSemantics(short semantics, int methodToken, int propertyToken)
217 		{
218 			MethodSemanticsTable.Record rec = new MethodSemanticsTable.Record();
219 			rec.Semantics = semantics;
220 			rec.Method = methodToken;
221 			rec.Association = propertyToken;
222 			typeBuilder.ModuleBuilder.MethodSemantics.AddRecord(rec);
223 		}
224 
225 		internal override bool IsPublic
226 		{
227 			get
228 			{
229 				foreach (Accessor acc in accessors)
230 				{
231 					if (acc.Method.IsPublic)
232 					{
233 						return true;
234 					}
235 				}
236 				return false;
237 			}
238 		}
239 
240 		internal override bool IsNonPrivate
241 		{
242 			get
243 			{
244 				foreach (Accessor acc in accessors)
245 				{
246 					if ((acc.Method.Attributes & MethodAttributes.MemberAccessMask) > MethodAttributes.Private)
247 					{
248 						return true;
249 					}
250 				}
251 				return false;
252 			}
253 		}
254 
255 		internal override bool IsStatic
256 		{
257 			get
258 			{
259 				foreach (Accessor acc in accessors)
260 				{
261 					if (acc.Method.IsStatic)
262 					{
263 						return true;
264 					}
265 				}
266 				return false;
267 			}
268 		}
269 
270 		internal override bool IsBaked
271 		{
272 			get { return typeBuilder.IsBaked; }
273 		}
274 
GetCurrentToken()275 		internal override int GetCurrentToken()
276 		{
277 			if (typeBuilder.ModuleBuilder.IsSaved && ModuleBuilder.IsPseudoToken(lazyPseudoToken))
278 			{
279 				return typeBuilder.ModuleBuilder.ResolvePseudoToken(lazyPseudoToken);
280 			}
281 			else
282 			{
283 				return lazyPseudoToken;
284 			}
285 		}
286 	}
287 }
288