// // property.cs: Property based handlers // // Authors: Miguel de Icaza (miguel@gnu.org) // Martin Baulig (martin@ximian.com) // Marek Safar (marek.safar@seznam.cz) // // Dual licensed under the terms of the MIT X11 or GNU GPL // // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com) // Copyright 2004-2008 Novell, Inc // using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Text; #if NET_2_1 using XmlElement = System.Object; #else using System.Xml; #endif using Mono.CompilerServices.SymbolWriter; namespace Mono.CSharp { // It is used as a base class for all property based members // This includes properties, indexers, and events public abstract class PropertyBasedMember : InterfaceMemberBase { public PropertyBasedMember (DeclSpace parent, GenericMethod generic, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs) : base (parent, generic, type, mod, allowed_mod, name, attrs) { } protected override bool VerifyClsCompliance () { if (!base.VerifyClsCompliance ()) return false; if (!AttributeTester.IsClsCompliant (MemberType)) { Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant", GetSignatureForError ()); } return true; } } // // `set' and `get' accessors are represented with an Accessor. // public class Accessor { // // Null if the accessor is empty, or a Block if not // public const Modifiers AllowedModifiers = Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE; public ToplevelBlock Block; public Attributes Attributes; public Location Location; public Modifiers ModFlags; public ParametersCompiled Parameters; public Accessor (ToplevelBlock b, Modifiers mod, Attributes attrs, ParametersCompiled p, Location loc) { Block = b; Attributes = attrs; Location = loc; Parameters = p; ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, 0, loc, RootContext.ToplevelTypes.Compiler.Report); } } public class PropertySpec : MemberSpec { PropertyInfo info; public PropertySpec (MemberKind kind, IMemberDefinition definition, PropertyInfo info, Modifiers modifiers) : base (kind, definition, info.Name, modifiers) { this.info = info; } public override Type DeclaringType { get { return info.DeclaringType; } } public PropertyInfo MetaInfo { get { return info; } } public Type PropertyType { get { return info.PropertyType; } } } // // Properties and Indexers both generate PropertyBuilders, we use this to share // their common bits. // abstract public class PropertyBase : PropertyBasedMember { public class GetMethod : PropertyMethod { static string[] attribute_targets = new string [] { "method", "return" }; public GetMethod (PropertyBase method): base (method, "get_") { } public GetMethod (PropertyBase method, Accessor accessor): base (method, accessor, "get_") { } public override MethodBuilder Define (DeclSpace parent) { base.Define (parent); if (IsDummy) return null; method_data = new MethodData (method, ModFlags, flags, this); if (!method_data.Define (parent, method.GetFullName (MemberName), Report)) return null; Spec = new MethodSpec (MemberKind.Method, this, method_data.MethodBuilder, ParameterInfo, ModFlags); return method_data.MethodBuilder; } public override Type ReturnType { get { return method.MemberType; } } public override ParametersCompiled ParameterInfo { get { return ParametersCompiled.EmptyReadOnlyParameters; } } public override string[] ValidAttributeTargets { get { return attribute_targets; } } } public class SetMethod : PropertyMethod { static string[] attribute_targets = new string [] { "method", "param", "return" }; ImplicitParameter param_attr; protected ParametersCompiled parameters; public SetMethod (PropertyBase method) : base (method, "set_") { parameters = new ParametersCompiled (Compiler, new Parameter (method.type_name, "value", Parameter.Modifier.NONE, null, Location)); } public SetMethod (PropertyBase method, Accessor accessor): base (method, accessor, "set_") { this.parameters = accessor.Parameters; } protected override void ApplyToExtraTarget (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if (a.Target == AttributeTargets.Parameter) { if (param_attr == null) param_attr = new ImplicitParameter (method_data.MethodBuilder); param_attr.ApplyAttributeBuilder (a, cb, pa); return; } base.ApplyAttributeBuilder (a, cb, pa); } public override ParametersCompiled ParameterInfo { get { return parameters; } } public override MethodBuilder Define (DeclSpace parent) { parameters.Resolve (this); base.Define (parent); if (IsDummy) return null; method_data = new MethodData (method, ModFlags, flags, this); if (!method_data.Define (parent, method.GetFullName (MemberName), Report)) return null; Spec = new MethodSpec (MemberKind.Method, this, method_data.MethodBuilder, ParameterInfo, ModFlags); return method_data.MethodBuilder; } public override Type ReturnType { get { return TypeManager.void_type; } } public override string[] ValidAttributeTargets { get { return attribute_targets; } } } static string[] attribute_targets = new string [] { "property" }; public abstract class PropertyMethod : AbstractPropertyEventMethod { protected readonly PropertyBase method; protected MethodAttributes flags; public PropertyMethod (PropertyBase method, string prefix) : base (method, prefix) { this.method = method; this.ModFlags = method.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE); } public PropertyMethod (PropertyBase method, Accessor accessor, string prefix) : base (method, accessor, prefix) { this.method = method; this.ModFlags = accessor.ModFlags | (method.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)); if (accessor.ModFlags != 0 && RootContext.Version == LanguageVersion.ISO_1) { Report.FeatureIsNotAvailable (Location, "access modifiers on properties"); } } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if (a.IsInternalMethodImplAttribute) { method.is_external_implementation = true; } base.ApplyAttributeBuilder (a, cb, pa); } public override AttributeTargets AttributeTargets { get { return AttributeTargets.Method; } } public override bool IsClsComplianceRequired () { return method.IsClsComplianceRequired (); } public virtual MethodBuilder Define (DeclSpace parent) { CheckForDuplications (); if (IsDummy) { if (method.InterfaceType != null && parent.PartialContainer.PendingImplementations != null) { MethodInfo mi = parent.PartialContainer.PendingImplementations.IsInterfaceMethod ( MethodName.Name, method.InterfaceType, new MethodData (method, ModFlags, flags, this)); if (mi != null) { Report.SymbolRelatedToPreviousError (mi); Report.Error (551, Location, "Explicit interface implementation `{0}' is missing accessor `{1}'", method.GetSignatureForError (), TypeManager.CSharpSignature (mi, true)); } } return null; } TypeContainer container = parent.PartialContainer; // // Check for custom access modifier // if ((ModFlags & Modifiers.AccessibilityMask) == 0) { ModFlags |= method.ModFlags; flags = method.flags; } else { if (container.Kind == Kind.Interface) Report.Error (275, Location, "`{0}': accessibility modifiers may not be used on accessors in an interface", GetSignatureForError ()); if ((method.ModFlags & Modifiers.ABSTRACT) != 0 && (ModFlags & Modifiers.PRIVATE) != 0) { Report.Error (442, Location, "`{0}': abstract properties cannot have private accessors", GetSignatureForError ()); } CheckModifiers (ModFlags); ModFlags |= (method.ModFlags & (~Modifiers.AccessibilityMask)); ModFlags |= Modifiers.PROPERTY_CUSTOM; flags = ModifiersExtensions.MethodAttr (ModFlags); flags |= (method.flags & (~MethodAttributes.MemberAccessMask)); } CheckAbstractAndExtern (block != null); CheckProtectedModifier (); if (block != null && block.IsIterator) Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags, Compiler); return null; } public bool HasCustomAccessModifier { get { return (ModFlags & Modifiers.PROPERTY_CUSTOM) != 0; } } public PropertyBase Property { get { return method; } } public override ObsoleteAttribute GetObsoleteAttribute () { return method.GetObsoleteAttribute (); } public override string GetSignatureForError() { return method.GetSignatureForError () + '.' + prefix.Substring (0, 3); } void CheckModifiers (Modifiers modflags) { modflags &= Modifiers.AccessibilityMask; Modifiers flags = 0; Modifiers mflags = method.ModFlags & Modifiers.AccessibilityMask; if ((mflags & Modifiers.PUBLIC) != 0) { flags |= Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE; } else if ((mflags & Modifiers.PROTECTED) != 0) { if ((mflags & Modifiers.INTERNAL) != 0) flags |= Modifiers.PROTECTED | Modifiers.INTERNAL; flags |= Modifiers.PRIVATE; } else if ((mflags & Modifiers.INTERNAL) != 0) flags |= Modifiers.PRIVATE; if ((mflags == modflags) || (modflags & (~flags)) != 0) { Report.Error (273, Location, "The accessibility modifier of the `{0}' accessor must be more restrictive than the modifier of the property or indexer `{1}'", GetSignatureForError (), method.GetSignatureForError ()); } } protected bool CheckForDuplications () { if ((caching_flags & Flags.MethodOverloadsExist) == 0) return true; return Parent.MemberCache.CheckExistingMembersOverloads (this, Name, ParameterInfo, Report); } } public PropertyMethod Get, Set; public PropertyBuilder PropertyBuilder; public MethodBuilder GetBuilder, SetBuilder; protected bool define_set_first = false; public PropertyBase (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, Modifiers allowed_mod, MemberName name, Attributes attrs, bool define_set_first) : base (parent, null, type, mod_flags, allowed_mod, name, attrs) { this.define_set_first = define_set_first; } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if (a.HasSecurityAttribute) { a.Error_InvalidSecurityParent (); return; } if (a.Type == pa.Dynamic) { a.Error_MisusedDynamicAttribute (); return; } PropertyBuilder.SetCustomAttribute (cb); } public override AttributeTargets AttributeTargets { get { return AttributeTargets.Property; } } protected override void DoMemberTypeDependentChecks () { base.DoMemberTypeDependentChecks (); IsTypePermitted (); #if MS_COMPATIBLE if (MemberType.IsGenericParameter) return; #endif if ((MemberType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) { Report.Error (722, Location, Error722, TypeManager.CSharpName (MemberType)); } } protected override void DoMemberTypeIndependentChecks () { base.DoMemberTypeIndependentChecks (); // // Accessors modifiers check // if ((Get.ModFlags & Modifiers.AccessibilityMask) != 0 && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) { Report.Error (274, Location, "`{0}': Cannot specify accessibility modifiers for both accessors of the property or indexer", GetSignatureForError ()); } if ((ModFlags & Modifiers.OVERRIDE) == 0 && (Get.IsDummy && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) || (Set.IsDummy && (Get.ModFlags & Modifiers.AccessibilityMask) != 0)) { Report.Error (276, Location, "`{0}': accessibility modifiers on accessors may only be used if the property or indexer has both a get and a set accessor", GetSignatureForError ()); } } bool DefineGet () { GetBuilder = Get.Define (Parent); return (Get.IsDummy) ? true : GetBuilder != null; } bool DefineSet (bool define) { if (!define) return true; SetBuilder = Set.Define (Parent); return (Set.IsDummy) ? true : SetBuilder != null; } protected bool DefineAccessors () { return DefineSet (define_set_first) && DefineGet () && DefineSet (!define_set_first); } protected void DefineBuilders (MemberKind kind, Type[] parameterTypes) { // FIXME - PropertyAttributes.HasDefault ? PropertyBuilder = Parent.TypeBuilder.DefineProperty ( GetFullName (MemberName), PropertyAttributes.None, MemberType, parameterTypes); if (!Get.IsDummy) { PropertyBuilder.SetGetMethod (GetBuilder); Parent.MemberCache.AddMember (GetBuilder, Get.Spec); } if (!Set.IsDummy) { PropertyBuilder.SetSetMethod (SetBuilder); Parent.MemberCache.AddMember (SetBuilder, Set.Spec); } var spec = new PropertySpec (kind, this, PropertyBuilder, ModFlags); Parent.MemberCache.AddMember (PropertyBuilder, spec); } protected abstract PropertyInfo ResolveBaseProperty (); // TODO: rename to Resolve...... protected override MethodInfo FindOutBaseMethod (ref Type base_ret_type) { PropertyInfo base_property = ResolveBaseProperty (); if (base_property == null) return null; base_ret_type = base_property.PropertyType; MethodInfo get_accessor = base_property.GetGetMethod (true); MethodInfo set_accessor = base_property.GetSetMethod (true); MethodAttributes get_accessor_access = 0, set_accessor_access = 0; // // Check base property accessors conflict // if ((ModFlags & (Modifiers.OVERRIDE | Modifiers.NEW)) == Modifiers.OVERRIDE) { if (get_accessor == null) { if (Get != null && !Get.IsDummy) { Report.SymbolRelatedToPreviousError (base_property); Report.Error (545, Location, "`{0}.get': cannot override because `{1}' does not have an overridable get accessor", GetSignatureForError (), TypeManager.GetFullNameSignature (base_property)); } } else { get_accessor_access = get_accessor.Attributes & MethodAttributes.MemberAccessMask; if (!Get.IsDummy && !CheckAccessModifiers ( ModifiersExtensions.MethodAttr (Get.ModFlags) & MethodAttributes.MemberAccessMask, get_accessor_access, get_accessor)) Error_CannotChangeAccessModifiers (Get.Location, get_accessor, get_accessor_access, ".get"); } if (set_accessor == null) { if (Set != null && !Set.IsDummy) { Report.SymbolRelatedToPreviousError (base_property); Report.Error (546, Location, "`{0}.set': cannot override because `{1}' does not have an overridable set accessor", GetSignatureForError (), TypeManager.GetFullNameSignature (base_property)); } } else { set_accessor_access = set_accessor.Attributes & MethodAttributes.MemberAccessMask; if (!Set.IsDummy && !CheckAccessModifiers ( ModifiersExtensions.MethodAttr (Set.ModFlags) & MethodAttributes.MemberAccessMask, set_accessor_access, set_accessor)) Error_CannotChangeAccessModifiers (Set.Location, set_accessor, set_accessor_access, ".set"); } } // When one accessor does not exist and property hides base one // we need to propagate this upwards if (set_accessor == null) set_accessor = get_accessor; // // Get the less restrictive access // return get_accessor_access > set_accessor_access ? get_accessor : set_accessor; } public override void Emit () { // // The PropertyBuilder can be null for explicit implementations, in that // case, we do not actually emit the ".property", so there is nowhere to // put the attribute // if (PropertyBuilder != null) { if (OptAttributes != null) OptAttributes.Emit (); if (TypeManager.IsDynamicType (member_type)) { PredefinedAttributes.Get.Dynamic.EmitAttribute (PropertyBuilder); } else { var trans_flags = TypeManager.HasDynamicTypeUsed (member_type); if (trans_flags != null) { var pa = PredefinedAttributes.Get.DynamicTransform; if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.bool_type.MakeArrayType ())) { PropertyBuilder.SetCustomAttribute ( new CustomAttributeBuilder (pa.Constructor, new object [] { trans_flags })); } } } } if (!Get.IsDummy) Get.Emit (Parent); if (!Set.IsDummy) Set.Emit (Parent); base.Emit (); } /// /// Tests whether accessors are not in collision with some method (CS0111) /// public bool AreAccessorsDuplicateImplementation (MethodCore mc) { return Get.IsDuplicateImplementation (mc) || Set.IsDuplicateImplementation (mc); } public override bool IsUsed { get { if (IsExplicitImpl) return true; return Get.IsUsed | Set.IsUsed; } } protected override void SetMemberName (MemberName new_name) { base.SetMemberName (new_name); Get.UpdateName (this); Set.UpdateName (this); } public override string[] ValidAttributeTargets { get { return attribute_targets; } } // // Represents header string for documentation comment. // public override string DocCommentHeader { get { return "P:"; } } } public class Property : PropertyBase { public sealed class BackingField : Field { readonly Property property; public BackingField (Property p) : base (p.Parent, p.type_name, Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (p.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)), new MemberName ("<" + p.GetFullName (p.MemberName) + ">k__BackingField", p.Location), null) { this.property = p; } public override string GetSignatureForError () { return property.GetSignatureForError (); } } const Modifiers AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE | Modifiers.STATIC | Modifiers.SEALED | Modifiers.OVERRIDE | Modifiers.ABSTRACT | Modifiers.UNSAFE | Modifiers.EXTERN | Modifiers.VIRTUAL; const Modifiers AllowedInterfaceModifiers = Modifiers.NEW; public Property (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs, Accessor get_block, Accessor set_block, bool define_set_first) : this (parent, type, mod, name, attrs, get_block, set_block, define_set_first, null) { } public Property (DeclSpace parent, FullNamedExpression type, Modifiers mod, MemberName name, Attributes attrs, Accessor get_block, Accessor set_block, bool define_set_first, Block current_block) : base (parent, type, mod, parent.PartialContainer.Kind == Kind.Interface ? AllowedInterfaceModifiers : AllowedModifiers, name, attrs, define_set_first) { if (get_block == null) Get = new GetMethod (this); else Get = new GetMethod (this, get_block); if (set_block == null) Set = new SetMethod (this); else Set = new SetMethod (this, set_block); if (!IsInterface && (mod & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0 && get_block != null && get_block.Block == null && set_block != null && set_block.Block == null) { if (RootContext.Version <= LanguageVersion.ISO_2) Report.FeatureIsNotAvailable (Location, "automatically implemented properties"); Get.ModFlags |= Modifiers.COMPILER_GENERATED; Set.ModFlags |= Modifiers.COMPILER_GENERATED; } } void CreateAutomaticProperty () { // Create backing field Field field = new BackingField (this); if (!field.Define ()) return; Parent.PartialContainer.AddField (field); FieldExpr fe = new FieldExpr (field, Location); if ((field.ModFlags & Modifiers.STATIC) == 0) fe.InstanceExpression = new CompilerGeneratedThis (fe.Type, Location); // Create get block Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location); Return r = new Return (fe, Location); Get.Block.AddStatement (r); // Create set block Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location); Assign a = new SimpleAssign (fe, new SimpleName ("value", Location)); Set.Block.AddStatement (new StatementExpression (a)); } public override bool Define () { if (!base.Define ()) return false; flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName; if ((Get.ModFlags & Modifiers.COMPILER_GENERATED) != 0) CreateAutomaticProperty (); if (!DefineAccessors ()) return false; if (!CheckBase ()) return false; DefineBuilders (MemberKind.Property, null); TypeManager.RegisterProperty (PropertyBuilder, this); return true; } public override void Emit () { if (((Set.ModFlags | Get.ModFlags) & (Modifiers.STATIC | Modifiers.COMPILER_GENERATED)) == Modifiers.COMPILER_GENERATED && Parent.PartialContainer.HasExplicitLayout) { Report.Error (842, Location, "Automatically implemented property `{0}' cannot be used inside a type with an explicit StructLayout attribute", GetSignatureForError ()); } base.Emit (); } protected override PropertyInfo ResolveBaseProperty () { return Parent.PartialContainer.BaseCache.FindMemberToOverride ( Parent.TypeBuilder, Name, ParametersCompiled.EmptyReadOnlyParameters, null, true) as PropertyInfo; } } /// /// Gigantic workaround for lameness in SRE follows : /// This class derives from EventInfo and attempts to basically /// wrap around the EventBuilder so that FindMembers can quickly /// return this in it search for members /// public class MyEventBuilder : EventInfo { // // We use this to "point" to our Builder which is // not really a MemberInfo // EventBuilder MyBuilder; // // We "catch" and wrap these methods // MethodInfo raise, remove, add; EventAttributes attributes; Type declaring_type, reflected_type, event_type; string name; Event my_event; public MyEventBuilder (Event ev, TypeBuilder type_builder, string name, EventAttributes event_attr, Type event_type) { MyBuilder = type_builder.DefineEvent (name, event_attr, event_type); // And now store the values in our own fields. declaring_type = type_builder; reflected_type = type_builder; attributes = event_attr; this.name = name; my_event = ev; this.event_type = event_type; } // // Methods that you have to override. Note that you only need // to "implement" the variants that take the argument (those are // the "abstract" methods, the others (GetAddMethod()) are // regular. // public override MethodInfo GetAddMethod (bool nonPublic) { return add; } public override MethodInfo GetRemoveMethod (bool nonPublic) { return remove; } public override MethodInfo GetRaiseMethod (bool nonPublic) { return raise; } // // These methods make "MyEventInfo" look like a Builder // public void SetRaiseMethod (MethodBuilder raiseMethod) { raise = raiseMethod; MyBuilder.SetRaiseMethod (raiseMethod); } public void SetRemoveOnMethod (MethodBuilder removeMethod) { remove = removeMethod; MyBuilder.SetRemoveOnMethod (removeMethod); } public void SetAddOnMethod (MethodBuilder addMethod) { add = addMethod; MyBuilder.SetAddOnMethod (addMethod); } public void SetCustomAttribute (CustomAttributeBuilder cb) { MyBuilder.SetCustomAttribute (cb); } public override object [] GetCustomAttributes (bool inherit) { // FIXME : There's nothing which can be seemingly done here because // we have no way of getting at the custom attribute objects of the // EventBuilder ! return null; } public override object [] GetCustomAttributes (Type t, bool inherit) { // FIXME : Same here ! return null; } public override bool IsDefined (Type t, bool b) { return true; } public override EventAttributes Attributes { get { return attributes; } } public override string Name { get { return name; } } public override Type DeclaringType { get { return declaring_type; } } public override Type ReflectedType { get { return reflected_type; } } public Type EventType { get { return event_type; } } public void SetUsed () { if (my_event != null) { // my_event.SetAssigned (); my_event.SetIsUsed (); } } } /// /// For case when event is declared like property (with add and remove accessors). /// public class EventProperty: Event { abstract class AEventPropertyAccessor : AEventAccessor { protected AEventPropertyAccessor (EventProperty method, Accessor accessor, string prefix) : base (method, accessor, prefix) { } public override MethodBuilder Define (DeclSpace ds) { CheckAbstractAndExtern (block != null); return base.Define (ds); } public override string GetSignatureForError () { return method.GetSignatureForError () + "." + prefix.Substring (0, prefix.Length - 1); } } sealed class AddDelegateMethod: AEventPropertyAccessor { public AddDelegateMethod (EventProperty method, Accessor accessor): base (method, accessor, AddPrefix) { } } sealed class RemoveDelegateMethod: AEventPropertyAccessor { public RemoveDelegateMethod (EventProperty method, Accessor accessor): base (method, accessor, RemovePrefix) { } } static readonly string[] attribute_targets = new string [] { "event" }; // "property" target was disabled for 2.0 version public EventProperty (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs, Accessor add, Accessor remove) : base (parent, type, mod_flags, name, attrs) { Add = new AddDelegateMethod (this, add); Remove = new RemoveDelegateMethod (this, remove); } public override bool Define() { if (!base.Define ()) return false; SetIsUsed (); return true; } public override string[] ValidAttributeTargets { get { return attribute_targets; } } } /// /// Event is declared like field. /// public class EventField : Event { abstract class EventFieldAccessor : AEventAccessor { protected EventFieldAccessor (EventField method, string prefix) : base (method, prefix) { } public override void Emit (DeclSpace parent) { if ((method.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0) { if (parent is Class) { MethodBuilder mb = method_data.MethodBuilder; mb.SetImplementationFlags (mb.GetMethodImplementationFlags () | MethodImplAttributes.Synchronized); } var field_info = ((EventField) method).BackingField; FieldExpr f_expr = new FieldExpr (field_info, Location); if ((method.ModFlags & Modifiers.STATIC) == 0) f_expr.InstanceExpression = new CompilerGeneratedThis (field_info.Spec.FieldType, Location); block = new ToplevelBlock (Compiler, ParameterInfo, Location); block.AddStatement (new StatementExpression ( new CompoundAssign (Operation, f_expr, block.GetParameterReference (ParameterInfo[0].Name, Location)))); } base.Emit (parent); } protected abstract Binary.Operator Operation { get; } } sealed class AddDelegateMethod: EventFieldAccessor { public AddDelegateMethod (EventField method): base (method, AddPrefix) { } protected override Binary.Operator Operation { get { return Binary.Operator.Addition; } } } sealed class RemoveDelegateMethod: EventFieldAccessor { public RemoveDelegateMethod (EventField method): base (method, RemovePrefix) { } protected override Binary.Operator Operation { get { return Binary.Operator.Subtraction; } } } static readonly string[] attribute_targets = new string [] { "event", "field", "method" }; static readonly string[] attribute_targets_interface = new string[] { "event", "method" }; public Field BackingField; public Expression Initializer; public EventField (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs) : base (parent, type, mod_flags, name, attrs) { Add = new AddDelegateMethod (this); Remove = new RemoveDelegateMethod (this); } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if (a.Target == AttributeTargets.Field) { BackingField.ApplyAttributeBuilder (a, cb, pa); return; } if (a.Target == AttributeTargets.Method) { int errors = Report.Errors; Add.ApplyAttributeBuilder (a, cb, pa); if (errors == Report.Errors) Remove.ApplyAttributeBuilder (a, cb, pa); return; } base.ApplyAttributeBuilder (a, cb, pa); } public override bool Define() { if (!base.Define ()) return false; if (Initializer != null && (ModFlags & Modifiers.ABSTRACT) != 0) { Report.Error (74, Location, "`{0}': abstract event cannot have an initializer", GetSignatureForError ()); } if (!HasBackingField) { SetIsUsed (); return true; } // FIXME: We are unable to detect whether generic event is used because // we are using FieldExpr instead of EventExpr for event access in that // case. When this issue will be fixed this hack can be removed. if (TypeManager.IsGenericType (MemberType) || Parent.IsGeneric) SetIsUsed (); if (Add.IsInterfaceImplementation) SetIsUsed (); BackingField = new Field (Parent, new TypeExpression (MemberType, Location), Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)), MemberName, null); Parent.PartialContainer.AddField (BackingField); BackingField.Initializer = Initializer; BackingField.ModFlags &= ~Modifiers.COMPILER_GENERATED; // Call define because we passed fields definition return BackingField.Define (); } public bool HasBackingField { get { return !IsInterface && (ModFlags & Modifiers.ABSTRACT) == 0; } } public override string[] ValidAttributeTargets { get { return HasBackingField ? attribute_targets : attribute_targets_interface; } } } public abstract class Event : PropertyBasedMember { public abstract class AEventAccessor : AbstractPropertyEventMethod { protected readonly Event method; ImplicitParameter param_attr; static readonly string[] attribute_targets = new string [] { "method", "param", "return" }; public const string AddPrefix = "add_"; public const string RemovePrefix = "remove_"; protected AEventAccessor (Event method, string prefix) : base (method, prefix) { this.method = method; this.ModFlags = method.ModFlags; } protected AEventAccessor (Event method, Accessor accessor, string prefix) : base (method, accessor, prefix) { this.method = method; this.ModFlags = method.ModFlags; } public bool IsInterfaceImplementation { get { return method_data.implementing != null; } } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if (a.IsInternalMethodImplAttribute) { method.is_external_implementation = true; } base.ApplyAttributeBuilder (a, cb, pa); } protected override void ApplyToExtraTarget (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if (a.Target == AttributeTargets.Parameter) { if (param_attr == null) param_attr = new ImplicitParameter (method_data.MethodBuilder); param_attr.ApplyAttributeBuilder (a, cb, pa); return; } base.ApplyAttributeBuilder (a, cb, pa); } public override AttributeTargets AttributeTargets { get { return AttributeTargets.Method; } } public override bool IsClsComplianceRequired () { return method.IsClsComplianceRequired (); } public virtual MethodBuilder Define (DeclSpace parent) { method_data = new MethodData (method, method.ModFlags, method.flags | MethodAttributes.HideBySig | MethodAttributes.SpecialName, this); if (!method_data.Define (parent, method.GetFullName (MemberName), Report)) return null; MethodBuilder mb = method_data.MethodBuilder; ParameterInfo.ApplyAttributes (mb); Spec = new MethodSpec (MemberKind.Method, this, mb, ParameterInfo, method.ModFlags); return mb; } public override Type ReturnType { get { return TypeManager.void_type; } } public override ObsoleteAttribute GetObsoleteAttribute () { return method.GetObsoleteAttribute (); } public override string[] ValidAttributeTargets { get { return attribute_targets; } } public override ParametersCompiled ParameterInfo { get { return method.parameters; } } } const Modifiers AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE | Modifiers.STATIC | Modifiers.VIRTUAL | Modifiers.SEALED | Modifiers.OVERRIDE | Modifiers.UNSAFE | Modifiers.ABSTRACT | Modifiers.EXTERN; const Modifiers AllowedInterfaceModifiers = Modifiers.NEW; public AEventAccessor Add, Remove; public MyEventBuilder EventBuilder; public MethodBuilder AddBuilder, RemoveBuilder; ParametersCompiled parameters; protected Event (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs) : base (parent, null, type, mod_flags, parent.PartialContainer.Kind == Kind.Interface ? AllowedInterfaceModifiers : AllowedModifiers, name, attrs) { } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa) { if ((a.HasSecurityAttribute)) { a.Error_InvalidSecurityParent (); return; } EventBuilder.SetCustomAttribute (cb); } public bool AreAccessorsDuplicateImplementation (MethodCore mc) { return Add.IsDuplicateImplementation (mc) || Remove.IsDuplicateImplementation (mc); } public override AttributeTargets AttributeTargets { get { return AttributeTargets.Event; } } public override bool Define () { if (!base.Define ()) return false; if (!TypeManager.IsDelegateType (MemberType)) { Report.Error (66, Location, "`{0}': event must be of a delegate type", GetSignatureForError ()); } parameters = ParametersCompiled.CreateFullyResolved ( new Parameter (null, "value", Parameter.Modifier.NONE, null, Location), MemberType); if (!CheckBase ()) return false; if (TypeManager.delegate_combine_delegate_delegate == null) { TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod ( TypeManager.delegate_type, "Combine", Location, TypeManager.delegate_type, TypeManager.delegate_type); } if (TypeManager.delegate_remove_delegate_delegate == null) { TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod ( TypeManager.delegate_type, "Remove", Location, TypeManager.delegate_type, TypeManager.delegate_type); } // // Now define the accessors // AddBuilder = Add.Define (Parent); if (AddBuilder == null) return false; RemoveBuilder = Remove.Define (Parent); if (RemoveBuilder == null) return false; EventBuilder = new MyEventBuilder (this, Parent.TypeBuilder, Name, EventAttributes.None, MemberType); EventBuilder.SetAddOnMethod (AddBuilder); EventBuilder.SetRemoveOnMethod (RemoveBuilder); var spec = new EventSpec (this, EventBuilder, ModFlags, Add.Spec, Remove.Spec) { EventType = MemberType }; TypeManager.RegisterEventField (EventBuilder, spec); Parent.MemberCache.AddMember (EventBuilder, spec); Parent.MemberCache.AddMember (AddBuilder, Add.Spec); Parent.MemberCache.AddMember (RemoveBuilder, Remove.Spec); return true; } public override void Emit () { if (OptAttributes != null) { OptAttributes.Emit (); } Add.Emit (Parent); Remove.Emit (Parent); base.Emit (); } protected override MethodInfo FindOutBaseMethod (ref Type base_ret_type) { MethodInfo mi = (MethodInfo) Parent.PartialContainer.BaseCache.FindBaseEvent ( Parent.TypeBuilder, Name); if (mi == null) return null; AParametersCollection pd = TypeManager.GetParameterData (mi); base_ret_type = pd.Types [0]; return mi; } // // Represents header string for documentation comment. // public override string DocCommentHeader { get { return "E:"; } } } public class EventSpec : MemberSpec { EventInfo info; public EventSpec (IMemberDefinition definition, EventInfo info, Modifiers modifiers, MethodSpec add, MethodSpec remove) : base (MemberKind.Event, definition, info.Name, modifiers) { this.info = info; this.AccessorAdd = add; this.AccessorRemove = remove; // TODO MemberCache: Remove if (TypeManager.IsBeingCompiled (info)) state &= ~MemberSpec.StateFlags.Obsolete_Undetected; } public MethodSpec AccessorAdd { get; private set; } public MethodSpec AccessorRemove { get; private set; } public override Type DeclaringType { get { return info.DeclaringType; } } public Type EventType { get; set; } public bool IsAbstract { get { return (Modifiers & Modifiers.ABSTRACT) != 0; } } public EventInfo MetaInfo { get { return info; } } } public class Indexer : PropertyBase { public class GetIndexerMethod : GetMethod { ParametersCompiled parameters; public GetIndexerMethod (Indexer method): base (method) { this.parameters = method.parameters; } public GetIndexerMethod (PropertyBase method, Accessor accessor): base (method, accessor) { parameters = accessor.Parameters; } public override MethodBuilder Define (DeclSpace parent) { parameters.Resolve (this); return base.Define (parent); } public override bool EnableOverloadChecks (MemberCore overload) { if (base.EnableOverloadChecks (overload)) { overload.caching_flags |= Flags.MethodOverloadsExist; return true; } return false; } public override ParametersCompiled ParameterInfo { get { return parameters; } } } public class SetIndexerMethod: SetMethod { public SetIndexerMethod (Indexer method): base (method) { parameters = ParametersCompiled.MergeGenerated (Compiler, method.parameters, false, parameters [0], null); } public SetIndexerMethod (PropertyBase method, Accessor accessor): base (method, accessor) { parameters = method.Get.IsDummy ? accessor.Parameters : accessor.Parameters.Clone (); } public override bool EnableOverloadChecks (MemberCore overload) { if (base.EnableOverloadChecks (overload)) { overload.caching_flags |= Flags.MethodOverloadsExist; return true; } return false; } } const Modifiers AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE | Modifiers.VIRTUAL | Modifiers.SEALED | Modifiers.OVERRIDE | Modifiers.UNSAFE | Modifiers.EXTERN | Modifiers.ABSTRACT; const Modifiers AllowedInterfaceModifiers = Modifiers.NEW; public readonly ParametersCompiled parameters; public Indexer (DeclSpace parent, FullNamedExpression type, MemberName name, Modifiers mod, ParametersCompiled parameters, Attributes attrs, Accessor get_block, Accessor set_block, bool define_set_first) : base (parent, type, mod, parent.PartialContainer.Kind == Kind.Interface ? AllowedInterfaceModifiers : AllowedModifiers, name, attrs, define_set_first) { this.parameters = parameters; if (get_block == null) Get = new GetIndexerMethod (this); else Get = new GetIndexerMethod (this, get_block); if (set_block == null) Set = new SetIndexerMethod (this); else Set = new SetIndexerMethod (this, set_block); } protected override bool CheckForDuplications () { return Parent.MemberCache.CheckExistingMembersOverloads (this, GetFullName (MemberName), parameters, Report); } public override bool Define () { if (!base.Define ()) return false; if (!DefineParameters (parameters)) return false; if (OptAttributes != null) { Attribute indexer_attr = OptAttributes.Search (PredefinedAttributes.Get.IndexerName); if (indexer_attr != null) { // Remove the attribute from the list because it is not emitted OptAttributes.Attrs.Remove (indexer_attr); string name = indexer_attr.GetIndexerAttributeValue (); if (name == null) return false; ShortName = name; if (IsExplicitImpl) { Report.Error (415, indexer_attr.Location, "The `IndexerName' attribute is valid only on an " + "indexer that is not an explicit interface member declaration"); return false; } if ((ModFlags & Modifiers.OVERRIDE) != 0) { Report.Error (609, indexer_attr.Location, "Cannot set the `IndexerName' attribute on an indexer marked override"); return false; } } } if (InterfaceType != null) { string base_IndexerName = TypeManager.IndexerPropertyName (InterfaceType); if (base_IndexerName != Name) ShortName = base_IndexerName; } if (!Parent.PartialContainer.AddMember (this) || !Parent.PartialContainer.AddMember (Get) || !Parent.PartialContainer.AddMember (Set)) return false; flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName; if (!DefineAccessors ()) return false; if (!CheckBase ()) return false; DefineBuilders (MemberKind.Indexer, parameters.GetEmitTypes ()); TypeManager.RegisterIndexer (PropertyBuilder, parameters); return true; } public override bool EnableOverloadChecks (MemberCore overload) { if (overload is Indexer) { caching_flags |= Flags.MethodOverloadsExist; return true; } return base.EnableOverloadChecks (overload); } public override string GetDocCommentName (DeclSpace ds) { return DocUtil.GetMethodDocCommentName (this, parameters, ds); } public override string GetSignatureForError () { StringBuilder sb = new StringBuilder (Parent.GetSignatureForError ()); if (MemberName.Left != null) { sb.Append ('.'); sb.Append (MemberName.Left.GetSignatureForError ()); } sb.Append (".this"); sb.Append (parameters.GetSignatureForError ().Replace ('(', '[').Replace (')', ']')); return sb.ToString (); } protected override PropertyInfo ResolveBaseProperty () { return Parent.PartialContainer.BaseCache.FindMemberToOverride ( Parent.TypeBuilder, Name, parameters, null, true) as PropertyInfo; } protected override bool VerifyClsCompliance () { if (!base.VerifyClsCompliance ()) return false; parameters.VerifyClsCompliance (this); return true; } } }