2 // field.cs: All field handlers
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Martin Baulig (martin@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Runtime.InteropServices;
22 public class FieldDeclarator
24 public FieldDeclarator (SimpleMemberName name, Expression initializer)
27 this.Initializer = initializer;
32 public SimpleMemberName Name { get; private set; }
33 public Expression Initializer { get; private set; }
39 // Abstract class for all fields
41 abstract public class FieldBase : MemberBase
43 protected FieldBuilder FieldBuilder;
44 protected FieldSpec spec;
46 protected Expression initializer;
47 protected List<FieldDeclarator> declarators;
50 public enum Status : byte {
51 HAS_OFFSET = 4 // Used by FieldMember.
54 static readonly string[] attribute_targets = new string [] { "field" };
56 protected FieldBase (DeclSpace parent, FullNamedExpression type, Modifiers mod,
57 Modifiers allowed_mod, MemberName name, Attributes attrs)
58 : base (parent, null, type, mod, allowed_mod | Modifiers.ABSTRACT, Modifiers.PRIVATE,
61 if ((mod & Modifiers.ABSTRACT) != 0)
62 Report.Error (681, Location, "The modifier 'abstract' is not valid on fields. Try using a property instead");
67 public override AttributeTargets AttributeTargets {
69 return AttributeTargets.Field;
73 public Expression Initializer {
78 this.initializer = value;
82 public FieldSpec Spec {
88 public override string[] ValidAttributeTargets {
90 return attribute_targets;
96 public void AddDeclarator (FieldDeclarator declarator)
98 if (declarators == null)
99 declarators = new List<FieldDeclarator> (2);
101 declarators.Add (declarator);
103 // TODO: This will probably break
104 Parent.AddMember (this, declarator.Name.Value);
107 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
109 if (a.Type == pa.FieldOffset) {
110 status |= Status.HAS_OFFSET;
112 if (!Parent.PartialContainer.HasExplicitLayout) {
113 Report.Error (636, Location, "The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)");
117 if ((ModFlags & Modifiers.STATIC) != 0 || this is Const) {
118 Report.Error (637, Location, "The FieldOffset attribute is not allowed on static or const fields");
123 if (a.Type == pa.FixedBuffer) {
124 Report.Error (1716, Location, "Do not use 'System.Runtime.CompilerServices.FixedBuffer' attribute. Use the 'fixed' field modifier instead");
129 if (a.Type == pa.MarshalAs) {
130 UnmanagedMarshal marshal = a.GetMarshal (this);
131 if (marshal != null) {
132 FieldBuilder.SetMarshal (marshal);
137 if ((a.HasSecurityAttribute)) {
138 a.Error_InvalidSecurityParent ();
142 if (a.Type == pa.Dynamic) {
143 a.Error_MisusedDynamicAttribute ();
147 FieldBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
150 protected override bool CheckBase ()
152 if (!base.CheckBase ())
155 MemberSpec candidate;
156 var conflict_symbol = MemberCache.FindBaseMember (this, out candidate);
157 if (conflict_symbol == null)
158 conflict_symbol = candidate;
160 if (conflict_symbol == null) {
161 if ((ModFlags & Modifiers.NEW) != 0) {
162 Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
163 GetSignatureForError ());
166 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.BACKING_FIELD)) == 0) {
167 Report.SymbolRelatedToPreviousError (conflict_symbol);
168 Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
169 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
172 if (conflict_symbol.IsAbstract) {
173 Report.SymbolRelatedToPreviousError (conflict_symbol);
174 Report.Error (533, Location, "`{0}' hides inherited abstract member `{1}'",
175 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
182 public virtual Constant ConvertInitializer (ResolveContext rc, Constant expr)
184 return expr.ConvertImplicitly (rc, MemberType);
187 protected override void DoMemberTypeDependentChecks ()
189 base.DoMemberTypeDependentChecks ();
191 if (MemberType.IsGenericParameter)
194 if (MemberType.IsStatic)
195 Error_VariableOfStaticClass (Location, GetSignatureForError (), MemberType, Report);
202 // Represents header string for documentation comment.
204 public override string DocCommentHeader {
208 public override void Emit ()
210 if (member_type == InternalType.Dynamic) {
211 Compiler.PredefinedAttributes.Dynamic.EmitAttribute (FieldBuilder);
212 } else if (!(Parent is CompilerGeneratedClass) && member_type.HasDynamicElement) {
213 Compiler.PredefinedAttributes.Dynamic.EmitAttribute (FieldBuilder, member_type);
216 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
217 Compiler.PredefinedAttributes.CompilerGenerated.EmitAttribute (FieldBuilder);
219 if (OptAttributes != null) {
220 OptAttributes.Emit ();
223 if (((status & Status.HAS_OFFSET) == 0) && (ModFlags & (Modifiers.STATIC | Modifiers.BACKING_FIELD)) == 0 && Parent.PartialContainer.HasExplicitLayout) {
224 Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ());
230 public static void Error_VariableOfStaticClass (Location loc, string variable_name, TypeSpec static_class, Report Report)
232 Report.SymbolRelatedToPreviousError (static_class);
233 Report.Error (723, loc, "`{0}': cannot declare variables of static types",
237 protected override bool VerifyClsCompliance ()
239 if (!base.VerifyClsCompliance ())
242 if (!MemberType.IsCLSCompliant () || this is FixedField) {
243 Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
244 GetSignatureForError ());
251 // Field specification
253 public class FieldSpec : MemberSpec, IInterfaceMemberSpec
258 public FieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers)
259 : base (MemberKind.Field, declaringType, definition, modifiers)
261 this.metaInfo = info;
262 this.memberType = memberType;
267 public bool IsReadOnly {
269 return (Modifiers & Modifiers.READONLY) != 0;
273 public TypeSpec MemberType {
281 public FieldInfo GetMetaInfo ()
283 if ((state & StateFlags.PendingMetaInflate) != 0) {
284 var decl_meta = DeclaringType.GetMetaInfo ();
285 if (DeclaringType.IsTypeBuilder) {
286 metaInfo = TypeBuilder.GetField (decl_meta, metaInfo);
288 var orig_token = metaInfo.MetadataToken;
289 metaInfo = decl_meta.GetField (Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
290 if (metaInfo.MetadataToken != orig_token)
291 throw new NotImplementedException ("Resolved to wrong meta token");
293 // What a stupid API, does not work because field handle is imported
294 // metaInfo = FieldInfo.GetFieldFromHandle (metaInfo.FieldHandle, DeclaringType.MetaInfo.TypeHandle);
297 state &= ~StateFlags.PendingMetaInflate;
303 public override MemberSpec InflateMember (TypeParameterInflator inflator)
305 var fs = (FieldSpec) base.InflateMember (inflator);
306 fs.memberType = inflator.Inflate (memberType);
310 public FieldSpec Mutate (TypeParameterMutator mutator)
312 var decl = DeclaringType;
313 if (DeclaringType.IsGenericOrParentIsGeneric)
314 decl = mutator.Mutate (decl);
316 if (decl == DeclaringType)
319 var fs = (FieldSpec) MemberwiseClone ();
320 fs.declaringType = decl;
321 fs.state |= StateFlags.PendingMetaInflate;
323 // Gets back FieldInfo in case of metaInfo was inflated
324 fs.metaInfo = MemberCache.GetMember (TypeParameterMutator.GetMemberDeclaringType (DeclaringType), this).metaInfo;
330 /// Fixed buffer implementation
332 public class FixedField : FieldBase
334 public const string FixedElementName = "FixedElementField";
335 static int GlobalCounter = 0;
336 static object[] ctor_args = new object[] { (short)LayoutKind.Sequential };
337 static FieldInfo[] fi;
339 TypeBuilder fixed_buffer_type;
341 const Modifiers AllowedModifiers =
344 Modifiers.PROTECTED |
349 public FixedField (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs)
350 : base (parent, type, mod, AllowedModifiers, name, attrs)
354 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
356 return expr.ImplicitConversionRequired (rc, TypeManager.int32_type, Location);
359 public override bool Define ()
364 if (!TypeManager.IsPrimitiveType (MemberType)) {
365 Report.Error (1663, Location,
366 "`{0}': Fixed size buffers type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double",
367 GetSignatureForError ());
368 } else if (declarators != null) {
369 var t = new TypeExpression (MemberType, TypeExpression.Location);
370 int index = Parent.PartialContainer.Fields.IndexOf (this);
371 foreach (var d in declarators) {
372 var f = new FixedField (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
373 f.initializer = d.Initializer;
374 ((ConstInitializer) f.initializer).Name = d.Name.Value;
375 Parent.PartialContainer.Fields.Insert (++index, f);
379 // Create nested fixed buffer container
380 string name = String.Format ("<{0}>__FixedBuffer{1}", Name, GlobalCounter++);
381 fixed_buffer_type = Parent.TypeBuilder.DefineNestedType (name, Parent.Module.DefaultCharSetType |
382 TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, TypeManager.value_type.GetMetaInfo ());
384 fixed_buffer_type.DefineField (FixedElementName, MemberType.GetMetaInfo (), FieldAttributes.Public);
385 RootContext.RegisterCompilerGeneratedType (fixed_buffer_type);
387 FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, ModifiersExtensions.FieldAttr (ModFlags));
388 var element_spec = new FieldSpec (null, this, MemberType, FieldBuilder, ModFlags);
389 spec = new FixedFieldSpec (Parent.Definition, this, FieldBuilder, element_spec, ModFlags);
391 Parent.MemberCache.AddMember (spec);
395 protected override void DoMemberTypeIndependentChecks ()
397 base.DoMemberTypeIndependentChecks ();
400 Expression.UnsafeError (Report, Location);
402 if (Parent.PartialContainer.Kind != MemberKind.Struct) {
403 Report.Error (1642, Location, "`{0}': Fixed size buffer fields may only be members of structs",
404 GetSignatureForError ());
408 public override void Emit()
410 ResolveContext rc = new ResolveContext (this);
411 IntConstant buffer_size_const = initializer.Resolve (rc) as IntConstant;
412 if (buffer_size_const == null)
415 int buffer_size = buffer_size_const.Value;
417 if (buffer_size <= 0) {
418 Report.Error (1665, Location, "`{0}': Fixed size buffers must have a length greater than zero", GetSignatureForError ());
422 int type_size = Expression.GetTypeSize (MemberType);
424 if (buffer_size > int.MaxValue / type_size) {
425 Report.Error (1664, Location, "Fixed size buffer `{0}' of length `{1}' and type `{2}' exceeded 2^31 limit",
426 GetSignatureForError (), buffer_size.ToString (), TypeManager.CSharpName (MemberType));
430 buffer_size *= type_size;
431 EmitFieldSize (buffer_size);
433 Compiler.PredefinedAttributes.UnsafeValueType.EmitAttribute (fixed_buffer_type);
438 void EmitFieldSize (int buffer_size)
440 CustomAttributeBuilder cab;
441 PredefinedAttribute pa;
443 pa = Compiler.PredefinedAttributes.StructLayout;
444 if (pa.Constructor == null &&
445 !pa.ResolveConstructor (Location, TypeManager.short_type))
448 // TODO: It's not cleared
450 var field = (FieldSpec) MemberCache.FindMember (pa.Type, MemberFilter.Field ("Size", null), BindingRestriction.DeclaredOnly);
451 fi = new FieldInfo[] { field.GetMetaInfo () };
454 object[] fi_val = new object[] { buffer_size };
455 cab = new CustomAttributeBuilder (pa.Constructor,
456 ctor_args, fi, fi_val);
457 fixed_buffer_type.SetCustomAttribute (cab);
460 // Don't emit FixedBufferAttribute attribute for private types
462 if ((ModFlags & Modifiers.PRIVATE) != 0)
465 pa = Compiler.PredefinedAttributes.FixedBuffer;
466 if (pa.Constructor == null &&
467 !pa.ResolveConstructor (Location, TypeManager.type_type, TypeManager.int32_type))
470 cab = new CustomAttributeBuilder (pa.Constructor, new object[] { MemberType.GetMetaInfo (), buffer_size });
471 FieldBuilder.SetCustomAttribute (cab);
474 public void SetCharSet (TypeAttributes ta)
476 TypeAttributes cta = fixed_buffer_type.Attributes;
477 if ((cta & TypeAttributes.UnicodeClass) != (ta & TypeAttributes.UnicodeClass))
478 SetTypeBuilderCharSet ((cta & ~TypeAttributes.AutoClass) | TypeAttributes.UnicodeClass);
479 else if ((cta & TypeAttributes.AutoClass) != (ta & TypeAttributes.AutoClass))
480 SetTypeBuilderCharSet ((cta & ~TypeAttributes.UnicodeClass) | TypeAttributes.AutoClass);
481 else if (cta == 0 && ta != 0)
482 SetTypeBuilderCharSet (cta & ~(TypeAttributes.UnicodeClass | TypeAttributes.AutoClass));
485 void SetTypeBuilderCharSet (TypeAttributes ta)
487 MethodInfo mi = typeof (TypeBuilder).GetMethod ("SetCharSet", BindingFlags.Instance | BindingFlags.NonPublic);
489 Report.RuntimeMissingSupport (Location, "TypeBuilder::SetCharSet");
491 mi.Invoke (fixed_buffer_type, new object [] { ta });
496 class FixedFieldSpec : FieldSpec
498 readonly FieldSpec element;
500 public FixedFieldSpec (TypeSpec declaringType, IMemberDefinition definition, FieldInfo info, FieldSpec element, Modifiers modifiers)
501 : base (declaringType, definition, element.MemberType, info, modifiers)
503 this.element = element;
505 // It's never CLS-Compliant
506 state &= ~StateFlags.CLSCompliant_Undetected;
509 public FieldSpec Element {
515 public TypeSpec ElementType {
523 // The Field class is used to represents class/struct fields during parsing.
525 public class Field : FieldBase {
527 // Modifiers allowed in a class declaration
529 const Modifiers AllowedModifiers =
532 Modifiers.PROTECTED |
540 public Field (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name,
542 : base (parent, type, mod, AllowedModifiers, name, attrs)
546 bool CanBeVolatile ()
548 if (TypeManager.IsReferenceType (MemberType))
551 if (MemberType == TypeManager.bool_type || MemberType == TypeManager.char_type ||
552 MemberType == TypeManager.sbyte_type || MemberType == TypeManager.byte_type ||
553 MemberType == TypeManager.short_type || MemberType == TypeManager.ushort_type ||
554 MemberType == TypeManager.int32_type || MemberType == TypeManager.uint32_type ||
555 MemberType == TypeManager.float_type ||
556 MemberType == TypeManager.intptr_type || MemberType == TypeManager.uintptr_type)
559 if (MemberType.IsEnum)
565 public override bool Define ()
570 Type[] required_modifier = null;
571 if ((ModFlags & Modifiers.VOLATILE) != 0) {
572 if (TypeManager.isvolatile_type == null)
573 TypeManager.isvolatile_type = TypeManager.CoreLookupType (Compiler,
574 "System.Runtime.CompilerServices", "IsVolatile", MemberKind.Class, true);
576 if (TypeManager.isvolatile_type != null)
577 required_modifier = new Type[] { TypeManager.isvolatile_type.GetMetaInfo () };
580 FieldBuilder = Parent.TypeBuilder.DefineField (
581 Name, member_type.GetMetaInfo (), required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags));
583 spec = new FieldSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags);
585 // Don't cache inaccessible fields
586 if ((ModFlags & Modifiers.BACKING_FIELD) == 0) {
587 Parent.MemberCache.AddMember (spec);
590 if (initializer != null) {
591 ((TypeContainer) Parent).RegisterFieldForInitialization (this,
592 new FieldInitializer (spec, initializer, this));
595 if (declarators != null) {
596 var t = new TypeExpression (MemberType, TypeExpression.Location);
597 int index = Parent.PartialContainer.Fields.IndexOf (this);
598 foreach (var d in declarators) {
599 var f = new Field (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
600 if (d.Initializer != null)
601 f.initializer = d.Initializer;
603 Parent.PartialContainer.Fields.Insert (++index, f);
610 protected override void DoMemberTypeDependentChecks ()
612 if ((ModFlags & Modifiers.BACKING_FIELD) != 0)
615 base.DoMemberTypeDependentChecks ();
617 if ((ModFlags & Modifiers.VOLATILE) != 0) {
618 if (!CanBeVolatile ()) {
619 Report.Error (677, Location, "`{0}': A volatile field cannot be of the type `{1}'",
620 GetSignatureForError (), TypeManager.CSharpName (MemberType));
623 if ((ModFlags & Modifiers.READONLY) != 0) {
624 Report.Error (678, Location, "`{0}': A field cannot be both volatile and readonly",
625 GetSignatureForError ());
630 protected override bool VerifyClsCompliance ()
632 if (!base.VerifyClsCompliance ())
635 if ((ModFlags & Modifiers.VOLATILE) != 0) {
636 Report.Warning (3026, 1, Location, "CLS-compliant field `{0}' cannot be volatile", GetSignatureForError ());