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;
23 // Abstract class for all fields
25 abstract public class FieldBase : MemberBase
27 public FieldBuilder FieldBuilder;
29 protected Expression initializer;
32 public enum Status : byte {
33 HAS_OFFSET = 4 // Used by FieldMember.
36 static readonly string[] attribute_targets = new string [] { "field" };
38 protected FieldBase (DeclSpace parent, FullNamedExpression type, Modifiers mod,
39 Modifiers allowed_mod, MemberName name, Attributes attrs)
40 : base (parent, null, type, mod, allowed_mod | Modifiers.ABSTRACT, Modifiers.PRIVATE,
43 if ((mod & Modifiers.ABSTRACT) != 0)
44 Report.Error (681, Location, "The modifier 'abstract' is not valid on fields. Try using a property instead");
47 public override AttributeTargets AttributeTargets {
49 return AttributeTargets.Field;
53 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
55 if (a.Type == pa.FieldOffset) {
56 status |= Status.HAS_OFFSET;
58 if (!Parent.PartialContainer.HasExplicitLayout) {
59 Report.Error (636, Location, "The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)");
63 if ((ModFlags & Modifiers.STATIC) != 0 || this is Const) {
64 Report.Error (637, Location, "The FieldOffset attribute is not allowed on static or const fields");
69 if (a.Type == pa.FixedBuffer) {
70 Report.Error (1716, Location, "Do not use 'System.Runtime.CompilerServices.FixedBuffer' attribute. Use the 'fixed' field modifier instead");
75 if (a.Type == pa.MarshalAs) {
76 UnmanagedMarshal marshal = a.GetMarshal (this);
77 if (marshal != null) {
78 FieldBuilder.SetMarshal (marshal);
83 if ((a.HasSecurityAttribute)) {
84 a.Error_InvalidSecurityParent ();
88 if (a.Type == pa.Dynamic) {
89 a.Error_MisusedDynamicAttribute ();
93 FieldBuilder.SetCustomAttribute (cb);
96 protected override bool CheckBase ()
98 if (!base.CheckBase ())
101 MemberInfo conflict_symbol = Parent.PartialContainer.FindBaseMemberWithSameName (Name, false);
102 if (conflict_symbol == null) {
103 if ((ModFlags & Modifiers.NEW) != 0) {
104 Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required", GetSignatureForError ());
109 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE | Modifiers.BACKING_FIELD)) == 0) {
110 Report.SymbolRelatedToPreviousError (conflict_symbol);
111 Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
112 GetSignatureForError (), TypeManager.GetFullNameSignature (conflict_symbol));
118 protected override void DoMemberTypeDependentChecks ()
120 base.DoMemberTypeDependentChecks ();
122 if (TypeManager.IsGenericParameter (MemberType))
125 if (MemberType.IsSealed && MemberType.IsAbstract) {
126 Error_VariableOfStaticClass (Location, GetSignatureForError (), MemberType, Report);
134 // Represents header string for documentation comment.
136 public override string DocCommentHeader {
140 public override void Emit ()
142 if (TypeManager.IsDynamicType (member_type)) {
143 PredefinedAttributes.Get.Dynamic.EmitAttribute (FieldBuilder);
145 var trans_flags = TypeManager.HasDynamicTypeUsed (member_type);
146 if (trans_flags != null) {
147 var pa = PredefinedAttributes.Get.DynamicTransform;
148 if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.bool_type.MakeArrayType ())) {
149 FieldBuilder.SetCustomAttribute (new CustomAttributeBuilder (pa.Constructor, new object[] { trans_flags }));
154 if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
155 PredefinedAttributes.Get.CompilerGenerated.EmitAttribute (FieldBuilder);
157 if (OptAttributes != null) {
158 OptAttributes.Emit ();
161 if (((status & Status.HAS_OFFSET) == 0) && (ModFlags & (Modifiers.STATIC | Modifiers.BACKING_FIELD)) == 0 && Parent.PartialContainer.HasExplicitLayout) {
162 Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ());
168 public static void Error_VariableOfStaticClass (Location loc, string variable_name, Type static_class, Report Report)
170 Report.SymbolRelatedToPreviousError (static_class);
171 Report.Error (723, loc, "`{0}': cannot declare variables of static types",
175 public Expression Initializer {
178 this.initializer = value;
183 protected virtual bool IsFieldClsCompliant {
185 if (FieldBuilder == null)
188 return AttributeTester.IsClsCompliant (FieldBuilder.FieldType);
192 public override string[] ValidAttributeTargets
195 return attribute_targets;
199 protected override bool VerifyClsCompliance ()
201 if (!base.VerifyClsCompliance ())
204 if (!IsFieldClsCompliant) {
205 Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
206 GetSignatureForError ());
211 public void SetAssigned ()
213 caching_flags |= Flags.IsAssigned;
217 interface IFixedBuffer
219 FieldInfo Element { get; }
220 Type ElementType { get; }
223 public class FixedFieldExternal: IFixedBuffer
225 FieldInfo element_field;
227 public FixedFieldExternal (FieldInfo fi)
229 element_field = fi.FieldType.GetField (FixedField.FixedElementName);
232 #region IFixedField Members
234 public FieldInfo Element {
236 return element_field;
240 public Type ElementType {
242 return element_field.FieldType;
250 /// Fixed buffer implementation
252 public class FixedField : FieldBase, IFixedBuffer
254 public const string FixedElementName = "FixedElementField";
255 static int GlobalCounter = 0;
256 static object[] ctor_args = new object[] { (short)LayoutKind.Sequential };
257 static FieldInfo[] fi;
259 TypeBuilder fixed_buffer_type;
260 FieldBuilder element;
261 Expression size_expr;
263 const Modifiers AllowedModifiers =
266 Modifiers.PROTECTED |
271 public FixedField (DeclSpace parent, FullNamedExpression type, Modifiers mod, string name,
272 Expression size_expr, Attributes attrs, Location loc):
273 base (parent, type, mod, AllowedModifiers, new MemberName (name, loc), attrs)
275 if (RootContext.Version < LanguageVersion.ISO_2)
276 Report.FeatureIsNotAvailable (loc, "fixed size buffers");
278 this.size_expr = size_expr;
281 public override bool Define()
286 if (!TypeManager.IsPrimitiveType (MemberType)) {
287 Report.Error (1663, Location, "`{0}': Fixed size buffers type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double",
288 GetSignatureForError ());
291 // Create nested fixed buffer container
292 string name = String.Format ("<{0}>__FixedBuffer{1}", Name, GlobalCounter++);
293 fixed_buffer_type = Parent.TypeBuilder.DefineNestedType (name, Parent.Module.DefaultCharSetType |
294 TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, TypeManager.value_type);
296 element = fixed_buffer_type.DefineField (FixedElementName, MemberType, FieldAttributes.Public);
297 RootContext.RegisterCompilerGeneratedType (fixed_buffer_type);
299 FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, ModifiersExtensions.FieldAttr (ModFlags));
300 Parent.MemberCache.AddMember (FieldBuilder, this);
301 TypeManager.RegisterFieldBase (FieldBuilder, this);
306 protected override void DoMemberTypeIndependentChecks ()
308 base.DoMemberTypeIndependentChecks ();
311 Expression.UnsafeError (Report, Location);
313 if (Parent.PartialContainer.Kind != Kind.Struct) {
314 Report.Error (1642, Location, "`{0}': Fixed size buffer fields may only be members of structs",
315 GetSignatureForError ());
319 public override void Emit()
321 ResolveContext rc = new ResolveContext (this);
322 Constant c = size_expr.ResolveAsConstant (rc, this);
326 IntConstant buffer_size_const = c.ImplicitConversionRequired (rc, TypeManager.int32_type, Location) as IntConstant;
327 if (buffer_size_const == null)
330 int buffer_size = buffer_size_const.Value;
332 if (buffer_size <= 0) {
333 Report.Error (1665, Location, "`{0}': Fixed size buffers must have a length greater than zero", GetSignatureForError ());
337 int type_size = Expression.GetTypeSize (MemberType);
339 if (buffer_size > int.MaxValue / type_size) {
340 Report.Error (1664, Location, "Fixed size buffer `{0}' of length `{1}' and type `{2}' exceeded 2^31 limit",
341 GetSignatureForError (), buffer_size.ToString (), TypeManager.CSharpName (MemberType));
345 buffer_size *= type_size;
346 EmitFieldSize (buffer_size);
348 PredefinedAttributes.Get.UnsafeValueType.EmitAttribute (fixed_buffer_type);
353 void EmitFieldSize (int buffer_size)
355 CustomAttributeBuilder cab;
356 PredefinedAttribute pa;
358 pa = PredefinedAttributes.Get.StructLayout;
359 if (pa.Constructor == null &&
360 !pa.ResolveConstructor (Location, TypeManager.short_type))
363 // TODO: It's not cleared
365 fi = new FieldInfo[] { pa.Type.GetField ("Size") };
367 object[] fi_val = new object[] { buffer_size };
368 cab = new CustomAttributeBuilder (pa.Constructor,
369 ctor_args, fi, fi_val);
370 fixed_buffer_type.SetCustomAttribute (cab);
373 // Don't emit FixedBufferAttribute attribute for private types
375 if ((ModFlags & Modifiers.PRIVATE) != 0)
378 pa = PredefinedAttributes.Get.FixedBuffer;
379 if (pa.Constructor == null &&
380 !pa.ResolveConstructor (Location, TypeManager.type_type, TypeManager.int32_type))
383 cab = new CustomAttributeBuilder (pa.Constructor, new object[] { MemberType, buffer_size });
384 FieldBuilder.SetCustomAttribute (cab);
387 protected override bool IsFieldClsCompliant {
393 public void SetCharSet (TypeAttributes ta)
395 TypeAttributes cta = fixed_buffer_type.Attributes;
396 if ((cta & TypeAttributes.UnicodeClass) != (ta & TypeAttributes.UnicodeClass))
397 SetTypeBuilderCharSet ((cta & ~TypeAttributes.AutoClass) | TypeAttributes.UnicodeClass);
398 else if ((cta & TypeAttributes.AutoClass) != (ta & TypeAttributes.AutoClass))
399 SetTypeBuilderCharSet ((cta & ~TypeAttributes.UnicodeClass) | TypeAttributes.AutoClass);
400 else if (cta == 0 && ta != 0)
401 SetTypeBuilderCharSet (cta & ~(TypeAttributes.UnicodeClass | TypeAttributes.AutoClass));
404 void SetTypeBuilderCharSet (TypeAttributes ta)
406 MethodInfo mi = typeof (TypeBuilder).GetMethod ("SetCharSet", BindingFlags.Instance | BindingFlags.NonPublic);
408 Report.RuntimeMissingSupport (Location, "TypeBuilder::SetCharSet");
410 mi.Invoke (fixed_buffer_type, new object [] { ta });
414 #region IFixedField Members
416 public FieldInfo Element {
422 public Type ElementType {
432 // The Field class is used to represents class/struct fields during parsing.
434 public class Field : FieldBase {
436 // Modifiers allowed in a class declaration
438 const Modifiers AllowedModifiers =
441 Modifiers.PROTECTED |
449 public Field (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name,
451 : base (parent, type, mod, AllowedModifiers, name, attrs)
455 bool CanBeVolatile ()
457 if (TypeManager.IsReferenceType (MemberType))
460 if (MemberType == TypeManager.bool_type || MemberType == TypeManager.char_type ||
461 MemberType == TypeManager.sbyte_type || MemberType == TypeManager.byte_type ||
462 MemberType == TypeManager.short_type || MemberType == TypeManager.ushort_type ||
463 MemberType == TypeManager.int32_type || MemberType == TypeManager.uint32_type ||
464 MemberType == TypeManager.float_type ||
465 MemberType == TypeManager.intptr_type || MemberType == TypeManager.uintptr_type)
468 if (TypeManager.IsEnumType (MemberType))
474 bool CheckStructLayout (Type type, bool isStatic)
476 if (TypeManager.IsBuiltinType (type))
480 if (!TypeManager.IsValueType (type) || TypeManager.IsEqual (type, Parent.TypeBuilder))
484 if (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (type), Parent.TypeBuilder)) {
485 if (!TypeManager.IsGenericType (type))
488 foreach (Type t in TypeManager.GetTypeArguments (type)) {
489 if (!CheckStructLayout (t, false))
495 Report.Error (523, Location,
496 "Struct member `{0}' of type `{1}' causes a cycle in the struct layout",
497 GetSignatureForError (), TypeManager.CSharpName (MemberType));
501 public override bool Define ()
507 Type[] required_modifier = null;
508 if ((ModFlags & Modifiers.VOLATILE) != 0) {
509 if (TypeManager.isvolatile_type == null)
510 TypeManager.isvolatile_type = TypeManager.CoreLookupType (Compiler,
511 "System.Runtime.CompilerServices", "IsVolatile", Kind.Class, true);
513 if (TypeManager.isvolatile_type != null)
514 required_modifier = new Type [] { TypeManager.isvolatile_type };
517 FieldBuilder = Parent.TypeBuilder.DefineField (
518 Name, MemberType, required_modifier, null, ModifiersExtensions.FieldAttr (ModFlags));
520 // Don't cache inaccessible fields
521 if ((ModFlags & Modifiers.BACKING_FIELD) == 0) {
522 Parent.MemberCache.AddMember (FieldBuilder, this);
525 TypeManager.RegisterFieldBase (FieldBuilder, this);
527 catch (ArgumentException) {
528 Report.RuntimeMissingSupport (Location, "`void' or `void*' field type");
532 if (initializer != null) {
533 ((TypeContainer) Parent).RegisterFieldForInitialization (this,
534 new FieldInitializer (FieldBuilder, initializer, this));
536 if (Parent.PartialContainer.Kind == Kind.Struct)
537 CheckStructLayout (member_type, (ModFlags & Modifiers.STATIC) != 0);
543 protected override void DoMemberTypeDependentChecks ()
545 base.DoMemberTypeDependentChecks ();
547 if ((ModFlags & Modifiers.VOLATILE) != 0) {
548 if (!CanBeVolatile ()) {
549 Report.Error (677, Location, "`{0}': A volatile field cannot be of the type `{1}'",
550 GetSignatureForError (), TypeManager.CSharpName (MemberType));
553 if ((ModFlags & Modifiers.READONLY) != 0) {
554 Report.Error (678, Location, "`{0}': A field cannot be both volatile and readonly",
555 GetSignatureForError ());
560 protected override bool VerifyClsCompliance ()
562 if (!base.VerifyClsCompliance ())
565 if ((ModFlags & Modifiers.VOLATILE) != 0) {
566 Report.Warning (3026, 1, Location, "CLS-compliant field `{0}' cannot be volatile", GetSignatureForError ());