GetField requires explicit binding arguments
[mono.git] / mcs / mcs / field.cs
1 //
2 // field.cs: All field handlers
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //          Martin Baulig (martin@ximian.com)
6 //          Marek Safar (marek.safar@seznam.cz)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
12 //
13
14 using System;
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Runtime.InteropServices;
19
20 namespace Mono.CSharp
21 {
22         //
23         // Abstract class for all fields
24         //
25         abstract public class FieldBase : MemberBase
26         {
27                 public FieldBuilder FieldBuilder;
28                 protected FieldSpec spec;
29                 public Status status;
30                 protected Expression initializer;
31
32                 [Flags]
33                 public enum Status : byte {
34                         HAS_OFFSET = 4          // Used by FieldMember.
35                 }
36
37                 static readonly string[] attribute_targets = new string [] { "field" };
38
39                 protected FieldBase (DeclSpace parent, FullNamedExpression type, Modifiers mod,
40                                      Modifiers allowed_mod, MemberName name, Attributes attrs)
41                         : base (parent, null, type, mod, allowed_mod | Modifiers.ABSTRACT, Modifiers.PRIVATE,
42                                 name, attrs)
43                 {
44                         if ((mod & Modifiers.ABSTRACT) != 0)
45                                 Report.Error (681, Location, "The modifier 'abstract' is not valid on fields. Try using a property instead");
46                 }
47
48                 public override AttributeTargets AttributeTargets {
49                         get {
50                                 return AttributeTargets.Field;
51                         }
52                 }
53
54                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
55                 {
56                         if (a.Type == pa.FieldOffset) {
57                                 status |= Status.HAS_OFFSET;
58
59                                 if (!Parent.PartialContainer.HasExplicitLayout) {
60                                         Report.Error (636, Location, "The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)");
61                                         return;
62                                 }
63
64                                 if ((ModFlags & Modifiers.STATIC) != 0 || this is Const) {
65                                         Report.Error (637, Location, "The FieldOffset attribute is not allowed on static or const fields");
66                                         return;
67                                 }
68                         }
69
70                         if (a.Type == pa.FixedBuffer) {
71                                 Report.Error (1716, Location, "Do not use 'System.Runtime.CompilerServices.FixedBuffer' attribute. Use the 'fixed' field modifier instead");
72                                 return;
73                         }
74
75 #if false
76                         if (a.Type == pa.MarshalAs) {
77                                 UnmanagedMarshal marshal = a.GetMarshal (this);
78                                 if (marshal != null) {
79                                         FieldBuilder.SetMarshal (marshal);
80                                 }
81                                 return;
82                         }
83 #endif
84                         if ((a.HasSecurityAttribute)) {
85                                 a.Error_InvalidSecurityParent ();
86                                 return;
87                         }
88
89                         if (a.Type == pa.Dynamic) {
90                                 a.Error_MisusedDynamicAttribute ();
91                                 return;
92                         }
93
94                         FieldBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
95                 }
96
97                 protected override bool CheckBase ()
98                 {
99                         if (!base.CheckBase ())
100                                 return false;
101
102                         MemberSpec candidate;
103                         var conflict_symbol = MemberCache.FindBaseMember (this, out candidate);
104                         if (conflict_symbol == null)
105                                 conflict_symbol = candidate;
106
107                         if (conflict_symbol == null) {
108                                 if ((ModFlags & Modifiers.NEW) != 0) {
109                                         Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
110                                                 GetSignatureForError ());
111                                 }
112                         } else {
113                                 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.BACKING_FIELD)) == 0) {
114                                         Report.SymbolRelatedToPreviousError (conflict_symbol);
115                                         Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
116                                                 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
117                                 }
118
119                                 if (conflict_symbol.IsAbstract) {
120                                         Report.SymbolRelatedToPreviousError (conflict_symbol);
121                                         Report.Error (533, Location, "`{0}' hides inherited abstract member `{1}'",
122                                                 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
123                                 }
124                         }
125  
126                         return true;
127                 }
128
129                 public virtual Constant ConvertInitializer (ResolveContext rc, Constant expr)
130                 {
131                         return expr.ConvertImplicitly (rc, MemberType);
132                 }
133
134                 protected override void DoMemberTypeDependentChecks ()
135                 {
136                         base.DoMemberTypeDependentChecks ();
137
138                         if (MemberType.IsGenericParameter)
139                                 return;
140
141                         if (MemberType.IsStatic)
142                                 Error_VariableOfStaticClass (Location, GetSignatureForError (), MemberType, Report);
143
144                         CheckBase ();
145                         IsTypePermitted ();
146                 }
147
148                 //
149                 //   Represents header string for documentation comment.
150                 //
151                 public override string DocCommentHeader {
152                         get { return "F:"; }
153                 }
154
155                 public override void Emit ()
156                 {
157                         if (member_type == InternalType.Dynamic) {
158                                 PredefinedAttributes.Get.Dynamic.EmitAttribute (FieldBuilder);
159                         } else {
160                                 var trans_flags = TypeManager.HasDynamicTypeUsed (member_type);
161                                 if (trans_flags != null) {
162                                         var pa = PredefinedAttributes.Get.DynamicTransform;
163                                         if (pa.Constructor != null || pa.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type, 1))) {
164                                                 FieldBuilder.SetCustomAttribute (new CustomAttributeBuilder (pa.Constructor, new object[] { trans_flags }));
165                                         }
166                                 }
167                         }
168
169                         if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
170                                 PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (FieldBuilder);
171
172                         if (OptAttributes != null) {
173                                 OptAttributes.Emit ();
174                         }
175
176                         if (((status & Status.HAS_OFFSET) == 0) && (ModFlags & (Modifiers.STATIC | Modifiers.BACKING_FIELD)) == 0 && Parent.PartialContainer.HasExplicitLayout) {
177                                 Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ());
178                         }
179
180                         base.Emit ();
181                 }
182
183                 public static void Error_VariableOfStaticClass (Location loc, string variable_name, TypeSpec static_class, Report Report)
184                 {
185                         Report.SymbolRelatedToPreviousError (static_class);
186                         Report.Error (723, loc, "`{0}': cannot declare variables of static types",
187                                 variable_name);
188                 }
189
190                 public Expression Initializer {
191                         get {
192                                 return initializer;
193                         }
194                         set {
195                                 if (value != null) {
196                                         this.initializer = value;
197                                 }
198                         }
199                 }
200
201                 public FieldSpec Spec {
202                         get { return spec; }
203                 }
204
205                 public override string[] ValidAttributeTargets 
206                 {
207                         get {
208                                 return attribute_targets;
209                         }
210                 }
211
212                 protected override bool VerifyClsCompliance ()
213                 {
214                         if (!base.VerifyClsCompliance ())
215                                 return false;
216
217                         if (!MemberType.IsCLSCompliant () || this is FixedField) {
218                                 Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
219                                         GetSignatureForError ());
220                         }
221                         return true;
222                 }
223         }
224
225         //
226         // Field specification
227         //
228         public class FieldSpec : MemberSpec, IInterfaceMemberSpec
229         {
230                 FieldInfo metaInfo;
231                 TypeSpec memberType;
232
233                 public FieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers)
234                         : base (MemberKind.Field, declaringType, definition, modifiers)
235                 {
236                         this.metaInfo = info;
237                         this.memberType = memberType;
238                 }
239
240 #region Properties
241
242                 public bool IsReadOnly {
243                         get {
244                                 return (Modifiers & Modifiers.READONLY) != 0;
245                         }
246                 }
247
248                 public TypeSpec MemberType {
249                         get {
250                                 return memberType;
251                         }
252                 }
253
254 #endregion
255
256                 public FieldInfo GetMetaInfo ()
257                 {
258                         if ((state & StateFlags.PendingMetaInflate) != 0) {
259                                 var decl_meta = DeclaringType.GetMetaInfo ();
260                                 if (DeclaringType.IsTypeBuilder) {
261                                         metaInfo = TypeBuilder.GetField (decl_meta, metaInfo);
262                                 } else {
263                                         var orig_token = metaInfo.MetadataToken;
264                                         metaInfo = decl_meta.GetField (Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
265                                         if (metaInfo.MetadataToken != orig_token)
266                                                 throw new NotImplementedException ("Resolved to wrong meta token");
267
268                                         // What a stupid API, does not work because field handle is imported
269                                         // metaInfo = FieldInfo.GetFieldFromHandle (metaInfo.FieldHandle, DeclaringType.MetaInfo.TypeHandle);
270                                 }
271
272                                 state &= ~StateFlags.PendingMetaInflate;
273                         }
274
275                         return metaInfo;
276                 }
277
278                 public override MemberSpec InflateMember (TypeParameterInflator inflator)
279                 {
280                         var fs = (FieldSpec) base.InflateMember (inflator);
281                         fs.memberType = inflator.Inflate (memberType);
282                         return fs;
283                 }
284
285                 public FieldSpec Mutate (TypeParameterMutator mutator)
286                 {
287                         var decl = DeclaringType;
288                         if (DeclaringType.IsGenericOrParentIsGeneric)
289                                 decl = mutator.Mutate (decl);
290
291                         if (decl == DeclaringType)
292                                 return this;
293
294                         var fs = (FieldSpec) MemberwiseClone ();
295                         fs.declaringType = decl;
296                         fs.state |= StateFlags.PendingMetaInflate;
297
298                         // Gets back FieldInfo in case of metaInfo was inflated
299                         fs.metaInfo = MemberCache.GetMember (DeclaringType.GetDefinition (), this).metaInfo;
300                         return fs;
301                 }
302         }
303
304         /// <summary>
305         /// Fixed buffer implementation
306         /// </summary>
307         public class FixedField : FieldBase
308         {
309                 public const string FixedElementName = "FixedElementField";
310                 static int GlobalCounter = 0;
311                 static object[] ctor_args = new object[] { (short)LayoutKind.Sequential };
312                 static FieldInfo[] fi;
313
314                 TypeBuilder fixed_buffer_type;
315
316                 const Modifiers AllowedModifiers =
317                         Modifiers.NEW |
318                         Modifiers.PUBLIC |
319                         Modifiers.PROTECTED |
320                         Modifiers.INTERNAL |
321                         Modifiers.PRIVATE |
322                         Modifiers.UNSAFE;
323
324                 public FixedField (DeclSpace parent, FullNamedExpression type, Modifiers mod, string name,
325                         Expression size_expr, Attributes attrs, Location loc):
326                         base (parent, type, mod, AllowedModifiers, new MemberName (name, loc), attrs)
327                 {
328                         initializer = new ConstInitializer (this, size_expr);
329                 }
330
331                 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
332                 {
333                         return expr.ImplicitConversionRequired (rc, TypeManager.int32_type, Location);
334                 }
335
336                 public override bool Define ()
337                 {
338                         if (!base.Define ())
339                                 return false;
340
341                         if (!TypeManager.IsPrimitiveType (MemberType)) {
342                                 Report.Error (1663, Location,
343                                         "`{0}': Fixed size buffers type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double",
344                                         GetSignatureForError ());
345                         }                       
346                         
347                         // Create nested fixed buffer container
348                         string name = String.Format ("<{0}>__FixedBuffer{1}", Name, GlobalCounter++);
349                         fixed_buffer_type = Parent.TypeBuilder.DefineNestedType (name, Parent.Module.DefaultCharSetType |
350                                 TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, TypeManager.value_type.GetMetaInfo ());
351
352                         fixed_buffer_type.DefineField (FixedElementName, MemberType.GetMetaInfo (), FieldAttributes.Public);
353                         RootContext.RegisterCompilerGeneratedType (fixed_buffer_type);
354                         
355                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, ModifiersExtensions.FieldAttr (ModFlags));
356                         var element_spec = new FieldSpec (null, this, MemberType, FieldBuilder, ModFlags);
357                         spec = new FixedFieldSpec (Parent.Definition, this, FieldBuilder, element_spec, ModFlags);
358
359                         Parent.MemberCache.AddMember (spec);
360                         return true;
361                 }
362
363                 protected override void DoMemberTypeIndependentChecks ()
364                 {
365                         base.DoMemberTypeIndependentChecks ();
366
367                         if (!IsUnsafe)
368                                 Expression.UnsafeError (Report, Location);
369
370                         if (Parent.PartialContainer.Kind != MemberKind.Struct) {
371                                 Report.Error (1642, Location, "`{0}': Fixed size buffer fields may only be members of structs",
372                                         GetSignatureForError ());
373                         }
374                 }
375
376                 public override void Emit()
377                 {
378                         ResolveContext rc = new ResolveContext (this);
379                         IntConstant buffer_size_const = initializer.Resolve (rc) as IntConstant;
380                         if (buffer_size_const == null)
381                                 return;
382
383                         int buffer_size = buffer_size_const.Value;
384
385                         if (buffer_size <= 0) {
386                                 Report.Error (1665, Location, "`{0}': Fixed size buffers must have a length greater than zero", GetSignatureForError ());
387                                 return;
388                         }
389
390                         int type_size = Expression.GetTypeSize (MemberType);
391
392                         if (buffer_size > int.MaxValue / type_size) {
393                                 Report.Error (1664, Location, "Fixed size buffer `{0}' of length `{1}' and type `{2}' exceeded 2^31 limit",
394                                         GetSignatureForError (), buffer_size.ToString (), TypeManager.CSharpName (MemberType));
395                                 return;
396                         }
397
398                         buffer_size *= type_size;
399                         EmitFieldSize (buffer_size);
400
401                         PredefinedAttributes.Get.UnsafeValueType.EmitAttribute (fixed_buffer_type);
402
403                         base.Emit ();
404                 }
405
406                 void EmitFieldSize (int buffer_size)
407                 {
408                         CustomAttributeBuilder cab;
409                         PredefinedAttribute pa;
410
411                         pa = PredefinedAttributes.Get.StructLayout;
412                         if (pa.Constructor == null &&
413                                 !pa.ResolveConstructor (Location, TypeManager.short_type))
414                                         return;
415
416                         // TODO: It's not cleared
417                         if (fi == null) {
418                                 var field = (FieldSpec) MemberCache.FindMember (pa.Type, MemberFilter.Field ("Size", null), BindingRestriction.DeclaredOnly);
419                                 fi = new FieldInfo[] { field.GetMetaInfo () };
420                         }
421
422                         object[] fi_val = new object[] { buffer_size };
423                         cab = new CustomAttributeBuilder (pa.Constructor,
424                                 ctor_args, fi, fi_val);
425                         fixed_buffer_type.SetCustomAttribute (cab);
426                         
427                         //
428                         // Don't emit FixedBufferAttribute attribute for private types
429                         //
430                         if ((ModFlags & Modifiers.PRIVATE) != 0)
431                                 return;
432
433                         pa = PredefinedAttributes.Get.FixedBuffer;
434                         if (pa.Constructor == null &&
435                                 !pa.ResolveConstructor (Location, TypeManager.type_type, TypeManager.int32_type))
436                                 return;
437
438                         cab = new CustomAttributeBuilder (pa.Constructor, new object[] { MemberType.GetMetaInfo (), buffer_size });
439                         FieldBuilder.SetCustomAttribute (cab);
440                 }
441
442                 public void SetCharSet (TypeAttributes ta)
443                 {
444                         TypeAttributes cta = fixed_buffer_type.Attributes;
445                         if ((cta & TypeAttributes.UnicodeClass) != (ta & TypeAttributes.UnicodeClass))
446                                 SetTypeBuilderCharSet ((cta & ~TypeAttributes.AutoClass) | TypeAttributes.UnicodeClass);
447                         else if ((cta & TypeAttributes.AutoClass) != (ta & TypeAttributes.AutoClass))
448                                 SetTypeBuilderCharSet ((cta & ~TypeAttributes.UnicodeClass) | TypeAttributes.AutoClass);
449                         else if (cta == 0 && ta != 0)
450                                 SetTypeBuilderCharSet (cta & ~(TypeAttributes.UnicodeClass | TypeAttributes.AutoClass));
451                 }
452
453                 void SetTypeBuilderCharSet (TypeAttributes ta)
454                 {
455                         MethodInfo mi = typeof (TypeBuilder).GetMethod ("SetCharSet", BindingFlags.Instance | BindingFlags.NonPublic);
456                         if (mi == null) {
457                                 Report.RuntimeMissingSupport (Location, "TypeBuilder::SetCharSet");
458                         } else {
459                                 mi.Invoke (fixed_buffer_type, new object [] { ta });
460                         }
461                 }
462         }
463
464         class FixedFieldSpec : FieldSpec
465         {
466                 readonly FieldSpec element;
467
468                 public FixedFieldSpec (TypeSpec declaringType, IMemberDefinition definition, FieldInfo info, FieldSpec element, Modifiers modifiers)
469                         : base (declaringType, definition, element.MemberType, info, modifiers)
470                 {
471                         this.element = element;
472
473                         // It's never CLS-Compliant
474                         state &= ~StateFlags.CLSCompliant_Undetected;
475                 }
476
477                 public FieldSpec Element {
478                         get {
479                                 return element;
480                         }
481                 }
482
483                 public TypeSpec ElementType {
484                         get {
485                                 return MemberType;
486                         }
487                 }
488         }
489
490         //
491         // The Field class is used to represents class/struct fields during parsing.
492         //
493         public class Field : FieldBase {
494                 // <summary>
495                 //   Modifiers allowed in a class declaration
496                 // </summary>
497                 const Modifiers AllowedModifiers =
498                         Modifiers.NEW |
499                         Modifiers.PUBLIC |
500                         Modifiers.PROTECTED |
501                         Modifiers.INTERNAL |
502                         Modifiers.PRIVATE |
503                         Modifiers.STATIC |
504                         Modifiers.VOLATILE |
505                         Modifiers.UNSAFE |
506                         Modifiers.READONLY;
507
508                 public Field (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name,
509                               Attributes attrs)
510                         : base (parent, type, mod, AllowedModifiers, name, attrs)
511                 {
512                 }
513
514                 bool CanBeVolatile ()
515                 {
516                         if (TypeManager.IsReferenceType (MemberType))
517                                 return true;
518
519                         if (MemberType == TypeManager.bool_type || MemberType == TypeManager.char_type ||
520                                 MemberType == TypeManager.sbyte_type || MemberType == TypeManager.byte_type ||
521                                 MemberType == TypeManager.short_type || MemberType == TypeManager.ushort_type ||
522                                 MemberType == TypeManager.int32_type || MemberType == TypeManager.uint32_type ||
523                                 MemberType == TypeManager.float_type ||
524                                 MemberType == TypeManager.intptr_type || MemberType == TypeManager.uintptr_type)
525                                 return true;
526
527                         if (MemberType.IsEnum)
528                                 return true;
529
530                         return false;
531                 }
532
533                 public override bool Define ()
534                 {
535                         if (!base.Define ())
536                                 return false;
537
538                         try {
539                                 Type[] required_modifier = null;
540                                 if ((ModFlags & Modifiers.VOLATILE) != 0) {
541                                         if (TypeManager.isvolatile_type == null)
542                                                 TypeManager.isvolatile_type = TypeManager.CoreLookupType (Compiler,
543                                                         "System.Runtime.CompilerServices", "IsVolatile", MemberKind.Class, true);
544
545                                         if (TypeManager.isvolatile_type != null)
546                                                 required_modifier = new Type[] { TypeManager.isvolatile_type.GetMetaInfo () };
547                                 }
548
549                                 FieldBuilder = Parent.TypeBuilder.DefineField (
550                                         Name, member_type.GetMetaInfo (), required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags));
551
552                                 spec = new FieldSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags);
553
554                                 // Don't cache inaccessible fields
555                                 if ((ModFlags & Modifiers.BACKING_FIELD) == 0) {
556                                         Parent.MemberCache.AddMember (spec);
557                                 }
558                         }
559                         catch (ArgumentException) {
560                                 Report.RuntimeMissingSupport (Location, "`void' or `void*' field type");
561                                 return false;
562                         }
563
564                         if (initializer != null) {
565                                 ((TypeContainer) Parent).RegisterFieldForInitialization (this,
566                                         new FieldInitializer (this, initializer, this));
567                         }
568
569                         return true;
570                 }
571
572                 protected override void DoMemberTypeDependentChecks ()
573                 {
574                         if ((ModFlags & Modifiers.BACKING_FIELD) != 0)
575                                 return;
576
577                         base.DoMemberTypeDependentChecks ();
578
579                         if ((ModFlags & Modifiers.VOLATILE) != 0) {
580                                 if (!CanBeVolatile ()) {
581                                         Report.Error (677, Location, "`{0}': A volatile field cannot be of the type `{1}'",
582                                                 GetSignatureForError (), TypeManager.CSharpName (MemberType));
583                                 }
584
585                                 if ((ModFlags & Modifiers.READONLY) != 0) {
586                                         Report.Error (678, Location, "`{0}': A field cannot be both volatile and readonly",
587                                                 GetSignatureForError ());
588                                 }
589                         }
590                 }
591
592                 protected override bool VerifyClsCompliance ()
593                 {
594                         if (!base.VerifyClsCompliance ())
595                                 return false;
596
597                         if ((ModFlags & Modifiers.VOLATILE) != 0) {
598                                 Report.Warning (3026, 1, Location, "CLS-compliant field `{0}' cannot be volatile", GetSignatureForError ());
599                         }
600
601                         return true;
602                 }
603         }
604 }