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 public void SetCustomAttribute (MethodSpec ctor, byte[] data)
152 FieldBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), data);
155 protected override bool CheckBase ()
157 if (!base.CheckBase ())
160 MemberSpec candidate;
161 var conflict_symbol = MemberCache.FindBaseMember (this, out candidate);
162 if (conflict_symbol == null)
163 conflict_symbol = candidate;
165 if (conflict_symbol == null) {
166 if ((ModFlags & Modifiers.NEW) != 0) {
167 Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
168 GetSignatureForError ());
171 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.BACKING_FIELD)) == 0) {
172 Report.SymbolRelatedToPreviousError (conflict_symbol);
173 Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
174 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
177 if (conflict_symbol.IsAbstract) {
178 Report.SymbolRelatedToPreviousError (conflict_symbol);
179 Report.Error (533, Location, "`{0}' hides inherited abstract member `{1}'",
180 GetSignatureForError (), conflict_symbol.GetSignatureForError ());
187 public virtual Constant ConvertInitializer (ResolveContext rc, Constant expr)
189 return expr.ConvertImplicitly (rc, MemberType);
192 protected override void DoMemberTypeDependentChecks ()
194 base.DoMemberTypeDependentChecks ();
196 if (MemberType.IsGenericParameter)
199 if (MemberType.IsStatic)
200 Error_VariableOfStaticClass (Location, GetSignatureForError (), MemberType, Report);
207 // Represents header string for documentation comment.
209 public override string DocCommentHeader {
213 public override void Emit ()
215 if (member_type == InternalType.Dynamic) {
216 Compiler.PredefinedAttributes.Dynamic.EmitAttribute (FieldBuilder);
217 } else if (!(Parent is CompilerGeneratedClass) && member_type.HasDynamicElement) {
218 Compiler.PredefinedAttributes.Dynamic.EmitAttribute (FieldBuilder, member_type);
221 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
222 Compiler.PredefinedAttributes.CompilerGenerated.EmitAttribute (FieldBuilder);
224 if (OptAttributes != null) {
225 OptAttributes.Emit ();
228 if (((status & Status.HAS_OFFSET) == 0) && (ModFlags & (Modifiers.STATIC | Modifiers.BACKING_FIELD)) == 0 && Parent.PartialContainer.HasExplicitLayout) {
229 Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ());
235 public static void Error_VariableOfStaticClass (Location loc, string variable_name, TypeSpec static_class, Report Report)
237 Report.SymbolRelatedToPreviousError (static_class);
238 Report.Error (723, loc, "`{0}': cannot declare variables of static types",
242 protected override bool VerifyClsCompliance ()
244 if (!base.VerifyClsCompliance ())
247 if (!MemberType.IsCLSCompliant () || this is FixedField) {
248 Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
249 GetSignatureForError ());
256 // Field specification
258 public class FieldSpec : MemberSpec, IInterfaceMemberSpec
263 public FieldSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo info, Modifiers modifiers)
264 : base (MemberKind.Field, declaringType, definition, modifiers)
266 this.metaInfo = info;
267 this.memberType = memberType;
272 public bool IsReadOnly {
274 return (Modifiers & Modifiers.READONLY) != 0;
278 public TypeSpec MemberType {
286 public FieldInfo GetMetaInfo ()
288 if ((state & StateFlags.PendingMetaInflate) != 0) {
289 var decl_meta = DeclaringType.GetMetaInfo ();
290 if (DeclaringType.IsTypeBuilder) {
291 metaInfo = TypeBuilder.GetField (decl_meta, metaInfo);
293 var orig_token = metaInfo.MetadataToken;
294 metaInfo = decl_meta.GetField (Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
295 if (metaInfo.MetadataToken != orig_token)
296 throw new NotImplementedException ("Resolved to wrong meta token");
298 // What a stupid API, does not work because field handle is imported
299 // metaInfo = FieldInfo.GetFieldFromHandle (metaInfo.FieldHandle, DeclaringType.MetaInfo.TypeHandle);
302 state &= ~StateFlags.PendingMetaInflate;
308 public override MemberSpec InflateMember (TypeParameterInflator inflator)
310 var fs = (FieldSpec) base.InflateMember (inflator);
311 fs.memberType = inflator.Inflate (memberType);
315 public FieldSpec Mutate (TypeParameterMutator mutator)
317 var decl = DeclaringType;
318 if (DeclaringType.IsGenericOrParentIsGeneric)
319 decl = mutator.Mutate (decl);
321 if (decl == DeclaringType)
324 var fs = (FieldSpec) MemberwiseClone ();
325 fs.declaringType = decl;
326 fs.state |= StateFlags.PendingMetaInflate;
328 // Gets back FieldInfo in case of metaInfo was inflated
329 fs.metaInfo = MemberCache.GetMember (TypeParameterMutator.GetMemberDeclaringType (DeclaringType), this).metaInfo;
335 /// Fixed buffer implementation
337 public class FixedField : FieldBase
339 public const string FixedElementName = "FixedElementField";
340 static int GlobalCounter = 0;
342 TypeBuilder fixed_buffer_type;
344 const Modifiers AllowedModifiers =
347 Modifiers.PROTECTED |
352 public FixedField (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs)
353 : base (parent, type, mod, AllowedModifiers, name, attrs)
357 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
359 return expr.ImplicitConversionRequired (rc, TypeManager.int32_type, Location);
362 public override bool Define ()
367 if (!TypeManager.IsPrimitiveType (MemberType)) {
368 Report.Error (1663, Location,
369 "`{0}': Fixed size buffers type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double",
370 GetSignatureForError ());
371 } else if (declarators != null) {
372 var t = new TypeExpression (MemberType, TypeExpression.Location);
373 int index = Parent.PartialContainer.Fields.IndexOf (this);
374 foreach (var d in declarators) {
375 var f = new FixedField (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
376 f.initializer = d.Initializer;
377 ((ConstInitializer) f.initializer).Name = d.Name.Value;
378 Parent.PartialContainer.Fields.Insert (++index, f);
382 // Create nested fixed buffer container
383 string name = String.Format ("<{0}>__FixedBuffer{1}", Name, GlobalCounter++);
384 fixed_buffer_type = Parent.TypeBuilder.DefineNestedType (name, Parent.Module.DefaultCharSetType |
385 TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, TypeManager.value_type.GetMetaInfo ());
387 fixed_buffer_type.DefineField (FixedElementName, MemberType.GetMetaInfo (), FieldAttributes.Public);
389 FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, ModifiersExtensions.FieldAttr (ModFlags));
390 var element_spec = new FieldSpec (null, this, MemberType, FieldBuilder, ModFlags);
391 spec = new FixedFieldSpec (Parent.Definition, this, FieldBuilder, element_spec, ModFlags);
393 Parent.MemberCache.AddMember (spec);
397 protected override void DoMemberTypeIndependentChecks ()
399 base.DoMemberTypeIndependentChecks ();
402 Expression.UnsafeError (Report, Location);
404 if (Parent.PartialContainer.Kind != MemberKind.Struct) {
405 Report.Error (1642, Location, "`{0}': Fixed size buffer fields may only be members of structs",
406 GetSignatureForError ());
410 public override void Emit()
412 ResolveContext rc = new ResolveContext (this);
413 IntConstant buffer_size_const = initializer.Resolve (rc) as IntConstant;
414 if (buffer_size_const == null)
417 int buffer_size = buffer_size_const.Value;
419 if (buffer_size <= 0) {
420 Report.Error (1665, Location, "`{0}': Fixed size buffers must have a length greater than zero", GetSignatureForError ());
424 int type_size = Expression.GetTypeSize (MemberType);
426 if (buffer_size > int.MaxValue / type_size) {
427 Report.Error (1664, Location, "Fixed size buffer `{0}' of length `{1}' and type `{2}' exceeded 2^31 limit",
428 GetSignatureForError (), buffer_size.ToString (), TypeManager.CSharpName (MemberType));
432 buffer_size *= type_size;
433 EmitFieldSize (buffer_size);
435 Compiler.PredefinedAttributes.UnsafeValueType.EmitAttribute (fixed_buffer_type);
436 Compiler.PredefinedAttributes.CompilerGenerated.EmitAttribute (fixed_buffer_type);
437 fixed_buffer_type.CreateType ();
442 void EmitFieldSize (int buffer_size)
444 PredefinedAttribute pa;
445 AttributeEncoder encoder;
447 pa = Compiler.PredefinedAttributes.StructLayout;
448 if (pa.Constructor == null && !pa.ResolveConstructor (Location, TypeManager.short_type))
451 var field = pa.GetField ("Size", TypeManager.int32_type, Location);
453 encoder = new AttributeEncoder (false);
454 encoder.Encode ((short)LayoutKind.Sequential);
455 encoder.EncodeNamedFieldArgument (field, new IntConstant (buffer_size, Location));
457 pa.EmitAttribute (fixed_buffer_type, encoder);
461 // Don't emit FixedBufferAttribute attribute for private types
463 if ((ModFlags & Modifiers.PRIVATE) != 0)
466 pa = Compiler.PredefinedAttributes.FixedBuffer;
467 if (pa.Constructor == null && !pa.ResolveConstructor (Location, TypeManager.type_type, TypeManager.int32_type))
470 encoder = new AttributeEncoder (false);
471 encoder.EncodeTypeName (MemberType);
472 encoder.Encode (buffer_size);
473 encoder.EncodeEmptyNamedArguments ();
475 pa.EmitAttribute (FieldBuilder, encoder);
478 public void SetCharSet (TypeAttributes ta)
480 TypeAttributes cta = fixed_buffer_type.Attributes;
481 if ((cta & TypeAttributes.UnicodeClass) != (ta & TypeAttributes.UnicodeClass))
482 SetTypeBuilderCharSet ((cta & ~TypeAttributes.AutoClass) | TypeAttributes.UnicodeClass);
483 else if ((cta & TypeAttributes.AutoClass) != (ta & TypeAttributes.AutoClass))
484 SetTypeBuilderCharSet ((cta & ~TypeAttributes.UnicodeClass) | TypeAttributes.AutoClass);
485 else if (cta == 0 && ta != 0)
486 SetTypeBuilderCharSet (cta & ~(TypeAttributes.UnicodeClass | TypeAttributes.AutoClass));
489 void SetTypeBuilderCharSet (TypeAttributes ta)
491 MethodInfo mi = typeof (TypeBuilder).GetMethod ("SetCharSet", BindingFlags.Instance | BindingFlags.NonPublic);
493 Report.RuntimeMissingSupport (Location, "TypeBuilder::SetCharSet");
495 mi.Invoke (fixed_buffer_type, new object [] { ta });
500 class FixedFieldSpec : FieldSpec
502 readonly FieldSpec element;
504 public FixedFieldSpec (TypeSpec declaringType, IMemberDefinition definition, FieldInfo info, FieldSpec element, Modifiers modifiers)
505 : base (declaringType, definition, element.MemberType, info, modifiers)
507 this.element = element;
509 // It's never CLS-Compliant
510 state &= ~StateFlags.CLSCompliant_Undetected;
513 public FieldSpec Element {
519 public TypeSpec ElementType {
527 // The Field class is used to represents class/struct fields during parsing.
529 public class Field : FieldBase {
531 // Modifiers allowed in a class declaration
533 const Modifiers AllowedModifiers =
536 Modifiers.PROTECTED |
544 public Field (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name,
546 : base (parent, type, mod, AllowedModifiers, name, attrs)
550 bool CanBeVolatile ()
552 if (TypeManager.IsReferenceType (MemberType))
555 if (MemberType == TypeManager.bool_type || MemberType == TypeManager.char_type ||
556 MemberType == TypeManager.sbyte_type || MemberType == TypeManager.byte_type ||
557 MemberType == TypeManager.short_type || MemberType == TypeManager.ushort_type ||
558 MemberType == TypeManager.int32_type || MemberType == TypeManager.uint32_type ||
559 MemberType == TypeManager.float_type ||
560 MemberType == TypeManager.intptr_type || MemberType == TypeManager.uintptr_type)
563 if (MemberType.IsEnum)
569 public override bool Define ()
574 Type[] required_modifier = null;
575 if ((ModFlags & Modifiers.VOLATILE) != 0) {
576 if (TypeManager.isvolatile_type == null)
577 TypeManager.isvolatile_type = TypeManager.CoreLookupType (Compiler,
578 "System.Runtime.CompilerServices", "IsVolatile", MemberKind.Class, true);
580 if (TypeManager.isvolatile_type != null)
581 required_modifier = new Type[] { TypeManager.isvolatile_type.GetMetaInfo () };
584 FieldBuilder = Parent.TypeBuilder.DefineField (
585 Name, member_type.GetMetaInfo (), required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags));
587 spec = new FieldSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags);
589 // Don't cache inaccessible fields
590 if ((ModFlags & Modifiers.BACKING_FIELD) == 0) {
591 Parent.MemberCache.AddMember (spec);
594 if (initializer != null) {
595 ((TypeContainer) Parent).RegisterFieldForInitialization (this,
596 new FieldInitializer (spec, initializer, this));
599 if (declarators != null) {
600 var t = new TypeExpression (MemberType, TypeExpression.Location);
601 int index = Parent.PartialContainer.Fields.IndexOf (this);
602 foreach (var d in declarators) {
603 var f = new Field (Parent, t, ModFlags, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
604 if (d.Initializer != null)
605 f.initializer = d.Initializer;
607 Parent.PartialContainer.Fields.Insert (++index, f);
614 protected override void DoMemberTypeDependentChecks ()
616 if ((ModFlags & Modifiers.BACKING_FIELD) != 0)
619 base.DoMemberTypeDependentChecks ();
621 if ((ModFlags & Modifiers.VOLATILE) != 0) {
622 if (!CanBeVolatile ()) {
623 Report.Error (677, Location, "`{0}': A volatile field cannot be of the type `{1}'",
624 GetSignatureForError (), TypeManager.CSharpName (MemberType));
627 if ((ModFlags & Modifiers.READONLY) != 0) {
628 Report.Error (678, Location, "`{0}': A field cannot be both volatile and readonly",
629 GetSignatureForError ());
634 protected override bool VerifyClsCompliance ()
636 if (!base.VerifyClsCompliance ())
639 if ((ModFlags & Modifiers.VOLATILE) != 0) {
640 Report.Warning (3026, 1, Location, "CLS-compliant field `{0}' cannot be volatile", GetSignatureForError ());