2 // property.cs: Property based 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
12 // Copyright 2011 Xamarin Inc
16 using System.Collections.Generic;
18 using Mono.CompilerServices.SymbolWriter;
21 using XmlElement = System.Object;
25 using IKVM.Reflection;
26 using IKVM.Reflection.Emit;
28 using System.Reflection;
29 using System.Reflection.Emit;
34 // It is used as a base class for all property based members
35 // This includes properties, indexers, and events
36 public abstract class PropertyBasedMember : InterfaceMemberBase
38 protected PropertyBasedMember (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs)
39 : base (parent, type, mod, allowed_mod, name, attrs)
43 protected void CheckReservedNameConflict (string prefix, MethodSpec accessor)
46 AParametersCollection parameters;
47 if (accessor != null) {
49 parameters = accessor.Parameters;
51 name = prefix + ShortName;
53 name = MemberName.Left + "." + name;
55 if (this is Indexer) {
56 parameters = ((Indexer) this).ParameterInfo;
57 if (prefix[0] == 's') {
58 var data = new IParameterData[parameters.Count + 1];
59 Array.Copy (parameters.FixedParameters, data, data.Length - 1);
60 data[data.Length - 1] = new ParameterData ("value", Parameter.Modifier.NONE);
61 var types = new TypeSpec[data.Length];
62 Array.Copy (parameters.Types, types, data.Length - 1);
63 types[data.Length - 1] = member_type;
65 parameters = new ParametersImported (data, types, false);
69 parameters = ParametersCompiled.CreateFullyResolved (new[] { member_type });
71 parameters = ParametersCompiled.EmptyReadOnlyParameters;
75 var conflict = MemberCache.FindMember (Parent.Definition,
76 new MemberFilter (name, 0, MemberKind.Method, parameters, null),
77 BindingRestriction.DeclaredOnly | BindingRestriction.NoAccessors);
79 if (conflict != null) {
80 Report.SymbolRelatedToPreviousError (conflict);
81 Report.Error (82, Location, "A member `{0}' is already reserved", conflict.GetSignatureForError ());
85 public abstract void PrepareEmit ();
87 protected override bool VerifyClsCompliance ()
89 if (!base.VerifyClsCompliance ())
92 if (!MemberType.IsCLSCompliant ()) {
93 Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
94 GetSignatureForError ());
101 public class PropertySpec : MemberSpec, IInterfaceMemberSpec
107 public PropertySpec (MemberKind kind, TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, PropertyInfo info, Modifiers modifiers)
108 : base (kind, declaringType, definition, modifiers)
111 this.memberType = memberType;
116 public MethodSpec Get {
122 get.IsAccessor = true;
126 public MethodSpec Set {
132 set.IsAccessor = true;
136 public bool HasDifferentAccessibility {
138 return HasGet && HasSet &&
139 (Get.Modifiers & Modifiers.AccessibilityMask) != (Set.Modifiers & Modifiers.AccessibilityMask);
155 public PropertyInfo MetaInfo {
157 if ((state & StateFlags.PendingMetaInflate) != 0)
158 throw new NotSupportedException ();
164 public TypeSpec MemberType {
172 public override MemberSpec InflateMember (TypeParameterInflator inflator)
174 var ps = (PropertySpec) base.InflateMember (inflator);
175 ps.memberType = inflator.Inflate (memberType);
179 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
181 return memberType.ResolveMissingDependencies (this);
186 // Properties and Indexers both generate PropertyBuilders, we use this to share
187 // their common bits.
189 abstract public class PropertyBase : PropertyBasedMember {
191 public class GetMethod : PropertyMethod
193 static readonly string[] attribute_targets = new string [] { "method", "return" };
195 internal const string Prefix = "get_";
197 public GetMethod (PropertyBase method, Modifiers modifiers, Attributes attrs, Location loc)
198 : base (method, Prefix, modifiers, attrs, loc)
202 public override void Define (TypeContainer parent)
204 base.Define (parent);
206 Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, ModFlags);
208 method_data = new MethodData (method, ModFlags, flags, this);
210 method_data.Define (parent.PartialContainer, method.GetFullName (MemberName));
213 public override TypeSpec ReturnType {
215 return method.MemberType;
219 public override ParametersCompiled ParameterInfo {
221 return ParametersCompiled.EmptyReadOnlyParameters;
225 public override string[] ValidAttributeTargets {
227 return attribute_targets;
232 public class SetMethod : PropertyMethod {
234 static readonly string[] attribute_targets = new string[] { "method", "param", "return" };
236 internal const string Prefix = "set_";
238 protected ParametersCompiled parameters;
240 public SetMethod (PropertyBase method, Modifiers modifiers, ParametersCompiled parameters, Attributes attrs, Location loc)
241 : base (method, Prefix, modifiers, attrs, loc)
243 this.parameters = parameters;
246 protected override void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
248 if (a.Target == AttributeTargets.Parameter) {
249 parameters[0].ApplyAttributeBuilder (a, ctor, cdata, pa);
253 base.ApplyToExtraTarget (a, ctor, cdata, pa);
256 public override ParametersCompiled ParameterInfo {
262 public override void Define (TypeContainer parent)
264 parameters.Resolve (this);
266 base.Define (parent);
268 Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, ModFlags);
270 method_data = new MethodData (method, ModFlags, flags, this);
272 method_data.Define (parent.PartialContainer, method.GetFullName (MemberName));
275 public override TypeSpec ReturnType {
277 return Parent.Compiler.BuiltinTypes.Void;
281 public override string[] ValidAttributeTargets {
283 return attribute_targets;
288 static readonly string[] attribute_targets = new string[] { "property" };
290 public abstract class PropertyMethod : AbstractPropertyEventMethod
292 const Modifiers AllowedModifiers =
294 Modifiers.PROTECTED |
298 protected readonly PropertyBase method;
299 protected MethodAttributes flags;
301 public PropertyMethod (PropertyBase method, string prefix, Modifiers modifiers, Attributes attrs, Location loc)
302 : base (method, prefix, attrs, loc)
304 this.method = method;
305 this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, modifiers, 0, loc, Report);
306 this.ModFlags |= (method.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE));
309 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
311 if (a.Type == pa.MethodImpl) {
312 method.is_external_implementation = a.IsInternalCall ();
315 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
318 public override AttributeTargets AttributeTargets {
320 return AttributeTargets.Method;
324 public override bool IsClsComplianceRequired ()
326 return method.IsClsComplianceRequired ();
329 public virtual void Define (TypeContainer parent)
331 var container = parent.PartialContainer;
334 // Check for custom access modifier
336 if ((ModFlags & Modifiers.AccessibilityMask) == 0) {
337 ModFlags |= method.ModFlags;
338 flags = method.flags;
340 if (container.Kind == MemberKind.Interface)
341 Report.Error (275, Location, "`{0}': accessibility modifiers may not be used on accessors in an interface",
342 GetSignatureForError ());
343 else if ((method.ModFlags & Modifiers.ABSTRACT) != 0 && (ModFlags & Modifiers.PRIVATE) != 0) {
344 Report.Error (442, Location, "`{0}': abstract properties cannot have private accessors", GetSignatureForError ());
347 CheckModifiers (ModFlags);
348 ModFlags |= (method.ModFlags & (~Modifiers.AccessibilityMask));
349 ModFlags |= Modifiers.PROPERTY_CUSTOM;
350 flags = ModifiersExtensions.MethodAttr (ModFlags);
351 flags |= (method.flags & (~MethodAttributes.MemberAccessMask));
354 CheckAbstractAndExtern (block != null);
355 CheckProtectedModifier ();
358 if (block.IsIterator)
359 Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags);
361 if (Compiler.Settings.WriteMetadataOnly)
366 public bool HasCustomAccessModifier {
368 return (ModFlags & Modifiers.PROPERTY_CUSTOM) != 0;
372 public PropertyBase Property {
378 public override ObsoleteAttribute GetAttributeObsolete ()
380 return method.GetAttributeObsolete ();
383 public override string GetSignatureForError()
385 return method.GetSignatureForError () + "." + prefix.Substring (0, 3);
388 void CheckModifiers (Modifiers modflags)
390 if (!ModifiersExtensions.IsRestrictedModifier (modflags & Modifiers.AccessibilityMask, method.ModFlags & Modifiers.AccessibilityMask)) {
391 Report.Error (273, Location,
392 "The accessibility modifier of the `{0}' accessor must be more restrictive than the modifier of the property or indexer `{1}'",
393 GetSignatureForError (), method.GetSignatureForError ());
398 PropertyMethod get, set, first;
399 PropertyBuilder PropertyBuilder;
401 protected PropertyBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, Modifiers allowed_mod, MemberName name, Attributes attrs)
402 : base (parent, type, mod_flags, allowed_mod, name, attrs)
408 public override AttributeTargets AttributeTargets {
410 return AttributeTargets.Property;
414 public PropertyMethod AccessorFirst {
420 public PropertyMethod AccessorSecond {
422 return first == get ? set : get;
426 public override Variance ExpectedMemberTypeVariance {
428 return (get != null && set != null) ?
429 Variance.None : set == null ?
431 Variance.Contravariant;
435 public PropertyMethod Get {
444 Parent.AddNameToContainer (get, get.MemberName.Basename);
448 public PropertyMethod Set {
457 Parent.AddNameToContainer (set, set.MemberName.Basename);
461 public override string[] ValidAttributeTargets {
463 return attribute_targets;
469 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
471 if (a.HasSecurityAttribute) {
472 a.Error_InvalidSecurityParent ();
476 if (a.Type == pa.Dynamic) {
477 a.Error_MisusedDynamicAttribute ();
481 PropertyBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
484 void CheckMissingAccessor (MemberKind kind, ParametersCompiled parameters, bool get)
486 if (IsExplicitImpl) {
488 if (kind == MemberKind.Indexer)
489 filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, kind, parameters, null);
491 filter = new MemberFilter (MemberName.Name, 0, kind, null, null);
493 var implementing = MemberCache.FindMember (InterfaceType, filter, BindingRestriction.DeclaredOnly) as PropertySpec;
495 if (implementing == null)
498 var accessor = get ? implementing.Get : implementing.Set;
499 if (accessor != null) {
500 Report.SymbolRelatedToPreviousError (accessor);
501 Report.Error (551, Location, "Explicit interface implementation `{0}' is missing accessor `{1}'",
502 GetSignatureForError (), accessor.GetSignatureForError ());
507 protected override bool CheckOverrideAgainstBase (MemberSpec base_member)
509 var ok = base.CheckOverrideAgainstBase (base_member);
512 // Check base property accessors conflict
514 var base_prop = (PropertySpec) base_member;
516 if ((ModFlags & Modifiers.SEALED) != 0 && base_prop.HasGet && !base_prop.Get.IsAccessible (this)) {
517 // TODO: Should be different error code but csc uses for some reason same
518 Report.SymbolRelatedToPreviousError (base_prop);
519 Report.Error (545, Location,
520 "`{0}': cannot override because `{1}' does not have accessible get accessor",
521 GetSignatureForError (), base_prop.GetSignatureForError ());
525 if (!base_prop.HasGet) {
527 Report.SymbolRelatedToPreviousError (base_prop);
528 Report.Error (545, Get.Location,
529 "`{0}': cannot override because `{1}' does not have an overridable get accessor",
530 Get.GetSignatureForError (), base_prop.GetSignatureForError ());
533 } else if (Get.HasCustomAccessModifier || base_prop.HasDifferentAccessibility) {
534 if (!CheckAccessModifiers (Get, base_prop.Get)) {
535 Error_CannotChangeAccessModifiers (Get, base_prop.Get);
542 if ((ModFlags & Modifiers.SEALED) != 0 && base_prop.HasSet && !base_prop.Set.IsAccessible (this)) {
543 // TODO: Should be different error code but csc uses for some reason same
544 Report.SymbolRelatedToPreviousError (base_prop);
545 Report.Error (546, Location,
546 "`{0}': cannot override because `{1}' does not have accessible set accessor",
547 GetSignatureForError (), base_prop.GetSignatureForError ());
551 if (!base_prop.HasSet) {
553 Report.SymbolRelatedToPreviousError (base_prop);
554 Report.Error (546, Set.Location,
555 "`{0}': cannot override because `{1}' does not have an overridable set accessor",
556 Set.GetSignatureForError (), base_prop.GetSignatureForError ());
559 } else if (Set.HasCustomAccessModifier || base_prop.HasDifferentAccessibility) {
560 if (!CheckAccessModifiers (Set, base_prop.Set)) {
561 Error_CannotChangeAccessModifiers (Set, base_prop.Set);
567 if ((Set == null || !Set.HasCustomAccessModifier) && (Get == null || !Get.HasCustomAccessModifier)) {
568 if (!CheckAccessModifiers (this, base_prop)) {
569 Error_CannotChangeAccessModifiers (this, base_prop);
577 protected override void DoMemberTypeDependentChecks ()
579 base.DoMemberTypeDependentChecks ();
583 if (MemberType.IsStatic)
584 Error_StaticReturnType ();
587 protected override void DoMemberTypeIndependentChecks ()
589 base.DoMemberTypeIndependentChecks ();
592 // Accessors modifiers check
594 if (AccessorSecond != null) {
595 if ((Get.ModFlags & Modifiers.AccessibilityMask) != 0 && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) {
596 Report.Error (274, Location, "`{0}': Cannot specify accessibility modifiers for both accessors of the property or indexer",
597 GetSignatureForError ());
599 } else if ((ModFlags & Modifiers.OVERRIDE) == 0 &&
600 (Get == null && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) ||
601 (Set == null && (Get.ModFlags & Modifiers.AccessibilityMask) != 0)) {
602 Report.Error (276, Location,
603 "`{0}': accessibility modifiers on accessors may only be used if the property or indexer has both a get and a set accessor",
604 GetSignatureForError ());
608 protected bool DefineAccessors ()
610 first.Define (Parent);
611 if (AccessorSecond != null)
612 AccessorSecond.Define (Parent);
617 protected void DefineBuilders (MemberKind kind, ParametersCompiled parameters)
619 PropertyBuilder = Parent.TypeBuilder.DefineProperty (
620 GetFullName (MemberName), PropertyAttributes.None,
621 #if !BOOTSTRAP_BASIC // Requires trunk version mscorlib
622 IsStatic ? 0 : CallingConventions.HasThis,
624 MemberType.GetMetaInfo (), null, null,
625 parameters.GetMetaInfo (), null, null);
628 if (kind == MemberKind.Indexer)
629 spec = new IndexerSpec (Parent.Definition, this, MemberType, parameters, PropertyBuilder, ModFlags);
631 spec = new PropertySpec (kind, Parent.Definition, this, MemberType, PropertyBuilder, ModFlags);
635 Parent.MemberCache.AddMember (this, Get.Spec.Name, Get.Spec);
637 CheckMissingAccessor (kind, parameters, true);
642 Parent.MemberCache.AddMember (this, Set.Spec.Name, Set.Spec);
644 CheckMissingAccessor (kind, parameters, false);
647 Parent.MemberCache.AddMember (this, PropertyBuilder.Name, spec);
650 public override void Emit ()
652 CheckReservedNameConflict (GetMethod.Prefix, get == null ? null : get.Spec);
653 CheckReservedNameConflict (SetMethod.Prefix, set == null ? null : set.Spec);
655 if (OptAttributes != null)
656 OptAttributes.Emit ();
658 if (member_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
659 Module.PredefinedAttributes.Dynamic.EmitAttribute (PropertyBuilder);
660 } else if (member_type.HasDynamicElement) {
661 Module.PredefinedAttributes.Dynamic.EmitAttribute (PropertyBuilder, member_type, Location);
664 ConstraintChecker.Check (this, member_type, type_expr.Location);
667 if (AccessorSecond != null)
668 AccessorSecond.Emit (Parent);
673 public override bool IsUsed {
678 return Get.IsUsed | Set.IsUsed;
682 public override void PrepareEmit ()
684 AccessorFirst.PrepareEmit ();
685 if (AccessorSecond != null)
686 AccessorSecond.PrepareEmit ();
689 var method = Get.Spec.GetMetaInfo () as MethodBuilder;
691 PropertyBuilder.SetGetMethod (method);
695 var method = Set.Spec.GetMetaInfo () as MethodBuilder;
697 PropertyBuilder.SetSetMethod (method);
701 protected override void SetMemberName (MemberName new_name)
703 base.SetMemberName (new_name);
706 Get.UpdateName (this);
709 Set.UpdateName (this);
712 public override void WriteDebugSymbol (MonoSymbolFile file)
715 get.WriteDebugSymbol (file);
718 set.WriteDebugSymbol (file);
722 // Represents header string for documentation comment.
724 public override string DocCommentHeader {
729 public class Property : PropertyBase
731 public sealed class BackingField : Field
733 readonly Property property;
734 const Modifiers DefaultModifiers = Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | Modifiers.DEBUGGER_HIDDEN;
736 public BackingField (Property p, bool readOnly)
737 : base (p.Parent, p.type_expr, DefaultModifiers | (p.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
738 new MemberName ("<" + p.GetFullName (p.MemberName) + ">k__BackingField", p.Location), null)
742 ModFlags |= Modifiers.READONLY;
745 public Property OriginalProperty {
751 public override string GetSignatureForError ()
753 return property.GetSignatureForError ();
757 static readonly string[] attribute_target_auto = new string[] { "property", "field" };
761 public Property (TypeDefinition parent, FullNamedExpression type, Modifiers mod,
762 MemberName name, Attributes attrs)
763 : base (parent, type, mod,
764 parent.PartialContainer.Kind == MemberKind.Interface ? AllowedModifiersInterface :
765 parent.PartialContainer.Kind == MemberKind.Struct ? AllowedModifiersStruct :
766 AllowedModifiersClass,
771 public Expression Initializer { get; set; }
773 public override void Accept (StructuralVisitor visitor)
775 visitor.Visit (this);
778 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
780 if (a.Target == AttributeTargets.Field) {
781 backing_field.ApplyAttributeBuilder (a, ctor, cdata, pa);
785 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
788 void CreateAutomaticProperty ()
790 // Create backing field
791 backing_field = new BackingField (this, Initializer != null && Set == null);
792 if (!backing_field.Define ())
795 if (Initializer != null) {
796 backing_field.Initializer = Initializer;
797 Parent.RegisterFieldForInitialization (backing_field, new FieldInitializer (backing_field, Initializer, Location));
798 backing_field.ModFlags |= Modifiers.READONLY;
801 Parent.PartialContainer.Members.Add (backing_field);
803 FieldExpr fe = new FieldExpr (backing_field, Location);
804 if ((backing_field.ModFlags & Modifiers.STATIC) == 0)
805 fe.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location);
808 // Create get block but we careful with location to
809 // emit only single sequence point per accessor. This allow
810 // to set a breakpoint on it even with no user code
812 Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null);
813 Return r = new Return (fe, Get.Location);
814 Get.Block.AddStatement (r);
815 Get.ModFlags |= Modifiers.COMPILER_GENERATED;
819 Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location.Null);
820 Assign a = new SimpleAssign (fe, new SimpleName ("value", Location.Null), Location.Null);
821 Set.Block.AddStatement (new StatementExpression (a, Set.Location));
822 Set.ModFlags |= Modifiers.COMPILER_GENERATED;
826 public override bool Define ()
831 flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
833 bool auto = AccessorFirst.Block == null && (AccessorSecond == null || AccessorSecond.Block == null) &&
834 (ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0;
836 if (Initializer != null) {
838 Report.Error (8050, Location, "`{0}': Only auto-implemented properties can have initializers",
839 GetSignatureForError ());
842 Report.Error (8053, Location, "`{0}': Properties inside interfaces cannot have initializers",
843 GetSignatureForError ());
845 if (Compiler.Settings.Version < LanguageVersion.V_6)
846 Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented property initializer");
851 Report.Error (8052, Location, "Auto-implemented property `{0}' must have get accessor",
852 GetSignatureForError ());
856 if (Initializer == null && AccessorSecond == null) {
857 Report.Error (8051, Location, "Auto-implemented property `{0}' must have set accessor or initializer",
858 GetSignatureForError ());
861 if (Compiler.Settings.Version < LanguageVersion.V_3 && Initializer == null)
862 Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented properties");
864 CreateAutomaticProperty ();
867 if (!DefineAccessors ())
870 if (AccessorSecond == null) {
872 if (AccessorFirst is GetMethod)
873 pm = new SetMethod (this, 0, ParametersCompiled.EmptyReadOnlyParameters, null, Location);
875 pm = new GetMethod (this, 0, null, Location);
877 Parent.AddNameToContainer (pm, pm.MemberName.Basename);
883 DefineBuilders (MemberKind.Property, ParametersCompiled.EmptyReadOnlyParameters);
887 public override void Emit ()
889 if ((AccessorFirst.ModFlags & (Modifiers.STATIC | Modifiers.COMPILER_GENERATED)) == Modifiers.COMPILER_GENERATED && Parent.PartialContainer.HasExplicitLayout) {
890 Report.Error (842, Location,
891 "Automatically implemented property `{0}' cannot be used inside a type with an explicit StructLayout attribute",
892 GetSignatureForError ());
898 public override string[] ValidAttributeTargets {
900 return Get != null && ((Get.ModFlags & Modifiers.COMPILER_GENERATED) != 0) ?
901 attribute_target_auto : base.ValidAttributeTargets;
907 /// For case when event is declared like property (with add and remove accessors).
909 public class EventProperty: Event {
910 public abstract class AEventPropertyAccessor : AEventAccessor
912 protected AEventPropertyAccessor (EventProperty method, string prefix, Attributes attrs, Location loc)
913 : base (method, prefix, attrs, loc)
917 public override void Define (TypeContainer ds)
919 CheckAbstractAndExtern (block != null);
923 public override string GetSignatureForError ()
925 return method.GetSignatureForError () + "." + prefix.Substring (0, prefix.Length - 1);
929 public sealed class AddDelegateMethod: AEventPropertyAccessor
931 public AddDelegateMethod (EventProperty method, Attributes attrs, Location loc)
932 : base (method, AddPrefix, attrs, loc)
937 public sealed class RemoveDelegateMethod: AEventPropertyAccessor
939 public RemoveDelegateMethod (EventProperty method, Attributes attrs, Location loc)
940 : base (method, RemovePrefix, attrs, loc)
945 static readonly string[] attribute_targets = new string [] { "event" };
947 public EventProperty (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
948 : base (parent, type, mod_flags, name, attrs)
952 public override void Accept (StructuralVisitor visitor)
954 visitor.Visit (this);
957 public override bool Define()
966 public override string[] ValidAttributeTargets {
968 return attribute_targets;
974 /// Event is declared like field.
976 public class EventField : Event
978 abstract class EventFieldAccessor : AEventAccessor
980 protected EventFieldAccessor (EventField method, string prefix)
981 : base (method, prefix, null, method.Location)
985 protected abstract MethodSpec GetOperation (Location loc);
987 public override void Emit (TypeDefinition parent)
989 if ((method.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0 && !Compiler.Settings.WriteMetadataOnly) {
990 block = new ToplevelBlock (Compiler, ParameterInfo, Location) {
991 IsCompilerGenerated = true
993 FabricateBodyStatement ();
999 void FabricateBodyStatement ()
1002 // Delegate obj1 = backing_field
1004 // Delegate obj2 = obj1;
1005 // obj1 = Interlocked.CompareExchange (ref backing_field, Delegate.Combine|Remove(obj2, value), obj1);
1006 // } while ((object)obj1 != (object)obj2)
1009 var field_info = ((EventField) method).backing_field;
1010 FieldExpr f_expr = new FieldExpr (field_info, Location);
1012 f_expr.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location);
1014 var obj1 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location);
1015 var obj2 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location);
1017 block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (obj1, Location), f_expr)));
1019 var cond = new BooleanExpression (new Binary (Binary.Operator.Inequality,
1020 new Cast (new TypeExpression (Module.Compiler.BuiltinTypes.Object, Location), new LocalVariableReference (obj1, Location), Location),
1021 new Cast (new TypeExpression (Module.Compiler.BuiltinTypes.Object, Location), new LocalVariableReference (obj2, Location), Location)));
1023 var body = new ExplicitBlock (block, Location, Location);
1024 block.AddStatement (new Do (body, cond, Location, Location));
1026 body.AddStatement (new StatementExpression (
1027 new SimpleAssign (new LocalVariableReference (obj2, Location), new LocalVariableReference (obj1, Location))));
1029 var args_oper = new Arguments (2);
1030 args_oper.Add (new Argument (new LocalVariableReference (obj2, Location)));
1031 args_oper.Add (new Argument (block.GetParameterReference (0, Location)));
1033 var op_method = GetOperation (Location);
1035 var args = new Arguments (3);
1036 args.Add (new Argument (f_expr, Argument.AType.Ref));
1037 args.Add (new Argument (new Cast (
1038 new TypeExpression (field_info.MemberType, Location),
1039 new Invocation (MethodGroupExpr.CreatePredefined (op_method, op_method.DeclaringType, Location), args_oper),
1041 args.Add (new Argument (new LocalVariableReference (obj1, Location)));
1043 var cas = Module.PredefinedMembers.InterlockedCompareExchange_T.Get ();
1045 if (Module.PredefinedMembers.MonitorEnter_v4.Get () != null || Module.PredefinedMembers.MonitorEnter.Get () != null) {
1046 // Workaround for cripled (e.g. microframework) mscorlib without CompareExchange
1047 body.AddStatement (new Lock (
1048 block.GetParameterReference (0, Location),
1049 new StatementExpression (new SimpleAssign (
1050 f_expr, args [1].Expr, Location), Location), Location));
1052 Module.PredefinedMembers.InterlockedCompareExchange_T.Resolve (Location);
1055 body.AddStatement (new StatementExpression (new SimpleAssign (
1056 new LocalVariableReference (obj1, Location),
1057 new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args))));
1062 sealed class AddDelegateMethod: EventFieldAccessor
1064 public AddDelegateMethod (EventField method):
1065 base (method, AddPrefix)
1069 protected override MethodSpec GetOperation (Location loc)
1071 return Module.PredefinedMembers.DelegateCombine.Resolve (loc);
1075 sealed class RemoveDelegateMethod: EventFieldAccessor
1077 public RemoveDelegateMethod (EventField method):
1078 base (method, RemovePrefix)
1082 protected override MethodSpec GetOperation (Location loc)
1084 return Module.PredefinedMembers.DelegateRemove.Resolve (loc);
1089 static readonly string[] attribute_targets = new string [] { "event", "field", "method" };
1090 static readonly string[] attribute_targets_interface = new string[] { "event", "method" };
1092 Expression initializer;
1093 Field backing_field;
1094 List<FieldDeclarator> declarators;
1096 public EventField (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
1097 : base (parent, type, mod_flags, name, attrs)
1099 Add = new AddDelegateMethod (this);
1100 Remove = new RemoveDelegateMethod (this);
1105 public List<FieldDeclarator> Declarators {
1107 return this.declarators;
1111 bool HasBackingField {
1113 return !IsInterface && (ModFlags & Modifiers.ABSTRACT) == 0;
1117 public Expression Initializer {
1122 initializer = value;
1126 public override string[] ValidAttributeTargets {
1128 return HasBackingField ? attribute_targets : attribute_targets_interface;
1135 public override void Accept (StructuralVisitor visitor)
1137 visitor.Visit (this);
1140 public void AddDeclarator (FieldDeclarator declarator)
1142 if (declarators == null)
1143 declarators = new List<FieldDeclarator> (2);
1145 declarators.Add (declarator);
1147 Parent.AddNameToContainer (this, declarator.Name.Value);
1150 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1152 if (a.Target == AttributeTargets.Field) {
1153 backing_field.ApplyAttributeBuilder (a, ctor, cdata, pa);
1157 if (a.Target == AttributeTargets.Method) {
1158 int errors = Report.Errors;
1159 Add.ApplyAttributeBuilder (a, ctor, cdata, pa);
1160 if (errors == Report.Errors)
1161 Remove.ApplyAttributeBuilder (a, ctor, cdata, pa);
1165 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
1168 public override bool Define()
1170 var mod_flags_src = ModFlags;
1172 if (!base.Define ())
1175 if (declarators != null) {
1176 if ((mod_flags_src & Modifiers.DEFAULT_ACCESS_MODIFIER) != 0)
1177 mod_flags_src &= ~(Modifiers.AccessibilityMask | Modifiers.DEFAULT_ACCESS_MODIFIER);
1179 var t = new TypeExpression (MemberType, TypeExpression.Location);
1180 foreach (var d in declarators) {
1181 var ef = new EventField (Parent, t, mod_flags_src, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
1183 if (d.Initializer != null)
1184 ef.initializer = d.Initializer;
1187 Parent.PartialContainer.Members.Add (ef);
1191 if (!HasBackingField) {
1196 backing_field = new Field (Parent,
1197 new TypeExpression (MemberType, Location),
1198 Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
1201 Parent.PartialContainer.Members.Add (backing_field);
1202 backing_field.Initializer = Initializer;
1203 backing_field.ModFlags &= ~Modifiers.COMPILER_GENERATED;
1205 // Call define because we passed fields definition
1206 backing_field.Define ();
1208 // Set backing field for event fields
1209 spec.BackingField = backing_field.Spec;
1215 public abstract class Event : PropertyBasedMember
1217 public abstract class AEventAccessor : AbstractPropertyEventMethod
1219 protected readonly Event method;
1220 readonly ParametersCompiled parameters;
1222 static readonly string[] attribute_targets = new string [] { "method", "param", "return" };
1224 public const string AddPrefix = "add_";
1225 public const string RemovePrefix = "remove_";
1227 protected AEventAccessor (Event method, string prefix, Attributes attrs, Location loc)
1228 : base (method, prefix, attrs, loc)
1230 this.method = method;
1231 this.ModFlags = method.ModFlags;
1232 this.parameters = ParametersCompiled.CreateImplicitParameter (method.TypeExpression, loc);
1235 public bool IsInterfaceImplementation {
1236 get { return method_data.implementing != null; }
1239 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1241 if (a.Type == pa.MethodImpl) {
1242 method.is_external_implementation = a.IsInternalCall ();
1245 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
1248 protected override void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1250 if (a.Target == AttributeTargets.Parameter) {
1251 parameters[0].ApplyAttributeBuilder (a, ctor, cdata, pa);
1255 base.ApplyToExtraTarget (a, ctor, cdata, pa);
1258 public override AttributeTargets AttributeTargets {
1260 return AttributeTargets.Method;
1264 public override bool IsClsComplianceRequired ()
1266 return method.IsClsComplianceRequired ();
1269 public virtual void Define (TypeContainer parent)
1271 // Fill in already resolved event type to speed things up and
1272 // avoid confusing duplicate errors
1273 ((Parameter) parameters.FixedParameters[0]).Type = method.member_type;
1274 parameters.Types = new TypeSpec[] { method.member_type };
1276 method_data = new MethodData (method, method.ModFlags,
1277 method.flags | MethodAttributes.HideBySig | MethodAttributes.SpecialName, this);
1279 if (!method_data.Define (parent.PartialContainer, method.GetFullName (MemberName)))
1282 if (Compiler.Settings.WriteMetadataOnly)
1285 Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, method.ModFlags);
1286 Spec.IsAccessor = true;
1289 public override TypeSpec ReturnType {
1291 return Parent.Compiler.BuiltinTypes.Void;
1295 public override ObsoleteAttribute GetAttributeObsolete ()
1297 return method.GetAttributeObsolete ();
1300 public MethodData MethodData {
1306 public override string[] ValidAttributeTargets {
1308 return attribute_targets;
1312 public override ParametersCompiled ParameterInfo {
1319 AEventAccessor add, remove;
1320 EventBuilder EventBuilder;
1321 protected EventSpec spec;
1323 protected Event (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
1324 : base (parent, type, mod_flags,
1325 parent.PartialContainer.Kind == MemberKind.Interface ? AllowedModifiersInterface :
1326 parent.PartialContainer.Kind == MemberKind.Struct ? AllowedModifiersStruct :
1327 AllowedModifiersClass,
1334 public override AttributeTargets AttributeTargets {
1336 return AttributeTargets.Event;
1340 public AEventAccessor Add {
1346 Parent.AddNameToContainer (value, value.MemberName.Basename);
1350 public override Variance ExpectedMemberTypeVariance {
1352 return Variance.Contravariant;
1356 public AEventAccessor Remove {
1362 Parent.AddNameToContainer (value, value.MemberName.Basename);
1367 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1369 if ((a.HasSecurityAttribute)) {
1370 a.Error_InvalidSecurityParent ();
1374 EventBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
1377 protected override bool CheckOverrideAgainstBase (MemberSpec base_member)
1379 var ok = base.CheckOverrideAgainstBase (base_member);
1381 if (!CheckAccessModifiers (this, base_member)) {
1382 Error_CannotChangeAccessModifiers (this, base_member);
1389 public override bool Define ()
1391 if (!base.Define ())
1394 if (!MemberType.IsDelegate) {
1395 Report.Error (66, Location, "`{0}': event must be of a delegate type", GetSignatureForError ());
1402 // Now define the accessors
1404 add.Define (Parent);
1405 remove.Define (Parent);
1407 EventBuilder = Parent.TypeBuilder.DefineEvent (GetFullName (MemberName), EventAttributes.None, MemberType.GetMetaInfo ());
1409 spec = new EventSpec (Parent.Definition, this, MemberType, ModFlags, Add.Spec, remove.Spec);
1411 Parent.MemberCache.AddMember (this, GetFullName (MemberName), spec);
1412 Parent.MemberCache.AddMember (this, Add.Spec.Name, Add.Spec);
1413 Parent.MemberCache.AddMember (this, Remove.Spec.Name, remove.Spec);
1418 public override void Emit ()
1420 CheckReservedNameConflict (null, add.Spec);
1421 CheckReservedNameConflict (null, remove.Spec);
1423 if (OptAttributes != null) {
1424 OptAttributes.Emit ();
1427 ConstraintChecker.Check (this, member_type, type_expr.Location);
1430 Remove.Emit (Parent);
1435 public override void PrepareEmit ()
1438 remove.PrepareEmit ();
1440 EventBuilder.SetAddOnMethod (add.MethodData.MethodBuilder);
1441 EventBuilder.SetRemoveOnMethod (remove.MethodData.MethodBuilder);
1444 public override void WriteDebugSymbol (MonoSymbolFile file)
1446 add.WriteDebugSymbol (file);
1447 remove.WriteDebugSymbol (file);
1451 // Represents header string for documentation comment.
1453 public override string DocCommentHeader {
1454 get { return "E:"; }
1458 public class EventSpec : MemberSpec, IInterfaceMemberSpec
1460 MethodSpec add, remove;
1461 FieldSpec backing_field;
1463 public EventSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec eventType, Modifiers modifiers, MethodSpec add, MethodSpec remove)
1464 : base (MemberKind.Event, declaringType, definition, modifiers)
1466 this.AccessorAdd = add;
1467 this.AccessorRemove = remove;
1468 this.MemberType = eventType;
1473 public MethodSpec AccessorAdd {
1482 public MethodSpec AccessorRemove {
1491 public FieldSpec BackingField {
1493 return backing_field;
1496 backing_field = value;
1500 public TypeSpec MemberType { get; private set; }
1504 public override MemberSpec InflateMember (TypeParameterInflator inflator)
1506 var es = (EventSpec) base.InflateMember (inflator);
1507 es.MemberType = inflator.Inflate (MemberType);
1509 if (backing_field != null)
1510 es.backing_field = (FieldSpec) backing_field.InflateMember (inflator);
1515 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
1517 return MemberType.ResolveMissingDependencies (this);
1521 public class Indexer : PropertyBase, IParametersMember
1523 public class GetIndexerMethod : GetMethod, IParametersMember
1525 ParametersCompiled parameters;
1527 public GetIndexerMethod (PropertyBase property, Modifiers modifiers, ParametersCompiled parameters, Attributes attrs, Location loc)
1528 : base (property, modifiers, attrs, loc)
1530 this.parameters = parameters;
1533 public override void Define (TypeContainer parent)
1535 // Disable reporting, parameters are resolved twice
1536 Report.DisableReporting ();
1538 parameters.Resolve (this);
1540 Report.EnableReporting ();
1543 base.Define (parent);
1546 public override ParametersCompiled ParameterInfo {
1552 #region IParametersMember Members
1554 AParametersCollection IParametersMember.Parameters {
1560 TypeSpec IInterfaceMemberSpec.MemberType {
1569 public class SetIndexerMethod : SetMethod, IParametersMember
1571 public SetIndexerMethod (PropertyBase property, Modifiers modifiers, ParametersCompiled parameters, Attributes attrs, Location loc)
1572 : base (property, modifiers, parameters, attrs, loc)
1576 #region IParametersMember Members
1578 AParametersCollection IParametersMember.Parameters {
1584 TypeSpec IInterfaceMemberSpec.MemberType {
1593 const Modifiers AllowedModifiers =
1596 Modifiers.PROTECTED |
1597 Modifiers.INTERNAL |
1601 Modifiers.OVERRIDE |
1606 const Modifiers AllowedInterfaceModifiers =
1609 readonly ParametersCompiled parameters;
1611 public Indexer (TypeDefinition parent, FullNamedExpression type, MemberName name, Modifiers mod, ParametersCompiled parameters, Attributes attrs)
1612 : base (parent, type, mod,
1613 parent.PartialContainer.Kind == MemberKind.Interface ? AllowedInterfaceModifiers : AllowedModifiers,
1616 this.parameters = parameters;
1621 AParametersCollection IParametersMember.Parameters {
1627 public ParametersCompiled ParameterInfo {
1636 public override void Accept (StructuralVisitor visitor)
1638 visitor.Visit (this);
1641 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1643 if (a.Type == pa.IndexerName) {
1644 // Attribute was copied to container
1648 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
1651 protected override bool CheckForDuplications ()
1653 return Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
1656 public override bool Define ()
1658 if (!base.Define ())
1661 if (!DefineParameters (parameters))
1664 if (OptAttributes != null) {
1665 Attribute indexer_attr = OptAttributes.Search (Module.PredefinedAttributes.IndexerName);
1666 if (indexer_attr != null) {
1667 var compiling = indexer_attr.Type.MemberDefinition as TypeContainer;
1668 if (compiling != null)
1669 compiling.Define ();
1671 if (IsExplicitImpl) {
1672 Report.Error (415, indexer_attr.Location,
1673 "The `{0}' attribute is valid only on an indexer that is not an explicit interface member declaration",
1674 indexer_attr.Type.GetSignatureForError ());
1675 } else if ((ModFlags & Modifiers.OVERRIDE) != 0) {
1676 Report.Error (609, indexer_attr.Location,
1677 "Cannot set the `IndexerName' attribute on an indexer marked override");
1679 string name = indexer_attr.GetIndexerAttributeValue ();
1681 if (!string.IsNullOrEmpty (name)) {
1682 SetMemberName (new MemberName (MemberName.Left, name, Location));
1688 if (InterfaceType != null) {
1689 string base_IndexerName = InterfaceType.MemberDefinition.GetAttributeDefaultMember ();
1690 if (base_IndexerName != ShortName) {
1691 SetMemberName (new MemberName (MemberName.Left, base_IndexerName, new TypeExpression (InterfaceType, Location), Location));
1695 Parent.AddNameToContainer (this, MemberName.Basename);
1697 flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
1699 if (!DefineAccessors ())
1705 DefineBuilders (MemberKind.Indexer, parameters);
1709 public override bool EnableOverloadChecks (MemberCore overload)
1711 if (overload is Indexer) {
1712 caching_flags |= Flags.MethodOverloadsExist;
1716 return base.EnableOverloadChecks (overload);
1719 public override void Emit ()
1721 parameters.CheckConstraints (this);
1726 public override string GetSignatureForError ()
1728 StringBuilder sb = new StringBuilder (Parent.GetSignatureForError ());
1729 if (MemberName.ExplicitInterface != null) {
1731 sb.Append (MemberName.ExplicitInterface.GetSignatureForError ());
1734 sb.Append (".this");
1735 sb.Append (parameters.GetSignatureForError ("[", "]", parameters.Count));
1736 return sb.ToString ();
1739 public override string GetSignatureForDocumentation ()
1741 return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation ();
1744 protected override bool VerifyClsCompliance ()
1746 if (!base.VerifyClsCompliance ())
1749 parameters.VerifyClsCompliance (this);
1754 public class IndexerSpec : PropertySpec, IParametersMember
1756 AParametersCollection parameters;
1758 public IndexerSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, AParametersCollection parameters, PropertyInfo info, Modifiers modifiers)
1759 : base (MemberKind.Indexer, declaringType, definition, memberType, info, modifiers)
1761 this.parameters = parameters;
1765 public AParametersCollection Parameters {
1772 public override string GetSignatureForDocumentation ()
1774 return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation ();
1777 public override string GetSignatureForError ()
1779 return DeclaringType.GetSignatureForError () + ".this" + parameters.GetSignatureForError ("[", "]", parameters.Count);
1782 public override MemberSpec InflateMember (TypeParameterInflator inflator)
1784 var spec = (IndexerSpec) base.InflateMember (inflator);
1785 spec.parameters = parameters.Inflate (inflator);
1789 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
1791 var missing = base.ResolveMissingDependencies (caller);
1793 foreach (var pt in parameters.Types) {
1794 var m = pt.GetMissingDependencies (caller);
1798 if (missing == null)
1799 missing = new List<MissingTypeSpecReference> ();
1801 missing.AddRange (m);