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