* membercache.cs: Extracted from decl.cs.
* *.cs: Put more infrastructure in place.
svn path=/trunk/mcs/; revision=149550
++2010-01-14 Marek Safar <marek.safar@gmail.com>
++
++ * membercache.cs: Extracted from decl.cs.
++
++ * *.cs: Put more infrastructure in place.
++
+2010-01-13 Marek Safar <marek.safar@gmail.com>
+
+ * *.cs: Add property specification, unused yet.
+
+2010-01-13 Marek Safar <marek.safar@gmail.com>
+
+ * property.cs: Move all property based declarations into a new file.
+
2010-01-13 Marek Safar <marek.safar at gmail.com>
* expression.cs (Conditional): Resolve reduced expression.
readonly string name;
StateFlags state;
protected IMemberDefinition definition;
++ public readonly MemberKind Kind;
-- protected MemberSpec (IMemberDefinition definition, string name, Modifiers modifiers)
++ protected MemberSpec (MemberKind kind, IMemberDefinition definition, string name, Modifiers modifiers)
{
this.definition = definition;
this.name = name;
return true;
}
}
--
-- /// <summary>
-- /// This is a readonly list of MemberInfo's.
-- /// </summary>
-- public class MemberList : IList<MemberInfo> {
-- public readonly IList<MemberInfo> List;
-- int count;
--
-- /// <summary>
-- /// Create a new MemberList from the given IList.
-- /// </summary>
-- public MemberList (IList<MemberInfo> list)
-- {
-- if (list != null)
-- this.List = list;
-- else
-- this.List = new List<MemberInfo> ();
-- count = List.Count;
-- }
--
-- /// <summary>
-- /// Concatenate the ILists `first' and `second' to a new MemberList.
-- /// </summary>
-- public MemberList (IList<MemberInfo> first, IList<MemberInfo> second)
-- {
-- var list = new List<MemberInfo> ();
-- list.AddRange (first);
-- list.AddRange (second);
-- count = list.Count;
-- List = list;
-- }
--
-- public static readonly MemberList Empty = new MemberList (Array.AsReadOnly (new MemberInfo[0]));
--
-- /// <summary>
-- /// Cast the MemberList into a MemberInfo[] array.
-- /// </summary>
-- /// <remarks>
-- /// This is an expensive operation, only use it if it's really necessary.
-- /// </remarks>
-- public static explicit operator MemberInfo [] (MemberList list)
-- {
-- Timer.StartTimer (TimerType.MiscTimer);
-- MemberInfo [] result = new MemberInfo [list.Count];
-- list.CopyTo (result, 0);
-- Timer.StopTimer (TimerType.MiscTimer);
-- return result;
-- }
--
-- // ICollection
--
-- public int Count {
-- get {
-- return count;
-- }
-- }
--
-- public void CopyTo (MemberInfo[] array, int index)
-- {
-- List.CopyTo (array, index);
-- }
--
-- // IEnumerable
--
-- public IEnumerator<MemberInfo> GetEnumerator ()
-- {
-- return List.GetEnumerator ();
-- }
--
-- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
-- {
-- return List.GetEnumerator ();
-- }
--
-- // IList
--
-- public bool IsFixedSize {
-- get {
-- return true;
-- }
-- }
--
-- public bool IsReadOnly {
-- get {
-- return true;
-- }
-- }
--
-- MemberInfo IList<MemberInfo>.this [int index] {
-- get {
-- return List [index];
-- }
--
-- set {
-- throw new NotSupportedException ();
-- }
-- }
--
-- // FIXME: try to find out whether we can avoid the cast in this indexer.
-- public MemberInfo this [int index] {
-- get {
-- return (MemberInfo) List [index];
-- }
-- }
--
-- public void Add (MemberInfo value)
-- {
-- throw new NotSupportedException ();
-- }
--
-- public void Clear ()
-- {
-- throw new NotSupportedException ();
-- }
--
-- public bool Contains (MemberInfo value)
-- {
-- return List.Contains (value);
-- }
--
-- public int IndexOf (MemberInfo value)
-- {
-- return List.IndexOf (value);
-- }
--
-- public void Insert (int index, MemberInfo value)
-- {
-- throw new NotSupportedException ();
-- }
--
-- public bool Remove (MemberInfo value)
-- {
-- throw new NotSupportedException ();
-- }
--
-- public void RemoveAt (int index)
-- {
-- throw new NotSupportedException ();
-- }
-- }
--
-- /// <summary>
-- /// This interface is used to get all members of a class when creating the
-- /// member cache. It must be implemented by all DeclSpace derivatives which
-- /// want to support the member cache and by TypeHandle to get caching of
-- /// non-dynamic types.
-- /// </summary>
-- public interface IMemberContainer {
-- /// <summary>
-- /// The name of the IMemberContainer. This is only used for
-- /// debugging purposes.
-- /// </summary>
-- string Name {
-- get;
-- }
--
-- /// <summary>
-- /// The type of this IMemberContainer.
-- /// </summary>
-- Type Type {
-- get;
-- }
--
-- /// <summary>
-- /// Returns the IMemberContainer of the base class or null if this
-- /// is an interface or TypeManger.object_type.
-- /// This is used when creating the member cache for a class to get all
-- /// members from the base class.
-- /// </summary>
-- MemberCache BaseCache {
-- get;
-- }
--
-- /// <summary>
-- /// Whether this is an interface.
-- /// </summary>
-- bool IsInterface {
-- get;
-- }
--
-- /// <summary>
-- /// Returns all members of this class with the corresponding MemberTypes
-- /// and BindingFlags.
-- /// </summary>
-- /// <remarks>
-- /// When implementing this method, make sure not to return any inherited
-- /// members and check the MemberTypes and BindingFlags properly.
-- /// Unfortunately, System.Reflection is lame and doesn't provide a way to
-- /// get the BindingFlags (static/non-static,public/non-public) in the
-- /// MemberInfo class, but the cache needs this information. That's why
-- /// this method is called multiple times with different BindingFlags.
-- /// </remarks>
-- MemberList GetMembers (MemberTypes mt, BindingFlags bf);
-- }
--
-- /// <summary>
-- /// The MemberCache is used by dynamic and non-dynamic types to speed up
-- /// member lookups. It has a member name based hash table; it maps each member
-- /// name to a list of CacheEntry objects. Each CacheEntry contains a MemberInfo
-- /// and the BindingFlags that were initially used to get it. The cache contains
-- /// all members of the current class and all inherited members. If this cache is
-- /// for an interface types, it also contains all inherited members.
-- ///
-- /// There are two ways to get a MemberCache:
-- /// * if this is a dynamic type, lookup the corresponding DeclSpace and then
-- /// use the DeclSpace.MemberCache property.
-- /// * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
-- /// TypeHandle instance for the type and then use TypeHandle.MemberCache.
-- /// </summary>
-- public class MemberCache {
-- public readonly IMemberContainer Container;
-- protected Dictionary<string, List<CacheEntry>> member_hash;
-- protected Dictionary<string, List<CacheEntry>> method_hash;
--
-- Dictionary<string, object> locase_table;
--
-- static List<MethodInfo> overrides = new List<MethodInfo> ();
--
-- /// <summary>
-- /// Create a new MemberCache for the given IMemberContainer `container'.
-- /// </summary>
-- public MemberCache (IMemberContainer container)
-- {
-- this.Container = container;
--
-- Timer.IncrementCounter (CounterType.MemberCache);
-- Timer.StartTimer (TimerType.CacheInit);
--
-- // If we have a base class (we have a base class unless we're
-- // TypeManager.object_type), we deep-copy its MemberCache here.
-- if (Container.BaseCache != null)
-- member_hash = SetupCache (Container.BaseCache);
-- else
-- member_hash = new Dictionary<string, List<CacheEntry>> ();
--
-- // If this is neither a dynamic type nor an interface, create a special
-- // method cache with all declared and inherited methods.
-- Type type = container.Type;
-- if (!(type is TypeBuilder) && !type.IsInterface &&
-- // !(type.IsGenericType && (type.GetGenericTypeDefinition () is TypeBuilder)) &&
-- !TypeManager.IsGenericType (type) && !TypeManager.IsGenericParameter (type) &&
-- (Container.BaseCache == null || Container.BaseCache.method_hash != null)) {
-- method_hash = new Dictionary<string, List<CacheEntry>> ();
-- AddMethods (type);
-- }
--
-- // Add all members from the current class.
-- AddMembers (Container);
--
-- Timer.StopTimer (TimerType.CacheInit);
-- }
--
-- public MemberCache (Type baseType, IMemberContainer container)
-- {
-- this.Container = container;
-- if (baseType == null)
-- this.member_hash = new Dictionary<string, List<CacheEntry>> ();
-- else
-- this.member_hash = SetupCache (TypeManager.LookupMemberCache (baseType));
-- }
--
-- public MemberCache (Type[] ifaces)
-- {
-- //
-- // The members of this cache all belong to other caches.
-- // So, 'Container' will not be used.
-- //
-- this.Container = null;
--
-- member_hash = new Dictionary<string, List<CacheEntry>> ();
-- if (ifaces == null)
-- return;
--
-- foreach (Type itype in ifaces)
-- AddCacheContents (TypeManager.LookupMemberCache (itype));
-- }
--
-- public MemberCache (IMemberContainer container, Type base_class, Type[] ifaces)
-- {
-- this.Container = container;
--
-- // If we have a base class (we have a base class unless we're
-- // TypeManager.object_type), we deep-copy its MemberCache here.
-- if (Container.BaseCache != null)
-- member_hash = SetupCache (Container.BaseCache);
-- else
-- member_hash = new Dictionary<string, List<CacheEntry>> ();
--
-- if (base_class != null)
-- AddCacheContents (TypeManager.LookupMemberCache (base_class));
-- if (ifaces != null) {
-- foreach (Type itype in ifaces) {
-- MemberCache cache = TypeManager.LookupMemberCache (itype);
-- if (cache != null)
-- AddCacheContents (cache);
-- }
-- }
-- }
--
-- /// <summary>
-- /// Bootstrap this member cache by doing a deep-copy of our base.
-- /// </summary>
-- static Dictionary<string, List<CacheEntry>> SetupCache (MemberCache base_class)
-- {
-- if (base_class == null)
-- return new Dictionary<string, List<CacheEntry>> ();
--
-- var hash = new Dictionary<string, List<CacheEntry>> (base_class.member_hash.Count);
-- var it = base_class.member_hash.GetEnumerator ();
-- while (it.MoveNext ()) {
-- hash.Add (it.Current.Key, new List<CacheEntry> (it.Current.Value));
-- }
--
-- return hash;
-- }
--
-- //
-- // Converts ModFlags to BindingFlags
-- //
-- static BindingFlags GetBindingFlags (Modifiers modifiers)
-- {
-- BindingFlags bf;
-- if ((modifiers & Modifiers.STATIC) != 0)
-- bf = BindingFlags.Static;
-- else
-- bf = BindingFlags.Instance;
--
-- if ((modifiers & Modifiers.PRIVATE) != 0)
-- bf |= BindingFlags.NonPublic;
-- else
-- bf |= BindingFlags.Public;
--
-- return bf;
-- }
--
-- /// <summary>
-- /// Add the contents of `cache' to the member_hash.
-- /// </summary>
-- void AddCacheContents (MemberCache cache)
-- {
-- var it = cache.member_hash.GetEnumerator ();
-- while (it.MoveNext ()) {
-- List<CacheEntry> list;
-- if (!member_hash.TryGetValue (it.Current.Key, out list))
-- member_hash [it.Current.Key] = list = new List<CacheEntry> ();
--
-- var entries = it.Current.Value;
-- for (int i = entries.Count-1; i >= 0; i--) {
-- var entry = entries [i];
--
-- if (entry.Container != cache.Container)
-- break;
-- list.Add (entry);
-- }
-- }
-- }
--
-- /// <summary>
-- /// Add all members from class `container' to the cache.
-- /// </summary>
-- void AddMembers (IMemberContainer container)
-- {
-- // We need to call AddMembers() with a single member type at a time
-- // to get the member type part of CacheEntry.EntryType right.
-- if (!container.IsInterface) {
-- AddMembers (MemberTypes.Constructor, container);
-- AddMembers (MemberTypes.Field, container);
-- }
-- AddMembers (MemberTypes.Method, container);
-- AddMembers (MemberTypes.Property, container);
-- AddMembers (MemberTypes.Event, container);
-- // Nested types are returned by both Static and Instance searches.
-- AddMembers (MemberTypes.NestedType,
-- BindingFlags.Static | BindingFlags.Public, container);
-- AddMembers (MemberTypes.NestedType,
-- BindingFlags.Static | BindingFlags.NonPublic, container);
-- }
--
-- void AddMembers (MemberTypes mt, IMemberContainer container)
-- {
-- AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
-- AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
-- AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
-- AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
-- }
--
-- public void AddMember (MemberInfo mi, MemberCore mc)
-- {
-- AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container, mi.Name, mi);
-- }
--
-- public void AddGenericMember (MemberInfo mi, InterfaceMemberBase mc)
-- {
-- AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container,
-- MemberName.MakeName (mc.GetFullName (mc.MemberName), mc.MemberName.TypeArguments), mi);
-- }
--
-- public void AddNestedType (DeclSpace type)
-- {
-- AddMember (MemberTypes.NestedType, GetBindingFlags (type.ModFlags), (IMemberContainer) type.Parent,
-- type.TypeBuilder.Name, type.TypeBuilder);
-- }
--
-- public void AddInterface (MemberCache baseCache)
-- {
-- if (baseCache.member_hash.Count > 0)
-- AddCacheContents (baseCache);
-- }
--
-- void AddMember (MemberTypes mt, BindingFlags bf, IMemberContainer container,
-- string name, MemberInfo member)
-- {
-- // We use a name-based hash table of ArrayList's.
-- List<CacheEntry> list;
-- if (!member_hash.TryGetValue (name, out list)) {
-- list = new List<CacheEntry> (1);
-- member_hash.Add (name, list);
-- }
--
-- // When this method is called for the current class, the list will
-- // already contain all inherited members from our base classes.
-- // We cannot add new members in front of the list since this'd be an
-- // expensive operation, that's why the list is sorted in reverse order
-- // (ie. members from the current class are coming last).
-- list.Add (new CacheEntry (container, member, mt, bf));
-- }
--
-- /// <summary>
-- /// Add all members from class `container' with the requested MemberTypes and
-- /// BindingFlags to the cache. This method is called multiple times with different
-- /// MemberTypes and BindingFlags.
-- /// </summary>
-- void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
-- {
-- MemberList members = container.GetMembers (mt, bf);
--
-- foreach (MemberInfo member in members) {
-- string name = member.Name;
--
-- AddMember (mt, bf, container, name, member);
--
-- if (member is MethodInfo) {
-- string gname = TypeManager.GetMethodName ((MethodInfo) member);
-- if (gname != name)
-- AddMember (mt, bf, container, gname, member);
-- }
-- }
-- }
--
-- /// <summary>
-- /// Add all declared and inherited methods from class `type' to the method cache.
-- /// </summary>
-- void AddMethods (Type type)
-- {
-- AddMethods (BindingFlags.Static | BindingFlags.Public |
-- BindingFlags.FlattenHierarchy, type);
-- AddMethods (BindingFlags.Static | BindingFlags.NonPublic |
-- BindingFlags.FlattenHierarchy, type);
-- AddMethods (BindingFlags.Instance | BindingFlags.Public, type);
-- AddMethods (BindingFlags.Instance | BindingFlags.NonPublic, type);
-- }
--
-- void AddMethods (BindingFlags bf, Type type)
-- {
-- MethodBase [] members = type.GetMethods (bf);
--
-- Array.Reverse (members);
--
-- foreach (MethodBase member in members) {
-- string name = member.Name;
--
-- // We use a name-based hash table of ArrayList's.
-- List<CacheEntry> list;
-- if (!method_hash.TryGetValue (name, out list)) {
-- list = new List<CacheEntry> (1);
-- method_hash.Add (name, list);
-- }
--
-- MethodInfo curr = (MethodInfo) member;
-- while (curr.IsVirtual && (curr.Attributes & MethodAttributes.NewSlot) == 0) {
-- MethodInfo base_method = curr.GetBaseDefinition ();
--
-- if (base_method == curr)
-- // Not every virtual function needs to have a NewSlot flag.
-- break;
--
-- overrides.Add (curr);
-- list.Add (new CacheEntry (null, base_method, MemberTypes.Method, bf));
-- curr = base_method;
-- }
--
-- if (overrides.Count > 0) {
-- for (int i = 0; i < overrides.Count; ++i)
-- TypeManager.RegisterOverride ((MethodBase) overrides [i], curr);
-- overrides.Clear ();
-- }
--
-- // Unfortunately, the elements returned by Type.GetMethods() aren't
-- // sorted so we need to do this check for every member.
-- BindingFlags new_bf = bf;
-- if (member.DeclaringType == type)
-- new_bf |= BindingFlags.DeclaredOnly;
--
-- list.Add (new CacheEntry (Container, member, MemberTypes.Method, new_bf));
-- }
-- }
--
-- /// <summary>
-- /// Compute and return a appropriate `EntryType' magic number for the given
-- /// MemberTypes and BindingFlags.
-- /// </summary>
-- protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
-- {
-- EntryType type = EntryType.None;
--
-- if ((mt & MemberTypes.Constructor) != 0)
-- type |= EntryType.Constructor;
-- if ((mt & MemberTypes.Event) != 0)
-- type |= EntryType.Event;
-- if ((mt & MemberTypes.Field) != 0)
-- type |= EntryType.Field;
-- if ((mt & MemberTypes.Method) != 0)
-- type |= EntryType.Method;
-- if ((mt & MemberTypes.Property) != 0)
-- type |= EntryType.Property;
-- // Nested types are returned by static and instance searches.
-- if ((mt & MemberTypes.NestedType) != 0)
-- type |= EntryType.NestedType | EntryType.Static | EntryType.Instance;
--
-- if ((bf & BindingFlags.Instance) != 0)
-- type |= EntryType.Instance;
-- if ((bf & BindingFlags.Static) != 0)
-- type |= EntryType.Static;
-- if ((bf & BindingFlags.Public) != 0)
-- type |= EntryType.Public;
-- if ((bf & BindingFlags.NonPublic) != 0)
-- type |= EntryType.NonPublic;
-- if ((bf & BindingFlags.DeclaredOnly) != 0)
-- type |= EntryType.Declared;
--
-- return type;
-- }
--
-- /// <summary>
-- /// The `MemberTypes' enumeration type is a [Flags] type which means that it may
-- /// denote multiple member types. Returns true if the given flags value denotes a
-- /// single member types.
-- /// </summary>
-- public static bool IsSingleMemberType (MemberTypes mt)
-- {
-- switch (mt) {
-- case MemberTypes.Constructor:
-- case MemberTypes.Event:
-- case MemberTypes.Field:
-- case MemberTypes.Method:
-- case MemberTypes.Property:
-- case MemberTypes.NestedType:
-- return true;
--
-- default:
-- return false;
-- }
-- }
--
-- /// <summary>
-- /// We encode the MemberTypes and BindingFlags of each members in a "magic"
-- /// number to speed up the searching process.
-- /// </summary>
-- [Flags]
-- public enum EntryType {
-- None = 0x000,
--
-- Instance = 0x001,
-- Static = 0x002,
-- MaskStatic = Instance|Static,
--
-- Public = 0x004,
-- NonPublic = 0x008,
-- MaskProtection = Public|NonPublic,
--
-- Declared = 0x010,
--
-- Constructor = 0x020,
-- Event = 0x040,
-- Field = 0x080,
-- Method = 0x100,
-- Property = 0x200,
-- NestedType = 0x400,
--
-- NotExtensionMethod = 0x800,
--
-- MaskType = Constructor|Event|Field|Method|Property|NestedType
-- }
--
-- public class CacheEntry {
-- public readonly IMemberContainer Container;
-- public EntryType EntryType;
-- public readonly MemberInfo Member;
--
-- public CacheEntry (IMemberContainer container, MemberInfo member,
-- MemberTypes mt, BindingFlags bf)
-- {
-- this.Container = container;
-- this.Member = member;
-- this.EntryType = GetEntryType (mt, bf);
-- }
--
-- public override string ToString ()
-- {
-- return String.Format ("CacheEntry ({0}:{1}:{2})", Container.Name,
-- EntryType, Member);
-- }
-- }
--
-- /// <summary>
-- /// This is called each time we're walking up one level in the class hierarchy
-- /// and checks whether we can abort the search since we've already found what
-- /// we were looking for.
-- /// </summary>
-- protected bool DoneSearching (IList<MemberInfo> list)
-- {
-- //
-- // We've found exactly one member in the current class and it's not
-- // a method or constructor.
-- //
-- if (list.Count == 1 && !(list [0] is MethodBase))
-- return true;
--
-- //
-- // Multiple properties: we query those just to find out the indexer
-- // name
-- //
-- if ((list.Count > 0) && (list [0] is PropertyInfo))
-- return true;
--
-- return false;
-- }
--
-- /// <summary>
-- /// Looks up members with name `name'. If you provide an optional
-- /// filter function, it'll only be called with members matching the
-- /// requested member name.
-- ///
-- /// This method will try to use the cache to do the lookup if possible.
-- ///
-- /// Unlike other FindMembers implementations, this method will always
-- /// check all inherited members - even when called on an interface type.
-- ///
-- /// If you know that you're only looking for methods, you should use
-- /// MemberTypes.Method alone since this speeds up the lookup a bit.
-- /// When doing a method-only search, it'll try to use a special method
-- /// cache (unless it's a dynamic type or an interface) and the returned
-- /// MemberInfo's will have the correct ReflectedType for inherited methods.
-- /// The lookup process will automatically restart itself in method-only
-- /// search mode if it discovers that it's about to return methods.
-- /// </summary>
-- List<MemberInfo> global = new List<MemberInfo> ();
-- bool using_global;
--
-- static MemberInfo [] emptyMemberInfo = new MemberInfo [0];
--
-- public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, string name,
-- MemberFilter filter, object criteria)
-- {
-- if (using_global)
-- throw new Exception ();
--
-- bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
-- bool method_search = mt == MemberTypes.Method;
-- // If we have a method cache and we aren't already doing a method-only search,
-- // then we restart a method search if the first match is a method.
-- bool do_method_search = !method_search && (method_hash != null);
--
-- List<CacheEntry> applicable;
--
-- // If this is a method-only search, we try to use the method cache if
-- // possible; a lookup in the method cache will return a MemberInfo with
-- // the correct ReflectedType for inherited methods.
--
-- if (method_search && (method_hash != null))
-- method_hash.TryGetValue (name, out applicable);
-- else
-- member_hash.TryGetValue (name, out applicable);
--
-- if (applicable == null)
-- return emptyMemberInfo;
--
-- //
-- // 32 slots gives 53 rss/54 size
-- // 2/4 slots gives 55 rss
-- //
-- // Strange: from 25,000 calls, only 1,800
-- // are above 2. Why does this impact it?
-- //
-- global.Clear ();
-- using_global = true;
--
-- Timer.StartTimer (TimerType.CachedLookup);
--
-- EntryType type = GetEntryType (mt, bf);
--
-- IMemberContainer current = Container;
--
-- bool do_interface_search = current.IsInterface;
--
-- // `applicable' is a list of all members with the given member name `name'
-- // in the current class and all its base classes. The list is sorted in
-- // reverse order due to the way how the cache is initialy created (to speed
-- // things up, we're doing a deep-copy of our base).
--
-- for (int i = applicable.Count-1; i >= 0; i--) {
-- CacheEntry entry = (CacheEntry) applicable [i];
--
-- // This happens each time we're walking one level up in the class
-- // hierarchy. If we're doing a DeclaredOnly search, we must abort
-- // the first time this happens (this may already happen in the first
-- // iteration of this loop if there are no members with the name we're
-- // looking for in the current class).
-- if (entry.Container != current) {
-- if (declared_only)
-- break;
--
-- if (!do_interface_search && DoneSearching (global))
-- break;
--
-- current = entry.Container;
-- }
--
-- // Is the member of the correct type ?
-- if ((entry.EntryType & type & EntryType.MaskType) == 0)
-- continue;
--
-- // Is the member static/non-static ?
-- if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
-- continue;
--
-- // Apply the filter to it.
-- if (filter (entry.Member, criteria)) {
-- if ((entry.EntryType & EntryType.MaskType) != EntryType.Method) {
-- do_method_search = false;
-- }
--
-- // Because interfaces support multiple inheritance we have to be sure that
-- // base member is from same interface, so only top level member will be returned
-- if (do_interface_search && global.Count > 0) {
-- bool member_already_exists = false;
--
-- foreach (MemberInfo mi in global) {
-- if (mi is MethodBase)
-- continue;
--
-- if (IsInterfaceBaseInterface (TypeManager.GetInterfaces (mi.DeclaringType), entry.Member.DeclaringType)) {
-- member_already_exists = true;
-- break;
-- }
-- }
-- if (member_already_exists)
-- continue;
-- }
--
-- global.Add (entry.Member);
-- }
-- }
--
-- Timer.StopTimer (TimerType.CachedLookup);
--
-- // If we have a method cache and we aren't already doing a method-only
-- // search, we restart in method-only search mode if the first match is
-- // a method. This ensures that we return a MemberInfo with the correct
-- // ReflectedType for inherited methods.
-- if (do_method_search && (global.Count > 0)){
-- using_global = false;
--
-- return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
-- }
--
-- using_global = false;
-- MemberInfo [] copy = new MemberInfo [global.Count];
-- global.CopyTo (copy);
-- return copy;
-- }
--
-- /// <summary>
-- /// Returns true if iterface exists in any base interfaces (ifaces)
-- /// </summary>
-- static bool IsInterfaceBaseInterface (Type[] ifaces, Type ifaceToFind)
-- {
-- foreach (Type iface in ifaces) {
-- if (iface == ifaceToFind)
-- return true;
--
-- Type[] base_ifaces = TypeManager.GetInterfaces (iface);
-- if (base_ifaces.Length > 0 && IsInterfaceBaseInterface (base_ifaces, ifaceToFind))
-- return true;
-- }
-- return false;
-- }
--
-- // find the nested type @name in @this.
-- public Type FindNestedType (string name)
-- {
-- List<CacheEntry> applicable;
-- if (!member_hash.TryGetValue (name, out applicable))
-- return null;
--
-- for (int i = applicable.Count-1; i >= 0; i--) {
-- CacheEntry entry = applicable [i];
-- if ((entry.EntryType & EntryType.NestedType & EntryType.MaskType) != 0)
-- return (Type) entry.Member;
-- }
--
-- return null;
-- }
--
-- public MemberInfo FindBaseEvent (Type invocation_type, string name)
-- {
-- List<CacheEntry> applicable;
-- if (!member_hash.TryGetValue (name, out applicable))
-- return null;
--
-- //
-- // Walk the chain of events, starting from the top.
-- //
-- for (int i = applicable.Count - 1; i >= 0; i--)
-- {
-- CacheEntry entry = applicable [i];
-- if ((entry.EntryType & EntryType.Event) == 0)
-- continue;
--
-- EventInfo ei = (EventInfo)entry.Member;
-- return ei.GetAddMethod (true);
-- }
--
-- return null;
-- }
--
-- //
-- // Looks for extension methods with defined name and extension type
-- //
-- public List<MethodSpec> FindExtensionMethods (Assembly thisAssembly, Type extensionType, string name, bool publicOnly)
-- {
-- List<CacheEntry> entries;
-- if (method_hash != null)
-- method_hash.TryGetValue (name, out entries);
-- else {
-- member_hash.TryGetValue (name, out entries);
-- }
--
-- if (entries == null)
-- return null;
--
-- EntryType entry_type = EntryType.Static | EntryType.Method | EntryType.NotExtensionMethod;
-- EntryType found_entry_type = entry_type & ~EntryType.NotExtensionMethod;
--
-- List<MethodSpec> candidates = null;
-- foreach (CacheEntry entry in entries) {
-- if ((entry.EntryType & entry_type) == found_entry_type) {
-- MethodBase mb = (MethodBase)entry.Member;
--
-- // Simple accessibility check
-- if ((entry.EntryType & EntryType.Public) == 0 && publicOnly) {
-- MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
-- if (ma != MethodAttributes.Assembly && ma != MethodAttributes.FamORAssem)
-- continue;
--
-- if (!TypeManager.IsThisOrFriendAssembly (thisAssembly, mb.DeclaringType.Assembly))
-- continue;
-- }
--
-- IMethodData md = TypeManager.GetMethod (mb);
-- AParametersCollection pd = md == null ?
-- TypeManager.GetParameterData (mb) : md.ParameterInfo;
--
-- Type ex_type = pd.ExtensionMethodType;
-- if (ex_type == null) {
-- entry.EntryType |= EntryType.NotExtensionMethod;
-- continue;
-- }
--
-- if (candidates == null)
-- candidates = new List<MethodSpec> (2);
-- candidates.Add (Import.CreateMethod (mb));
-- }
-- }
--
-- return candidates;
-- }
--
-- //
-- // This finds the method or property for us to override. invocation_type is the type where
-- // the override is going to be declared, name is the name of the method/property, and
-- // param_types is the parameters, if any to the method or property
-- //
-- // Because the MemberCache holds members from this class and all the base classes,
-- // we can avoid tons of reflection stuff.
-- //
-- public MemberInfo FindMemberToOverride (Type invocation_type, string name, AParametersCollection parameters, GenericMethod generic_method, bool is_property)
-- {
-- List<CacheEntry> applicable;
-- if (method_hash != null && !is_property)
-- method_hash.TryGetValue (name, out applicable);
-- else
-- member_hash.TryGetValue (name, out applicable);
--
-- if (applicable == null)
-- return null;
-- //
-- // Walk the chain of methods, starting from the top.
-- //
-- for (int i = applicable.Count - 1; i >= 0; i--) {
-- CacheEntry entry = applicable [i];
--
-- if ((entry.EntryType & (is_property ? (EntryType.Property | EntryType.Field) : EntryType.Method)) == 0)
-- continue;
--
-- PropertyInfo pi = null;
-- MethodInfo mi = null;
-- FieldInfo fi = null;
-- AParametersCollection cmp_attrs;
--
-- if (is_property) {
-- if ((entry.EntryType & EntryType.Field) != 0) {
-- fi = (FieldInfo)entry.Member;
-- cmp_attrs = ParametersCompiled.EmptyReadOnlyParameters;
-- } else {
-- pi = (PropertyInfo) entry.Member;
-- cmp_attrs = TypeManager.GetParameterData (pi);
-- }
-- } else {
-- mi = (MethodInfo) entry.Member;
-- cmp_attrs = TypeManager.GetParameterData (mi);
-- }
--
-- if (fi != null) {
-- // TODO: Almost duplicate !
-- // Check visibility
-- switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
-- case FieldAttributes.PrivateScope:
-- continue;
-- case FieldAttributes.Private:
-- //
-- // A private method is Ok if we are a nested subtype.
-- // The spec actually is not very clear about this, see bug 52458.
-- //
-- if (!invocation_type.Equals (entry.Container.Type) &&
-- !TypeManager.IsNestedChildOf (invocation_type, entry.Container.Type))
-- continue;
-- break;
-- case FieldAttributes.FamANDAssem:
-- case FieldAttributes.Assembly:
-- //
-- // Check for assembly methods
-- //
-- if (fi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
-- continue;
-- break;
-- }
-- return entry.Member;
-- }
--
-- //
-- // Check the arguments
-- //
-- if (cmp_attrs.Count != parameters.Count)
-- continue;
--
-- int j;
-- for (j = 0; j < cmp_attrs.Count; ++j) {
-- //
-- // LAMESPEC: No idea why `params' modifier is ignored
-- //
-- if ((parameters.FixedParameters [j].ModFlags & ~Parameter.Modifier.PARAMS) !=
-- (cmp_attrs.FixedParameters [j].ModFlags & ~Parameter.Modifier.PARAMS))
-- break;
--
-- if (!TypeManager.IsEqual (parameters.Types [j], cmp_attrs.Types [j]))
-- break;
-- }
--
-- if (j < cmp_attrs.Count)
-- continue;
--
-- //
-- // check generic arguments for methods
-- //
-- if (mi != null) {
-- Type [] cmpGenArgs = TypeManager.GetGenericArguments (mi);
-- if (generic_method == null && cmpGenArgs != null && cmpGenArgs.Length != 0)
-- continue;
-- if (generic_method != null && cmpGenArgs != null && cmpGenArgs.Length != generic_method.TypeParameters.Length)
-- continue;
-- }
--
-- //
-- // get one of the methods because this has the visibility info.
-- //
-- if (is_property) {
-- mi = pi.GetGetMethod (true);
-- if (mi == null)
-- mi = pi.GetSetMethod (true);
-- }
--
-- //
-- // Check visibility
-- //
-- switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
-- case MethodAttributes.PrivateScope:
-- continue;
-- case MethodAttributes.Private:
-- //
-- // A private method is Ok if we are a nested subtype.
-- // The spec actually is not very clear about this, see bug 52458.
-- //
-- if (!invocation_type.Equals (entry.Container.Type) &&
-- !TypeManager.IsNestedChildOf (invocation_type, entry.Container.Type))
-- continue;
-- break;
-- case MethodAttributes.FamANDAssem:
-- case MethodAttributes.Assembly:
-- //
-- // Check for assembly methods
-- //
-- if (!TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly))
-- continue;
-- break;
-- }
-- return entry.Member;
-- }
--
-- return null;
-- }
--
-- /// <summary>
-- /// The method is looking for conflict with inherited symbols (errors CS0108, CS0109).
-- /// We handle two cases. The first is for types without parameters (events, field, properties).
-- /// The second are methods, indexers and this is why ignore_complex_types is here.
-- /// The latest param is temporary hack. See DoDefineMembers method for more info.
-- /// </summary>
-- public MemberInfo FindMemberWithSameName (string name, bool ignore_complex_types, MemberInfo ignore_member)
-- {
-- List<CacheEntry> applicable = null;
--
-- if (method_hash != null)
-- method_hash.TryGetValue (name, out applicable);
--
-- if (applicable != null) {
-- for (int i = applicable.Count - 1; i >= 0; i--) {
-- CacheEntry entry = (CacheEntry) applicable [i];
-- if ((entry.EntryType & EntryType.Public) != 0)
-- return entry.Member;
-- }
-- }
--
-- if (member_hash == null)
-- return null;
--
-- if (member_hash.TryGetValue (name, out applicable)) {
-- for (int i = applicable.Count - 1; i >= 0; i--) {
-- CacheEntry entry = (CacheEntry) applicable [i];
-- if ((entry.EntryType & EntryType.Public) != 0 & entry.Member != ignore_member) {
-- if (ignore_complex_types) {
-- if ((entry.EntryType & EntryType.Method) != 0)
-- continue;
--
-- // Does exist easier way how to detect indexer ?
-- if ((entry.EntryType & EntryType.Property) != 0) {
-- AParametersCollection arg_types = TypeManager.GetParameterData ((PropertyInfo)entry.Member);
-- if (arg_types.Count > 0)
-- continue;
-- }
-- }
-- return entry.Member;
-- }
-- }
-- }
-- return null;
-- }
--
--
-- /// <summary>
-- /// Builds low-case table for CLS Compliance test
-- /// </summary>
-- public Dictionary<string, object> GetPublicMembers ()
-- {
-- if (locase_table != null)
-- return locase_table;
--
-- locase_table = new Dictionary<string, object> ();
-- foreach (var entry in member_hash) {
-- var members = entry.Value;
-- for (int ii = 0; ii < members.Count; ++ii) {
-- CacheEntry member_entry = members [ii];
--
-- if ((member_entry.EntryType & EntryType.Public) == 0)
-- continue;
--
-- // TODO: Does anyone know easier way how to detect that member is internal ?
-- switch (member_entry.EntryType & EntryType.MaskType) {
-- case EntryType.Constructor:
-- continue;
--
-- case EntryType.Field:
-- if ((((FieldInfo)member_entry.Member).Attributes & (FieldAttributes.Assembly | FieldAttributes.Public)) == FieldAttributes.Assembly)
-- continue;
-- break;
--
-- case EntryType.Method:
-- if ((((MethodInfo)member_entry.Member).Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
-- continue;
-- break;
--
-- case EntryType.Property:
-- PropertyInfo pi = (PropertyInfo)member_entry.Member;
-- if (pi.GetSetMethod () == null && pi.GetGetMethod () == null)
-- continue;
-- break;
--
-- case EntryType.Event:
-- EventInfo ei = (EventInfo)member_entry.Member;
-- MethodInfo mi = ei.GetAddMethod ();
-- if ((mi.Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
-- continue;
-- break;
-- }
-- string lcase = ((string)entry.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture);
-- locase_table [lcase] = member_entry.Member;
-- break;
-- }
-- }
-- return locase_table;
-- }
--
-- public IDictionary<string, List<CacheEntry>> Members {
-- get {
-- return member_hash;
-- }
-- }
--
-- /// <summary>
-- /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
-- /// </summary>
-- ///
-- // TODO: refactor as method is always 'this'
-- public static void VerifyClsParameterConflict (IList<CacheEntry> al, MethodCore method, MemberInfo this_builder, Report Report)
-- {
-- EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public;
--
-- for (int i = 0; i < al.Count; ++i) {
-- var entry = al [i];
--
-- // skip itself
-- if (entry.Member == this_builder)
-- continue;
--
-- if ((entry.EntryType & tested_type) != tested_type)
-- continue;
--
-- MethodBase method_to_compare = (MethodBase)entry.Member;
-- AttributeTester.Result result = AttributeTester.AreOverloadedMethodParamsClsCompliant (
-- method.Parameters, TypeManager.GetParameterData (method_to_compare));
--
-- if (result == AttributeTester.Result.Ok)
-- continue;
--
-- IMethodData md = TypeManager.GetMethod (method_to_compare);
--
-- // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy.
-- // However it is exactly what csc does.
-- if (md != null && !md.IsClsComplianceRequired ())
-- continue;
--
-- Report.SymbolRelatedToPreviousError (entry.Member);
-- switch (result) {
-- case AttributeTester.Result.RefOutArrayError:
-- Report.Warning (3006, 1, method.Location,
-- "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
-- method.GetSignatureForError ());
-- continue;
-- case AttributeTester.Result.ArrayArrayError:
-- Report.Warning (3007, 1, method.Location,
-- "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
-- method.GetSignatureForError ());
-- continue;
-- }
--
-- throw new NotImplementedException (result.ToString ());
-- }
-- }
--
-- public bool CheckExistingMembersOverloads (MemberCore member, string name, ParametersCompiled parameters, Report Report)
-- {
-- List<CacheEntry> entries;
-- if (!member_hash.TryGetValue (name, out entries))
-- return true;
--
-- int method_param_count = parameters.Count;
-- for (int i = entries.Count - 1; i >= 0; --i) {
-- CacheEntry ce = (CacheEntry) entries [i];
--
-- if (ce.Container != member.Parent.PartialContainer)
-- return true;
--
-- Type [] p_types;
-- AParametersCollection pd;
-- if ((ce.EntryType & EntryType.Property) != 0) {
-- pd = TypeManager.GetParameterData ((PropertyInfo) ce.Member);
-- p_types = pd.Types;
-- } else {
-- MethodBase mb = (MethodBase) ce.Member;
--
-- // TODO: This is more like a hack, because we are adding generic methods
-- // twice with and without arity name
-- if (TypeManager.IsGenericMethod (mb) && !member.MemberName.IsGeneric)
-- continue;
--
-- pd = TypeManager.GetParameterData (mb);
-- p_types = pd.Types;
-- }
--
-- if (p_types.Length != method_param_count)
-- continue;
--
-- if (method_param_count > 0) {
-- int ii = method_param_count - 1;
-- Type type_a, type_b;
-- do {
-- type_a = parameters.Types [ii];
-- type_b = p_types [ii];
--
-- if (TypeManager.IsGenericParameter (type_a) && type_a.DeclaringMethod != null)
-- type_a = typeof (TypeParameter);
--
-- if (TypeManager.IsGenericParameter (type_b) && type_b.DeclaringMethod != null)
-- type_b = typeof (TypeParameter);
--
-- if ((pd.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF) !=
-- (parameters.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF))
-- break;
--
-- } while (TypeManager.IsEqual (type_a, type_b) && ii-- != 0);
--
-- if (ii >= 0)
-- continue;
--
-- //
-- // Operators can differ in return type only
-- //
-- if (member is Operator) {
-- Operator op = TypeManager.GetMethod ((MethodBase) ce.Member) as Operator;
-- if (op != null && op.ReturnType != ((Operator) member).ReturnType)
-- continue;
-- }
--
-- //
-- // Report difference in parameter modifiers only
-- //
-- if (pd != null && member is MethodCore) {
-- ii = method_param_count;
-- while (ii-- != 0 && parameters.FixedParameters [ii].ModFlags == pd.FixedParameters [ii].ModFlags &&
-- parameters.ExtensionMethodType == pd.ExtensionMethodType);
--
-- if (ii >= 0) {
-- MethodCore mc = TypeManager.GetMethod ((MethodBase) ce.Member) as MethodCore;
-- Report.SymbolRelatedToPreviousError (ce.Member);
-- if ((member.ModFlags & Modifiers.PARTIAL) != 0 && (mc.ModFlags & Modifiers.PARTIAL) != 0) {
-- if (parameters.HasParams || pd.HasParams) {
-- Report.Error (758, member.Location,
-- "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
-- } else {
-- Report.Error (755, member.Location,
-- "A partial method declaration and partial method implementation must be both an extension method or neither");
-- }
-- } else {
-- if (member is Constructor) {
-- Report.Error (851, member.Location,
-- "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
-- member.GetSignatureForError ());
-- } else {
-- Report.Error (663, member.Location,
-- "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
-- member.GetSignatureForError ());
-- }
-- }
-- return false;
-- }
-- }
-- }
--
-- if ((ce.EntryType & EntryType.Method) != 0) {
-- Method method_a = member as Method;
-- Method method_b = TypeManager.GetMethod ((MethodBase) ce.Member) as Method;
-- if (method_a != null && method_b != null && (method_a.ModFlags & method_b.ModFlags & Modifiers.PARTIAL) != 0) {
-- const Modifiers partial_modifiers = Modifiers.STATIC | Modifiers.UNSAFE;
-- if (method_a.IsPartialDefinition == method_b.IsPartialImplementation) {
-- if ((method_a.ModFlags & partial_modifiers) == (method_b.ModFlags & partial_modifiers) ||
-- method_a.Parent.IsUnsafe && method_b.Parent.IsUnsafe) {
-- if (method_a.IsPartialImplementation) {
-- method_a.SetPartialDefinition (method_b);
-- entries.RemoveAt (i);
-- } else {
-- method_b.SetPartialDefinition (method_a);
-- method_a.caching_flags |= MemberCore.Flags.PartialDefinitionExists;
-- }
-- continue;
-- }
--
-- if ((method_a.ModFlags & Modifiers.STATIC) != (method_b.ModFlags & Modifiers.STATIC)) {
-- Report.SymbolRelatedToPreviousError (ce.Member);
-- Report.Error (763, member.Location,
-- "A partial method declaration and partial method implementation must be both `static' or neither");
-- }
--
-- Report.SymbolRelatedToPreviousError (ce.Member);
-- Report.Error (764, member.Location,
-- "A partial method declaration and partial method implementation must be both `unsafe' or neither");
-- return false;
-- }
--
-- Report.SymbolRelatedToPreviousError (ce.Member);
-- if (method_a.IsPartialDefinition) {
-- Report.Error (756, member.Location, "A partial method `{0}' declaration is already defined",
-- member.GetSignatureForError ());
-- } else {
-- Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
-- member.GetSignatureForError ());
-- }
--
-- return false;
-- }
--
-- Report.SymbolRelatedToPreviousError (ce.Member);
-- IMethodData duplicate_member = TypeManager.GetMethod ((MethodBase) ce.Member);
-- if (member is Operator && duplicate_member is Operator) {
-- Report.Error (557, member.Location, "Duplicate user-defined conversion in type `{0}'",
-- member.Parent.GetSignatureForError ());
-- return false;
-- }
--
-- bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
-- bool is_reserved_b = duplicate_member is AbstractPropertyEventMethod || duplicate_member is Operator;
--
-- if (is_reserved_a || is_reserved_b) {
-- Report.Error (82, member.Location, "A member `{0}' is already reserved",
-- is_reserved_a ?
-- TypeManager.GetFullNameSignature (ce.Member) :
-- member.GetSignatureForError ());
-- return false;
-- }
-- } else {
-- Report.SymbolRelatedToPreviousError (ce.Member);
-- }
--
-- Report.Error (111, member.Location,
-- "A member `{0}' is already defined. Rename this member or use different parameter types",
-- member.GetSignatureForError ());
-- return false;
-- }
--
-- return true;
-- }
-- }
}
</Compile>
<Compile Include="location.cs">
</Compile>
++ <Compile Include="membercache.cs" />
<Compile Include="method.cs" />
<Compile Include="modifiers.cs">
</Compile>
</Compile>
<Compile Include="linq.cs" />
<Compile Include="field.cs" />
++ <Compile Include="typespec.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
linq.cs
literal.cs
location.cs
++membercache.cs
method.cs
modifiers.cs
namespace.cs
statement.cs
support.cs
typemanager.cs
++typespec.cs
symbolwriter.cs
../class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs
../class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs
}
}
}
++
++ public class EnumSpec : TypeSpec
++ {
++ public EnumSpec (MemberKind kind, ITypeDefinition definition, TypeSpec underlyingType, Type info, string name, Modifiers modifiers)
++ : base (kind, definition, info, name, modifiers)
++ {
++ this.UnderlyingType = underlyingType;
++ }
++
++ public TypeSpec UnderlyingType { get; private set; }
++ }
}
FieldInfo info;
public FieldSpec (IMemberDefinition definition, FieldInfo info, Modifiers modifiers)
-- : base (definition, info.Name, modifiers)
++ : base (MemberKind.Field, definition, info.Name, modifiers)
{
this.info = info;
}
linq.cs
literal.cs
location.cs
++membercache.cs
method.cs
modifiers.cs
namespace.cs
statement.cs
support.cs
typemanager.cs
++typespec.cs
symbolwriter.cs
../class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs
../class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
--// Copyright 2009 Novell, Inc
++// Copyright 2009, 2010 Novell, Inc
//
using System;
// TODO MemberCache: Use AParametersCollection p = ParametersImported.Create (mb);
AParametersCollection p = TypeManager.GetParameterData (mb);
-- MethodSpec ms = new MethodSpec (definition, mb, p, mod);
++
++ MemberKind kind;
++ if (mb.IsConstructor) {
++ kind = MemberKind.Constructor;
++ } else {
++ //
++ // Detect operators and destructors
++ //
++ string name = mb.Name;
++ kind = MemberKind.Method;
++ if (!mb.DeclaringType.IsInterface && name.Length > 6) {
++ if ((mod & Modifiers.STATIC) != 0 && name[2] == '_' && name[1] == 'p' && name[0] == 'o') {
++ var op_type = Operator.GetType (name);
++ if (op_type.HasValue) {
++ kind = MemberKind.Operator;
++ }
++ } else if (p.IsEmpty && (mod & Modifiers.STATIC) == 0 && name == Destructor.MetadataName) {
++ kind = MemberKind.Destructor;
++ }
++ }
++ }
++
++ MethodSpec ms = new MethodSpec (kind, definition, mb, p, mod);
return ms;
}
- return new PropertySpec (definition, pi, mod);
+ public static PropertySpec CreateProperty (PropertyInfo pi)
+ {
+ var definition = new ImportedMemberDefinition (pi);
+ var mod = Modifiers.PRIVATE; // TODO: modifiers
++ return new PropertySpec (MemberKind.Property | MemberKind.Indexer, definition, pi, mod);
++ }
++
++ static TypeSpec CreateType (Type type)
++ {
++ Modifiers mod = 0;
++ var ma = type.Attributes;
++ switch (ma & TypeAttributes.VisibilityMask) {
++ case TypeAttributes.Public:
++ case TypeAttributes.NestedPublic:
++ mod = Modifiers.PUBLIC;
++ break;
++ case TypeAttributes.NestedPrivate:
++ mod = Modifiers.PRIVATE;
++ break;
++ case TypeAttributes.NestedFamily:
++ mod = Modifiers.PROTECTED;
++ break;
++ case TypeAttributes.NestedFamORAssem:
++ mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
++ break;
++ default:
++ mod = Modifiers.INTERNAL;
++ break;
++ }
++
++ var type_def = TypeManager.DropGenericTypeArguments (type);
++
++ MemberKind kind;
++ if (type_def.IsInterface)
++ kind = MemberKind.Interface;
++ else if (type_def.IsEnum)
++ kind = MemberKind.Enum;
++ else if (type_def.IsClass) {
++ if (type_def.BaseType == TypeManager.multicast_delegate_type)
++ kind = MemberKind.Delegate;
++ else
++ kind = MemberKind.Class;
++ } else {
++ kind = MemberKind.Struct;
++ }
++
++ if (type.IsGenericType) {
++ throw new NotImplementedException ();
++ }
++
++ var definition = new ImportedTypeDefinition (type_def);
++ var spec = new TypeSpec (kind, definition, type, type.Name, mod);
++
++ // TODO: BaseType for class only?
++
++ return spec;
++ }
++
++ public static TypeSpec ImportType (Type type)
++ {
++ if (type.IsDefined (typeof (CompilerGeneratedAttribute), false))
++ return null;
++
++ return CreateType (type);
+ }
+
//
// Decimal constants cannot be encoded in the constant blob, and thus are marked
// as IsInitOnly ('readonly' in C# parlance). We get its value from the
return ((MethodInfo) provider).MakeGenericMethod (targs);
}
}
++
++ class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition
++ {
++ public ImportedTypeDefinition (Type type)
++ : base (type)
++ {
++ }
++
++ public void LoadMembers (MemberCache cache)
++ {
++ throw new NotImplementedException ();
++ }
++ }
}
--- /dev/null
--- /dev/null
++//
++// membercache.cs: A container for all member lookups
++//
++// Author: Miguel de Icaza (miguel@gnu.org)
++// Marek Safar (marek.safar@gmail.com)
++//
++// Dual licensed under the terms of the MIT X11 or GNU GPL
++//
++// Copyright 2001 Ximian, Inc (http://www.ximian.com)
++// Copyright 2004-2010 Novell, Inc
++//
++//
++
++using System;
++using System.Text;
++using System.Collections.Generic;
++using System.Globalization;
++using System.Reflection.Emit;
++using System.Reflection;
++
++namespace Mono.CSharp {
++
++ [Flags]
++ public enum MemberKind
++ {
++ Constructor = 1,
++ Event = 1 << 1,
++ Field = 1 << 2,
++ Method = 1 << 3,
++ Property = 1 << 4,
++ Indexer = 1 << 5,
++ Operator = 1 << 6,
++ Destructor = 1 << 7,
++ //Constant = 1 << 8,
++
++ NestedType = 1 << 10,
++
++ Class = 1 << 11,
++ Struct = 1 << 12,
++ Delegate = 1 << 13,
++ Enum = 1 << 14,
++ Interface = 1 << 15,
++
++ MaskType = Constructor | Event | Field | Method | Property | NestedType | Indexer | Operator | Destructor,
++ All = MaskType
++ }
++
++ [Flags]
++ public enum BindingRestriction
++ {
++ None = 0,
++
++ // Member has to be accessible
++ AccessibleOnly = 1,
++
++ // Inspect only queried type members
++ DeclaredOnly = 1 << 1,
++
++ // Excluded static
++ InstanceOnly = 1 << 2,
++
++ //
++ NoOverloadableOverrides = 1 << 3
++ }
++/*
++ public struct MemberFilter : IEquatable<MemberCore>
++ {
++ public readonly string Name;
++ public readonly MemberKind Kind;
++ public readonly TypeSpec[] Parameters;
++ public readonly TypeSpec MemberType;
++
++ public MemberFilter (IMethod m)
++ {
++ Name = m.MethodBuilder.Name;
++ Kind = MemberKind.Method;
++ Parameters = m.Parameters.Types;
++ MemberType = m.ReturnType;
++ }
++
++ public MemberFilter (string name, MemberKind kind)
++ {
++ Name = name;
++ Kind = kind;
++ Parameters = null;
++ MemberType = null;
++ }
++
++ public MemberFilter (string name, MemberKind kind, TypeSpec[] param, TypeSpec type)
++ : this (name, kind)
++ {
++ Name = name;
++ Kind = kind;
++ Parameters = param;
++ MemberType = type;
++ }
++
++ public static MemberFilter Constuctor (TypeSpec[] param)
++ {
++ return new MemberFilter (System.Reflection.ConstructorInfo.ConstructorName, MemberKind.Constructor, param, null);
++ }
++
++ public static MemberFilter Property (string name, TypeSpec type)
++ {
++ return new MemberFilter (name, MemberKind.Property, null, type);
++ }
++
++ public static MemberFilter Field (string name, TypeSpec type)
++ {
++ return new MemberFilter (name, MemberKind.Field, null, type);
++ }
++
++ public static MemberFilter Method (string name, TypeSpec[] param, TypeSpec type)
++ {
++ return new MemberFilter (name, MemberKind.Method, param, type);
++ }
++
++ #region IEquatable<MemberCore> Members
++
++ public bool Equals (MemberCore other)
++ {
++ // Is the member of the correct type ?
++ if ((other.MemberKind & Kind & MemberKind.MaskType) == 0)
++ return false;
++
++ if (Parameters != null) {
++ if (other is IParametersMember) {
++ AParametersCollection other_param = ((IParametersMember) other).Parameters;
++ if (TypeSpecArrayComparer.Default.Equals (Parameters, other_param.Types))
++ return true;
++ }
++
++ return false;
++ }
++
++ if (MemberType != null) {
++ //throw new NotImplementedException ();
++ }
++
++ return true;
++ }
++
++ #endregion
++ }
++*/
++ /// <summary>
++ /// This is a readonly list of MemberInfo's.
++ /// </summary>
++ public class MemberList : IList<MemberInfo> {
++ public readonly IList<MemberInfo> List;
++ int count;
++
++ /// <summary>
++ /// Create a new MemberList from the given IList.
++ /// </summary>
++ public MemberList (IList<MemberInfo> list)
++ {
++ if (list != null)
++ this.List = list;
++ else
++ this.List = new List<MemberInfo> ();
++ count = List.Count;
++ }
++
++ /// <summary>
++ /// Concatenate the ILists `first' and `second' to a new MemberList.
++ /// </summary>
++ public MemberList (IList<MemberInfo> first, IList<MemberInfo> second)
++ {
++ var list = new List<MemberInfo> ();
++ list.AddRange (first);
++ list.AddRange (second);
++ count = list.Count;
++ List = list;
++ }
++
++ public static readonly MemberList Empty = new MemberList (Array.AsReadOnly (new MemberInfo[0]));
++
++ /// <summary>
++ /// Cast the MemberList into a MemberInfo[] array.
++ /// </summary>
++ /// <remarks>
++ /// This is an expensive operation, only use it if it's really necessary.
++ /// </remarks>
++ public static explicit operator MemberInfo [] (MemberList list)
++ {
++ Timer.StartTimer (TimerType.MiscTimer);
++ MemberInfo [] result = new MemberInfo [list.Count];
++ list.CopyTo (result, 0);
++ Timer.StopTimer (TimerType.MiscTimer);
++ return result;
++ }
++
++ // ICollection
++
++ public int Count {
++ get {
++ return count;
++ }
++ }
++
++ public void CopyTo (MemberInfo[] array, int index)
++ {
++ List.CopyTo (array, index);
++ }
++
++ // IEnumerable
++
++ public IEnumerator<MemberInfo> GetEnumerator ()
++ {
++ return List.GetEnumerator ();
++ }
++
++ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
++ {
++ return List.GetEnumerator ();
++ }
++
++ // IList
++
++ public bool IsFixedSize {
++ get {
++ return true;
++ }
++ }
++
++ public bool IsReadOnly {
++ get {
++ return true;
++ }
++ }
++
++ MemberInfo IList<MemberInfo>.this [int index] {
++ get {
++ return List [index];
++ }
++
++ set {
++ throw new NotSupportedException ();
++ }
++ }
++
++ // FIXME: try to find out whether we can avoid the cast in this indexer.
++ public MemberInfo this [int index] {
++ get {
++ return (MemberInfo) List [index];
++ }
++ }
++
++ public void Add (MemberInfo value)
++ {
++ throw new NotSupportedException ();
++ }
++
++ public void Clear ()
++ {
++ throw new NotSupportedException ();
++ }
++
++ public bool Contains (MemberInfo value)
++ {
++ return List.Contains (value);
++ }
++
++ public int IndexOf (MemberInfo value)
++ {
++ return List.IndexOf (value);
++ }
++
++ public void Insert (int index, MemberInfo value)
++ {
++ throw new NotSupportedException ();
++ }
++
++ public bool Remove (MemberInfo value)
++ {
++ throw new NotSupportedException ();
++ }
++
++ public void RemoveAt (int index)
++ {
++ throw new NotSupportedException ();
++ }
++ }
++
++ /// <summary>
++ /// This interface is used to get all members of a class when creating the
++ /// member cache. It must be implemented by all DeclSpace derivatives which
++ /// want to support the member cache and by TypeHandle to get caching of
++ /// non-dynamic types.
++ /// </summary>
++ public interface IMemberContainer {
++ /// <summary>
++ /// The name of the IMemberContainer. This is only used for
++ /// debugging purposes.
++ /// </summary>
++ string Name {
++ get;
++ }
++
++ /// <summary>
++ /// The type of this IMemberContainer.
++ /// </summary>
++ Type Type {
++ get;
++ }
++
++ /// <summary>
++ /// Returns the IMemberContainer of the base class or null if this
++ /// is an interface or TypeManger.object_type.
++ /// This is used when creating the member cache for a class to get all
++ /// members from the base class.
++ /// </summary>
++ MemberCache BaseCache {
++ get;
++ }
++
++ /// <summary>
++ /// Whether this is an interface.
++ /// </summary>
++ bool IsInterface {
++ get;
++ }
++
++ /// <summary>
++ /// Returns all members of this class with the corresponding MemberTypes
++ /// and BindingFlags.
++ /// </summary>
++ /// <remarks>
++ /// When implementing this method, make sure not to return any inherited
++ /// members and check the MemberTypes and BindingFlags properly.
++ /// Unfortunately, System.Reflection is lame and doesn't provide a way to
++ /// get the BindingFlags (static/non-static,public/non-public) in the
++ /// MemberInfo class, but the cache needs this information. That's why
++ /// this method is called multiple times with different BindingFlags.
++ /// </remarks>
++ MemberList GetMembers (MemberTypes mt, BindingFlags bf);
++ }
++
++ /// <summary>
++ /// The MemberCache is used by dynamic and non-dynamic types to speed up
++ /// member lookups. It has a member name based hash table; it maps each member
++ /// name to a list of CacheEntry objects. Each CacheEntry contains a MemberInfo
++ /// and the BindingFlags that were initially used to get it. The cache contains
++ /// all members of the current class and all inherited members. If this cache is
++ /// for an interface types, it also contains all inherited members.
++ ///
++ /// There are two ways to get a MemberCache:
++ /// * if this is a dynamic type, lookup the corresponding DeclSpace and then
++ /// use the DeclSpace.MemberCache property.
++ /// * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
++ /// TypeHandle instance for the type and then use TypeHandle.MemberCache.
++ /// </summary>
++ public class MemberCache {
++ public readonly IMemberContainer Container;
++ protected Dictionary<string, List<CacheEntry>> member_hash;
++ protected Dictionary<string, List<CacheEntry>> method_hash;
++
++ Dictionary<string, object> locase_table;
++
++ static List<MethodInfo> overrides = new List<MethodInfo> ();
++
++ /// <summary>
++ /// Create a new MemberCache for the given IMemberContainer `container'.
++ /// </summary>
++ public MemberCache (IMemberContainer container)
++ {
++ this.Container = container;
++
++ Timer.IncrementCounter (CounterType.MemberCache);
++ Timer.StartTimer (TimerType.CacheInit);
++
++ // If we have a base class (we have a base class unless we're
++ // TypeManager.object_type), we deep-copy its MemberCache here.
++ if (Container.BaseCache != null)
++ member_hash = SetupCache (Container.BaseCache);
++ else
++ member_hash = new Dictionary<string, List<CacheEntry>> ();
++
++ // If this is neither a dynamic type nor an interface, create a special
++ // method cache with all declared and inherited methods.
++ Type type = container.Type;
++ if (!(type is TypeBuilder) && !type.IsInterface &&
++ // !(type.IsGenericType && (type.GetGenericTypeDefinition () is TypeBuilder)) &&
++ !TypeManager.IsGenericType (type) && !TypeManager.IsGenericParameter (type) &&
++ (Container.BaseCache == null || Container.BaseCache.method_hash != null)) {
++ method_hash = new Dictionary<string, List<CacheEntry>> ();
++ AddMethods (type);
++ }
++
++ // Add all members from the current class.
++ AddMembers (Container);
++
++ Timer.StopTimer (TimerType.CacheInit);
++ }
++
++ public MemberCache (Type baseType, IMemberContainer container)
++ {
++ this.Container = container;
++ if (baseType == null)
++ this.member_hash = new Dictionary<string, List<CacheEntry>> ();
++ else
++ this.member_hash = SetupCache (TypeManager.LookupMemberCache (baseType));
++ }
++
++ public MemberCache (Type[] ifaces)
++ {
++ //
++ // The members of this cache all belong to other caches.
++ // So, 'Container' will not be used.
++ //
++ this.Container = null;
++
++ member_hash = new Dictionary<string, List<CacheEntry>> ();
++ if (ifaces == null)
++ return;
++
++ foreach (Type itype in ifaces)
++ AddCacheContents (TypeManager.LookupMemberCache (itype));
++ }
++
++ public MemberCache (IMemberContainer container, Type base_class, Type[] ifaces)
++ {
++ this.Container = container;
++
++ // If we have a base class (we have a base class unless we're
++ // TypeManager.object_type), we deep-copy its MemberCache here.
++ if (Container.BaseCache != null)
++ member_hash = SetupCache (Container.BaseCache);
++ else
++ member_hash = new Dictionary<string, List<CacheEntry>> ();
++
++ if (base_class != null)
++ AddCacheContents (TypeManager.LookupMemberCache (base_class));
++ if (ifaces != null) {
++ foreach (Type itype in ifaces) {
++ MemberCache cache = TypeManager.LookupMemberCache (itype);
++ if (cache != null)
++ AddCacheContents (cache);
++ }
++ }
++ }
++
++ /// <summary>
++ /// Bootstrap this member cache by doing a deep-copy of our base.
++ /// </summary>
++ static Dictionary<string, List<CacheEntry>> SetupCache (MemberCache base_class)
++ {
++ if (base_class == null)
++ return new Dictionary<string, List<CacheEntry>> ();
++
++ var hash = new Dictionary<string, List<CacheEntry>> (base_class.member_hash.Count);
++ var it = base_class.member_hash.GetEnumerator ();
++ while (it.MoveNext ()) {
++ hash.Add (it.Current.Key, new List<CacheEntry> (it.Current.Value));
++ }
++
++ return hash;
++ }
++
++ //
++ // Converts ModFlags to BindingFlags
++ //
++ static BindingFlags GetBindingFlags (Modifiers modifiers)
++ {
++ BindingFlags bf;
++ if ((modifiers & Modifiers.STATIC) != 0)
++ bf = BindingFlags.Static;
++ else
++ bf = BindingFlags.Instance;
++
++ if ((modifiers & Modifiers.PRIVATE) != 0)
++ bf |= BindingFlags.NonPublic;
++ else
++ bf |= BindingFlags.Public;
++
++ return bf;
++ }
++
++ /// <summary>
++ /// Add the contents of `cache' to the member_hash.
++ /// </summary>
++ void AddCacheContents (MemberCache cache)
++ {
++ var it = cache.member_hash.GetEnumerator ();
++ while (it.MoveNext ()) {
++ List<CacheEntry> list;
++ if (!member_hash.TryGetValue (it.Current.Key, out list))
++ member_hash [it.Current.Key] = list = new List<CacheEntry> ();
++
++ var entries = it.Current.Value;
++ for (int i = entries.Count-1; i >= 0; i--) {
++ var entry = entries [i];
++
++ if (entry.Container != cache.Container)
++ break;
++ list.Add (entry);
++ }
++ }
++ }
++
++ /// <summary>
++ /// Add all members from class `container' to the cache.
++ /// </summary>
++ void AddMembers (IMemberContainer container)
++ {
++ // We need to call AddMembers() with a single member type at a time
++ // to get the member type part of CacheEntry.EntryType right.
++ if (!container.IsInterface) {
++ AddMembers (MemberTypes.Constructor, container);
++ AddMembers (MemberTypes.Field, container);
++ }
++ AddMembers (MemberTypes.Method, container);
++ AddMembers (MemberTypes.Property, container);
++ AddMembers (MemberTypes.Event, container);
++ // Nested types are returned by both Static and Instance searches.
++ AddMembers (MemberTypes.NestedType,
++ BindingFlags.Static | BindingFlags.Public, container);
++ AddMembers (MemberTypes.NestedType,
++ BindingFlags.Static | BindingFlags.NonPublic, container);
++ }
++
++ void AddMembers (MemberTypes mt, IMemberContainer container)
++ {
++ AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
++ AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
++ AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
++ AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
++ }
++
++ public void AddMember (MemberInfo mi, MemberCore mc)
++ {
++ AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container, mi.Name, mi);
++ }
++
++ public void AddGenericMember (MemberInfo mi, InterfaceMemberBase mc)
++ {
++ AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container,
++ MemberName.MakeName (mc.GetFullName (mc.MemberName), mc.MemberName.TypeArguments), mi);
++ }
++
++ public void AddNestedType (DeclSpace type)
++ {
++ AddMember (MemberTypes.NestedType, GetBindingFlags (type.ModFlags), (IMemberContainer) type.Parent,
++ type.TypeBuilder.Name, type.TypeBuilder);
++ }
++
++ public void AddInterface (MemberCache baseCache)
++ {
++ if (baseCache.member_hash.Count > 0)
++ AddCacheContents (baseCache);
++ }
++
++ void AddMember (MemberTypes mt, BindingFlags bf, IMemberContainer container,
++ string name, MemberInfo member)
++ {
++ // We use a name-based hash table of ArrayList's.
++ List<CacheEntry> list;
++ if (!member_hash.TryGetValue (name, out list)) {
++ list = new List<CacheEntry> (1);
++ member_hash.Add (name, list);
++ }
++
++ // When this method is called for the current class, the list will
++ // already contain all inherited members from our base classes.
++ // We cannot add new members in front of the list since this'd be an
++ // expensive operation, that's why the list is sorted in reverse order
++ // (ie. members from the current class are coming last).
++ list.Add (new CacheEntry (container, member, mt, bf));
++ }
++
++ /// <summary>
++ /// Add all members from class `container' with the requested MemberTypes and
++ /// BindingFlags to the cache. This method is called multiple times with different
++ /// MemberTypes and BindingFlags.
++ /// </summary>
++ void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
++ {
++ MemberList members = container.GetMembers (mt, bf);
++
++ foreach (MemberInfo member in members) {
++ string name = member.Name;
++
++ AddMember (mt, bf, container, name, member);
++
++ if (member is MethodInfo) {
++ string gname = TypeManager.GetMethodName ((MethodInfo) member);
++ if (gname != name)
++ AddMember (mt, bf, container, gname, member);
++ }
++ }
++ }
++
++ /// <summary>
++ /// Add all declared and inherited methods from class `type' to the method cache.
++ /// </summary>
++ void AddMethods (Type type)
++ {
++ AddMethods (BindingFlags.Static | BindingFlags.Public |
++ BindingFlags.FlattenHierarchy, type);
++ AddMethods (BindingFlags.Static | BindingFlags.NonPublic |
++ BindingFlags.FlattenHierarchy, type);
++ AddMethods (BindingFlags.Instance | BindingFlags.Public, type);
++ AddMethods (BindingFlags.Instance | BindingFlags.NonPublic, type);
++ }
++
++ void AddMethods (BindingFlags bf, Type type)
++ {
++ MethodBase [] members = type.GetMethods (bf);
++
++ Array.Reverse (members);
++
++ foreach (MethodBase member in members) {
++ string name = member.Name;
++
++ // We use a name-based hash table of ArrayList's.
++ List<CacheEntry> list;
++ if (!method_hash.TryGetValue (name, out list)) {
++ list = new List<CacheEntry> (1);
++ method_hash.Add (name, list);
++ }
++
++ MethodInfo curr = (MethodInfo) member;
++ while (curr.IsVirtual && (curr.Attributes & MethodAttributes.NewSlot) == 0) {
++ MethodInfo base_method = curr.GetBaseDefinition ();
++
++ if (base_method == curr)
++ // Not every virtual function needs to have a NewSlot flag.
++ break;
++
++ overrides.Add (curr);
++ list.Add (new CacheEntry (null, base_method, MemberTypes.Method, bf));
++ curr = base_method;
++ }
++
++ if (overrides.Count > 0) {
++ for (int i = 0; i < overrides.Count; ++i)
++ TypeManager.RegisterOverride ((MethodBase) overrides [i], curr);
++ overrides.Clear ();
++ }
++
++ // Unfortunately, the elements returned by Type.GetMethods() aren't
++ // sorted so we need to do this check for every member.
++ BindingFlags new_bf = bf;
++ if (member.DeclaringType == type)
++ new_bf |= BindingFlags.DeclaredOnly;
++
++ list.Add (new CacheEntry (Container, member, MemberTypes.Method, new_bf));
++ }
++ }
++
++ /// <summary>
++ /// Compute and return a appropriate `EntryType' magic number for the given
++ /// MemberTypes and BindingFlags.
++ /// </summary>
++ protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
++ {
++ EntryType type = EntryType.None;
++
++ if ((mt & MemberTypes.Constructor) != 0)
++ type |= EntryType.Constructor;
++ if ((mt & MemberTypes.Event) != 0)
++ type |= EntryType.Event;
++ if ((mt & MemberTypes.Field) != 0)
++ type |= EntryType.Field;
++ if ((mt & MemberTypes.Method) != 0)
++ type |= EntryType.Method;
++ if ((mt & MemberTypes.Property) != 0)
++ type |= EntryType.Property;
++ // Nested types are returned by static and instance searches.
++ if ((mt & MemberTypes.NestedType) != 0)
++ type |= EntryType.NestedType | EntryType.Static | EntryType.Instance;
++
++ if ((bf & BindingFlags.Instance) != 0)
++ type |= EntryType.Instance;
++ if ((bf & BindingFlags.Static) != 0)
++ type |= EntryType.Static;
++ if ((bf & BindingFlags.Public) != 0)
++ type |= EntryType.Public;
++ if ((bf & BindingFlags.NonPublic) != 0)
++ type |= EntryType.NonPublic;
++ if ((bf & BindingFlags.DeclaredOnly) != 0)
++ type |= EntryType.Declared;
++
++ return type;
++ }
++
++ /// <summary>
++ /// The `MemberTypes' enumeration type is a [Flags] type which means that it may
++ /// denote multiple member types. Returns true if the given flags value denotes a
++ /// single member types.
++ /// </summary>
++ public static bool IsSingleMemberType (MemberTypes mt)
++ {
++ switch (mt) {
++ case MemberTypes.Constructor:
++ case MemberTypes.Event:
++ case MemberTypes.Field:
++ case MemberTypes.Method:
++ case MemberTypes.Property:
++ case MemberTypes.NestedType:
++ return true;
++
++ default:
++ return false;
++ }
++ }
++
++ /// <summary>
++ /// We encode the MemberTypes and BindingFlags of each members in a "magic"
++ /// number to speed up the searching process.
++ /// </summary>
++ [Flags]
++ public enum EntryType {
++ None = 0x000,
++
++ Instance = 0x001,
++ Static = 0x002,
++ MaskStatic = Instance|Static,
++
++ Public = 0x004,
++ NonPublic = 0x008,
++ MaskProtection = Public|NonPublic,
++
++ Declared = 0x010,
++
++ Constructor = 0x020,
++ Event = 0x040,
++ Field = 0x080,
++ Method = 0x100,
++ Property = 0x200,
++ NestedType = 0x400,
++
++ NotExtensionMethod = 0x800,
++
++ MaskType = Constructor|Event|Field|Method|Property|NestedType
++ }
++
++ public class CacheEntry {
++ public readonly IMemberContainer Container;
++ public EntryType EntryType;
++ public readonly MemberInfo Member;
++
++ public CacheEntry (IMemberContainer container, MemberInfo member,
++ MemberTypes mt, BindingFlags bf)
++ {
++ this.Container = container;
++ this.Member = member;
++ this.EntryType = GetEntryType (mt, bf);
++ }
++
++ public override string ToString ()
++ {
++ return String.Format ("CacheEntry ({0}:{1}:{2})", Container.Name,
++ EntryType, Member);
++ }
++ }
++
++ /// <summary>
++ /// This is called each time we're walking up one level in the class hierarchy
++ /// and checks whether we can abort the search since we've already found what
++ /// we were looking for.
++ /// </summary>
++ protected bool DoneSearching (IList<MemberInfo> list)
++ {
++ //
++ // We've found exactly one member in the current class and it's not
++ // a method or constructor.
++ //
++ if (list.Count == 1 && !(list [0] is MethodBase))
++ return true;
++
++ //
++ // Multiple properties: we query those just to find out the indexer
++ // name
++ //
++ if ((list.Count > 0) && (list [0] is PropertyInfo))
++ return true;
++
++ return false;
++ }
++
++ /// <summary>
++ /// Looks up members with name `name'. If you provide an optional
++ /// filter function, it'll only be called with members matching the
++ /// requested member name.
++ ///
++ /// This method will try to use the cache to do the lookup if possible.
++ ///
++ /// Unlike other FindMembers implementations, this method will always
++ /// check all inherited members - even when called on an interface type.
++ ///
++ /// If you know that you're only looking for methods, you should use
++ /// MemberTypes.Method alone since this speeds up the lookup a bit.
++ /// When doing a method-only search, it'll try to use a special method
++ /// cache (unless it's a dynamic type or an interface) and the returned
++ /// MemberInfo's will have the correct ReflectedType for inherited methods.
++ /// The lookup process will automatically restart itself in method-only
++ /// search mode if it discovers that it's about to return methods.
++ /// </summary>
++ List<MemberInfo> global = new List<MemberInfo> ();
++ bool using_global;
++
++ static MemberInfo [] emptyMemberInfo = new MemberInfo [0];
++
++ public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, string name,
++ MemberFilter filter, object criteria)
++ {
++ if (using_global)
++ throw new Exception ();
++
++ bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
++ bool method_search = mt == MemberTypes.Method;
++ // If we have a method cache and we aren't already doing a method-only search,
++ // then we restart a method search if the first match is a method.
++ bool do_method_search = !method_search && (method_hash != null);
++
++ List<CacheEntry> applicable;
++
++ // If this is a method-only search, we try to use the method cache if
++ // possible; a lookup in the method cache will return a MemberInfo with
++ // the correct ReflectedType for inherited methods.
++
++ if (method_search && (method_hash != null))
++ method_hash.TryGetValue (name, out applicable);
++ else
++ member_hash.TryGetValue (name, out applicable);
++
++ if (applicable == null)
++ return emptyMemberInfo;
++
++ //
++ // 32 slots gives 53 rss/54 size
++ // 2/4 slots gives 55 rss
++ //
++ // Strange: from 25,000 calls, only 1,800
++ // are above 2. Why does this impact it?
++ //
++ global.Clear ();
++ using_global = true;
++
++ Timer.StartTimer (TimerType.CachedLookup);
++
++ EntryType type = GetEntryType (mt, bf);
++
++ IMemberContainer current = Container;
++
++ bool do_interface_search = current.IsInterface;
++
++ // `applicable' is a list of all members with the given member name `name'
++ // in the current class and all its base classes. The list is sorted in
++ // reverse order due to the way how the cache is initialy created (to speed
++ // things up, we're doing a deep-copy of our base).
++
++ for (int i = applicable.Count-1; i >= 0; i--) {
++ CacheEntry entry = (CacheEntry) applicable [i];
++
++ // This happens each time we're walking one level up in the class
++ // hierarchy. If we're doing a DeclaredOnly search, we must abort
++ // the first time this happens (this may already happen in the first
++ // iteration of this loop if there are no members with the name we're
++ // looking for in the current class).
++ if (entry.Container != current) {
++ if (declared_only)
++ break;
++
++ if (!do_interface_search && DoneSearching (global))
++ break;
++
++ current = entry.Container;
++ }
++
++ // Is the member of the correct type ?
++ if ((entry.EntryType & type & EntryType.MaskType) == 0)
++ continue;
++
++ // Is the member static/non-static ?
++ if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
++ continue;
++
++ // Apply the filter to it.
++ if (filter (entry.Member, criteria)) {
++ if ((entry.EntryType & EntryType.MaskType) != EntryType.Method) {
++ do_method_search = false;
++ }
++
++ // Because interfaces support multiple inheritance we have to be sure that
++ // base member is from same interface, so only top level member will be returned
++ if (do_interface_search && global.Count > 0) {
++ bool member_already_exists = false;
++
++ foreach (MemberInfo mi in global) {
++ if (mi is MethodBase)
++ continue;
++
++ if (IsInterfaceBaseInterface (TypeManager.GetInterfaces (mi.DeclaringType), entry.Member.DeclaringType)) {
++ member_already_exists = true;
++ break;
++ }
++ }
++ if (member_already_exists)
++ continue;
++ }
++
++ global.Add (entry.Member);
++ }
++ }
++
++ Timer.StopTimer (TimerType.CachedLookup);
++
++ // If we have a method cache and we aren't already doing a method-only
++ // search, we restart in method-only search mode if the first match is
++ // a method. This ensures that we return a MemberInfo with the correct
++ // ReflectedType for inherited methods.
++ if (do_method_search && (global.Count > 0)){
++ using_global = false;
++
++ return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
++ }
++
++ using_global = false;
++ MemberInfo [] copy = new MemberInfo [global.Count];
++ global.CopyTo (copy);
++ return copy;
++ }
++
++ /// <summary>
++ /// Returns true if iterface exists in any base interfaces (ifaces)
++ /// </summary>
++ static bool IsInterfaceBaseInterface (Type[] ifaces, Type ifaceToFind)
++ {
++ foreach (Type iface in ifaces) {
++ if (iface == ifaceToFind)
++ return true;
++
++ Type[] base_ifaces = TypeManager.GetInterfaces (iface);
++ if (base_ifaces.Length > 0 && IsInterfaceBaseInterface (base_ifaces, ifaceToFind))
++ return true;
++ }
++ return false;
++ }
++
++ // find the nested type @name in @this.
++ public Type FindNestedType (string name)
++ {
++ List<CacheEntry> applicable;
++ if (!member_hash.TryGetValue (name, out applicable))
++ return null;
++
++ for (int i = applicable.Count-1; i >= 0; i--) {
++ CacheEntry entry = applicable [i];
++ if ((entry.EntryType & EntryType.NestedType & EntryType.MaskType) != 0)
++ return (Type) entry.Member;
++ }
++
++ return null;
++ }
++
++ public MemberInfo FindBaseEvent (Type invocation_type, string name)
++ {
++ List<CacheEntry> applicable;
++ if (!member_hash.TryGetValue (name, out applicable))
++ return null;
++
++ //
++ // Walk the chain of events, starting from the top.
++ //
++ for (int i = applicable.Count - 1; i >= 0; i--)
++ {
++ CacheEntry entry = applicable [i];
++ if ((entry.EntryType & EntryType.Event) == 0)
++ continue;
++
++ EventInfo ei = (EventInfo)entry.Member;
++ return ei.GetAddMethod (true);
++ }
++
++ return null;
++ }
++
++ //
++ // Looks for extension methods with defined name and extension type
++ //
++ public List<MethodSpec> FindExtensionMethods (Assembly thisAssembly, Type extensionType, string name, bool publicOnly)
++ {
++ List<CacheEntry> entries;
++ if (method_hash != null)
++ method_hash.TryGetValue (name, out entries);
++ else {
++ member_hash.TryGetValue (name, out entries);
++ }
++
++ if (entries == null)
++ return null;
++
++ EntryType entry_type = EntryType.Static | EntryType.Method | EntryType.NotExtensionMethod;
++ EntryType found_entry_type = entry_type & ~EntryType.NotExtensionMethod;
++
++ List<MethodSpec> candidates = null;
++ foreach (CacheEntry entry in entries) {
++ if ((entry.EntryType & entry_type) == found_entry_type) {
++ MethodBase mb = (MethodBase)entry.Member;
++
++ // Simple accessibility check
++ if ((entry.EntryType & EntryType.Public) == 0 && publicOnly) {
++ MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
++ if (ma != MethodAttributes.Assembly && ma != MethodAttributes.FamORAssem)
++ continue;
++
++ if (!TypeManager.IsThisOrFriendAssembly (thisAssembly, mb.DeclaringType.Assembly))
++ continue;
++ }
++
++ IMethodData md = TypeManager.GetMethod (mb);
++ AParametersCollection pd = md == null ?
++ TypeManager.GetParameterData (mb) : md.ParameterInfo;
++
++ Type ex_type = pd.ExtensionMethodType;
++ if (ex_type == null) {
++ entry.EntryType |= EntryType.NotExtensionMethod;
++ continue;
++ }
++
++ if (candidates == null)
++ candidates = new List<MethodSpec> (2);
++ candidates.Add (Import.CreateMethod (mb));
++ }
++ }
++
++ return candidates;
++ }
++
++ //
++ // This finds the method or property for us to override. invocation_type is the type where
++ // the override is going to be declared, name is the name of the method/property, and
++ // param_types is the parameters, if any to the method or property
++ //
++ // Because the MemberCache holds members from this class and all the base classes,
++ // we can avoid tons of reflection stuff.
++ //
++ public MemberInfo FindMemberToOverride (Type invocation_type, string name, AParametersCollection parameters, GenericMethod generic_method, bool is_property)
++ {
++ List<CacheEntry> applicable;
++ if (method_hash != null && !is_property)
++ method_hash.TryGetValue (name, out applicable);
++ else
++ member_hash.TryGetValue (name, out applicable);
++
++ if (applicable == null)
++ return null;
++ //
++ // Walk the chain of methods, starting from the top.
++ //
++ for (int i = applicable.Count - 1; i >= 0; i--) {
++ CacheEntry entry = applicable [i];
++
++ if ((entry.EntryType & (is_property ? (EntryType.Property | EntryType.Field) : EntryType.Method)) == 0)
++ continue;
++
++ PropertyInfo pi = null;
++ MethodInfo mi = null;
++ FieldInfo fi = null;
++ AParametersCollection cmp_attrs;
++
++ if (is_property) {
++ if ((entry.EntryType & EntryType.Field) != 0) {
++ fi = (FieldInfo)entry.Member;
++ cmp_attrs = ParametersCompiled.EmptyReadOnlyParameters;
++ } else {
++ pi = (PropertyInfo) entry.Member;
++ cmp_attrs = TypeManager.GetParameterData (pi);
++ }
++ } else {
++ mi = (MethodInfo) entry.Member;
++ cmp_attrs = TypeManager.GetParameterData (mi);
++ }
++
++ if (fi != null) {
++ // TODO: Almost duplicate !
++ // Check visibility
++ switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
++ case FieldAttributes.PrivateScope:
++ continue;
++ case FieldAttributes.Private:
++ //
++ // A private method is Ok if we are a nested subtype.
++ // The spec actually is not very clear about this, see bug 52458.
++ //
++ if (!invocation_type.Equals (entry.Container.Type) &&
++ !TypeManager.IsNestedChildOf (invocation_type, entry.Container.Type))
++ continue;
++ break;
++ case FieldAttributes.FamANDAssem:
++ case FieldAttributes.Assembly:
++ //
++ // Check for assembly methods
++ //
++ if (fi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
++ continue;
++ break;
++ }
++ return entry.Member;
++ }
++
++ //
++ // Check the arguments
++ //
++ if (cmp_attrs.Count != parameters.Count)
++ continue;
++
++ int j;
++ for (j = 0; j < cmp_attrs.Count; ++j) {
++ //
++ // LAMESPEC: No idea why `params' modifier is ignored
++ //
++ if ((parameters.FixedParameters [j].ModFlags & ~Parameter.Modifier.PARAMS) !=
++ (cmp_attrs.FixedParameters [j].ModFlags & ~Parameter.Modifier.PARAMS))
++ break;
++
++ if (!TypeManager.IsEqual (parameters.Types [j], cmp_attrs.Types [j]))
++ break;
++ }
++
++ if (j < cmp_attrs.Count)
++ continue;
++
++ //
++ // check generic arguments for methods
++ //
++ if (mi != null) {
++ Type [] cmpGenArgs = TypeManager.GetGenericArguments (mi);
++ if (generic_method == null && cmpGenArgs != null && cmpGenArgs.Length != 0)
++ continue;
++ if (generic_method != null && cmpGenArgs != null && cmpGenArgs.Length != generic_method.TypeParameters.Length)
++ continue;
++ }
++
++ //
++ // get one of the methods because this has the visibility info.
++ //
++ if (is_property) {
++ mi = pi.GetGetMethod (true);
++ if (mi == null)
++ mi = pi.GetSetMethod (true);
++ }
++
++ //
++ // Check visibility
++ //
++ switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
++ case MethodAttributes.PrivateScope:
++ continue;
++ case MethodAttributes.Private:
++ //
++ // A private method is Ok if we are a nested subtype.
++ // The spec actually is not very clear about this, see bug 52458.
++ //
++ if (!invocation_type.Equals (entry.Container.Type) &&
++ !TypeManager.IsNestedChildOf (invocation_type, entry.Container.Type))
++ continue;
++ break;
++ case MethodAttributes.FamANDAssem:
++ case MethodAttributes.Assembly:
++ //
++ // Check for assembly methods
++ //
++ if (!TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly))
++ continue;
++ break;
++ }
++ return entry.Member;
++ }
++
++ return null;
++ }
++
++ /// <summary>
++ /// The method is looking for conflict with inherited symbols (errors CS0108, CS0109).
++ /// We handle two cases. The first is for types without parameters (events, field, properties).
++ /// The second are methods, indexers and this is why ignore_complex_types is here.
++ /// The latest param is temporary hack. See DoDefineMembers method for more info.
++ /// </summary>
++ public MemberInfo FindMemberWithSameName (string name, bool ignore_complex_types, MemberInfo ignore_member)
++ {
++ List<CacheEntry> applicable = null;
++
++ if (method_hash != null)
++ method_hash.TryGetValue (name, out applicable);
++
++ if (applicable != null) {
++ for (int i = applicable.Count - 1; i >= 0; i--) {
++ CacheEntry entry = (CacheEntry) applicable [i];
++ if ((entry.EntryType & EntryType.Public) != 0)
++ return entry.Member;
++ }
++ }
++
++ if (member_hash == null)
++ return null;
++
++ if (member_hash.TryGetValue (name, out applicable)) {
++ for (int i = applicable.Count - 1; i >= 0; i--) {
++ CacheEntry entry = (CacheEntry) applicable [i];
++ if ((entry.EntryType & EntryType.Public) != 0 & entry.Member != ignore_member) {
++ if (ignore_complex_types) {
++ if ((entry.EntryType & EntryType.Method) != 0)
++ continue;
++
++ // Does exist easier way how to detect indexer ?
++ if ((entry.EntryType & EntryType.Property) != 0) {
++ AParametersCollection arg_types = TypeManager.GetParameterData ((PropertyInfo)entry.Member);
++ if (arg_types.Count > 0)
++ continue;
++ }
++ }
++ return entry.Member;
++ }
++ }
++ }
++ return null;
++ }
++
++
++ /// <summary>
++ /// Builds low-case table for CLS Compliance test
++ /// </summary>
++ public Dictionary<string, object> GetPublicMembers ()
++ {
++ if (locase_table != null)
++ return locase_table;
++
++ locase_table = new Dictionary<string, object> ();
++ foreach (var entry in member_hash) {
++ var members = entry.Value;
++ for (int ii = 0; ii < members.Count; ++ii) {
++ CacheEntry member_entry = members [ii];
++
++ if ((member_entry.EntryType & EntryType.Public) == 0)
++ continue;
++
++ // TODO: Does anyone know easier way how to detect that member is internal ?
++ switch (member_entry.EntryType & EntryType.MaskType) {
++ case EntryType.Constructor:
++ continue;
++
++ case EntryType.Field:
++ if ((((FieldInfo)member_entry.Member).Attributes & (FieldAttributes.Assembly | FieldAttributes.Public)) == FieldAttributes.Assembly)
++ continue;
++ break;
++
++ case EntryType.Method:
++ if ((((MethodInfo)member_entry.Member).Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
++ continue;
++ break;
++
++ case EntryType.Property:
++ PropertyInfo pi = (PropertyInfo)member_entry.Member;
++ if (pi.GetSetMethod () == null && pi.GetGetMethod () == null)
++ continue;
++ break;
++
++ case EntryType.Event:
++ EventInfo ei = (EventInfo)member_entry.Member;
++ MethodInfo mi = ei.GetAddMethod ();
++ if ((mi.Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
++ continue;
++ break;
++ }
++ string lcase = ((string)entry.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture);
++ locase_table [lcase] = member_entry.Member;
++ break;
++ }
++ }
++ return locase_table;
++ }
++
++ public IDictionary<string, List<CacheEntry>> Members {
++ get {
++ return member_hash;
++ }
++ }
++
++ /// <summary>
++ /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
++ /// </summary>
++ ///
++ // TODO: refactor as method is always 'this'
++ public static void VerifyClsParameterConflict (IList<CacheEntry> al, MethodCore method, MemberInfo this_builder, Report Report)
++ {
++ EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public;
++
++ for (int i = 0; i < al.Count; ++i) {
++ var entry = al [i];
++
++ // skip itself
++ if (entry.Member == this_builder)
++ continue;
++
++ if ((entry.EntryType & tested_type) != tested_type)
++ continue;
++
++ MethodBase method_to_compare = (MethodBase)entry.Member;
++ AttributeTester.Result result = AttributeTester.AreOverloadedMethodParamsClsCompliant (
++ method.Parameters, TypeManager.GetParameterData (method_to_compare));
++
++ if (result == AttributeTester.Result.Ok)
++ continue;
++
++ IMethodData md = TypeManager.GetMethod (method_to_compare);
++
++ // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy.
++ // However it is exactly what csc does.
++ if (md != null && !md.IsClsComplianceRequired ())
++ continue;
++
++ Report.SymbolRelatedToPreviousError (entry.Member);
++ switch (result) {
++ case AttributeTester.Result.RefOutArrayError:
++ Report.Warning (3006, 1, method.Location,
++ "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant",
++ method.GetSignatureForError ());
++ continue;
++ case AttributeTester.Result.ArrayArrayError:
++ Report.Warning (3007, 1, method.Location,
++ "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant",
++ method.GetSignatureForError ());
++ continue;
++ }
++
++ throw new NotImplementedException (result.ToString ());
++ }
++ }
++
++ public bool CheckExistingMembersOverloads (MemberCore member, string name, ParametersCompiled parameters, Report Report)
++ {
++ List<CacheEntry> entries;
++ if (!member_hash.TryGetValue (name, out entries))
++ return true;
++
++ int method_param_count = parameters.Count;
++ for (int i = entries.Count - 1; i >= 0; --i) {
++ CacheEntry ce = (CacheEntry) entries [i];
++
++ if (ce.Container != member.Parent.PartialContainer)
++ return true;
++
++ Type [] p_types;
++ AParametersCollection pd;
++ if ((ce.EntryType & EntryType.Property) != 0) {
++ pd = TypeManager.GetParameterData ((PropertyInfo) ce.Member);
++ p_types = pd.Types;
++ } else {
++ MethodBase mb = (MethodBase) ce.Member;
++
++ // TODO: This is more like a hack, because we are adding generic methods
++ // twice with and without arity name
++ if (TypeManager.IsGenericMethod (mb) && !member.MemberName.IsGeneric)
++ continue;
++
++ pd = TypeManager.GetParameterData (mb);
++ p_types = pd.Types;
++ }
++
++ if (p_types.Length != method_param_count)
++ continue;
++
++ if (method_param_count > 0) {
++ int ii = method_param_count - 1;
++ Type type_a, type_b;
++ do {
++ type_a = parameters.Types [ii];
++ type_b = p_types [ii];
++
++ if (TypeManager.IsGenericParameter (type_a) && type_a.DeclaringMethod != null)
++ type_a = typeof (TypeParameter);
++
++ if (TypeManager.IsGenericParameter (type_b) && type_b.DeclaringMethod != null)
++ type_b = typeof (TypeParameter);
++
++ if ((pd.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF) !=
++ (parameters.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF))
++ break;
++
++ } while (TypeManager.IsEqual (type_a, type_b) && ii-- != 0);
++
++ if (ii >= 0)
++ continue;
++
++ //
++ // Operators can differ in return type only
++ //
++ if (member is Operator) {
++ Operator op = TypeManager.GetMethod ((MethodBase) ce.Member) as Operator;
++ if (op != null && op.ReturnType != ((Operator) member).ReturnType)
++ continue;
++ }
++
++ //
++ // Report difference in parameter modifiers only
++ //
++ if (pd != null && member is MethodCore) {
++ ii = method_param_count;
++ while (ii-- != 0 && parameters.FixedParameters [ii].ModFlags == pd.FixedParameters [ii].ModFlags &&
++ parameters.ExtensionMethodType == pd.ExtensionMethodType);
++
++ if (ii >= 0) {
++ MethodCore mc = TypeManager.GetMethod ((MethodBase) ce.Member) as MethodCore;
++ Report.SymbolRelatedToPreviousError (ce.Member);
++ if ((member.ModFlags & Modifiers.PARTIAL) != 0 && (mc.ModFlags & Modifiers.PARTIAL) != 0) {
++ if (parameters.HasParams || pd.HasParams) {
++ Report.Error (758, member.Location,
++ "A partial method declaration and partial method implementation cannot differ on use of `params' modifier");
++ } else {
++ Report.Error (755, member.Location,
++ "A partial method declaration and partial method implementation must be both an extension method or neither");
++ }
++ } else {
++ if (member is Constructor) {
++ Report.Error (851, member.Location,
++ "Overloaded contructor `{0}' cannot differ on use of parameter modifiers only",
++ member.GetSignatureForError ());
++ } else {
++ Report.Error (663, member.Location,
++ "Overloaded method `{0}' cannot differ on use of parameter modifiers only",
++ member.GetSignatureForError ());
++ }
++ }
++ return false;
++ }
++ }
++ }
++
++ if ((ce.EntryType & EntryType.Method) != 0) {
++ Method method_a = member as Method;
++ Method method_b = TypeManager.GetMethod ((MethodBase) ce.Member) as Method;
++ if (method_a != null && method_b != null && (method_a.ModFlags & method_b.ModFlags & Modifiers.PARTIAL) != 0) {
++ const Modifiers partial_modifiers = Modifiers.STATIC | Modifiers.UNSAFE;
++ if (method_a.IsPartialDefinition == method_b.IsPartialImplementation) {
++ if ((method_a.ModFlags & partial_modifiers) == (method_b.ModFlags & partial_modifiers) ||
++ method_a.Parent.IsUnsafe && method_b.Parent.IsUnsafe) {
++ if (method_a.IsPartialImplementation) {
++ method_a.SetPartialDefinition (method_b);
++ entries.RemoveAt (i);
++ } else {
++ method_b.SetPartialDefinition (method_a);
++ method_a.caching_flags |= MemberCore.Flags.PartialDefinitionExists;
++ }
++ continue;
++ }
++
++ if ((method_a.ModFlags & Modifiers.STATIC) != (method_b.ModFlags & Modifiers.STATIC)) {
++ Report.SymbolRelatedToPreviousError (ce.Member);
++ Report.Error (763, member.Location,
++ "A partial method declaration and partial method implementation must be both `static' or neither");
++ }
++
++ Report.SymbolRelatedToPreviousError (ce.Member);
++ Report.Error (764, member.Location,
++ "A partial method declaration and partial method implementation must be both `unsafe' or neither");
++ return false;
++ }
++
++ Report.SymbolRelatedToPreviousError (ce.Member);
++ if (method_a.IsPartialDefinition) {
++ Report.Error (756, member.Location, "A partial method `{0}' declaration is already defined",
++ member.GetSignatureForError ());
++ } else {
++ Report.Error (757, member.Location, "A partial method `{0}' implementation is already defined",
++ member.GetSignatureForError ());
++ }
++
++ return false;
++ }
++
++ Report.SymbolRelatedToPreviousError (ce.Member);
++ IMethodData duplicate_member = TypeManager.GetMethod ((MethodBase) ce.Member);
++ if (member is Operator && duplicate_member is Operator) {
++ Report.Error (557, member.Location, "Duplicate user-defined conversion in type `{0}'",
++ member.Parent.GetSignatureForError ());
++ return false;
++ }
++
++ bool is_reserved_a = member is AbstractPropertyEventMethod || member is Operator;
++ bool is_reserved_b = duplicate_member is AbstractPropertyEventMethod || duplicate_member is Operator;
++
++ if (is_reserved_a || is_reserved_b) {
++ Report.Error (82, member.Location, "A member `{0}' is already reserved",
++ is_reserved_a ?
++ TypeManager.GetFullNameSignature (ce.Member) :
++ member.GetSignatureForError ());
++ return false;
++ }
++ } else {
++ Report.SymbolRelatedToPreviousError (ce.Member);
++ }
++
++ Report.Error (111, member.Location,
++ "A member `{0}' is already defined. Rename this member or use different parameter types",
++ member.GetSignatureForError ());
++ return false;
++ }
++
++ return true;
++ }
++ }
++}
MethodBase metaInfo;
readonly AParametersCollection parameters;
-- public MethodSpec (IMemberDefinition details, MethodBase info, AParametersCollection parameters, Modifiers modifiers)
-- : base (details, info.Name, modifiers)
++ public MethodSpec (MemberKind kind, IMemberDefinition details, MethodBase info, AParametersCollection parameters, Modifiers modifiers)
++ : base (kind, details, info.Name, modifiers)
{
this.MetaInfo = info;
this.parameters = parameters;
// TODO: Does not work on .NET
var par = TypeManager.GetParameterData (mb);
-- return new MethodSpec (definition, mb, par, modifiers);
++ return new MethodSpec (Kind, definition, mb, par, modifiers);
}
public bool IsAbstract {
ModFlags |= Modifiers.DEBUGGER_HIDDEN;
}
++ MemberKind kind;
++ if (this is Operator)
++ kind = MemberKind.Operator;
++ else if (this is Destructor)
++ kind = MemberKind.Destructor;
++ else
++ kind = MemberKind.Method;
++
if (IsPartialDefinition) {
caching_flags &= ~Flags.Excluded_Undetected;
caching_flags |= Flags.Excluded;
Parent.MemberCache.AddMember (mb, this);
TypeManager.AddMethod (mb, this);
-- spec = new MethodSpec (this, mb, Parameters, ModFlags);
++ spec = new MethodSpec (kind, this, mb, Parameters, ModFlags);
}
return true;
MethodBuilder = MethodData.MethodBuilder;
-- spec = new MethodSpec (this, MethodBuilder, Parameters, ModFlags);
++ spec = new MethodSpec (kind, this, MethodBuilder, Parameters, ModFlags);
if (TypeManager.IsGenericMethod (MethodBuilder))
Parent.MemberCache.AddGenericMember (MethodBuilder, this);
ca, CallingConventions,
Parameters.GetEmitTypes ());
-- spec = new MethodSpec (this, ConstructorBuilder, Parameters, ModFlags);
++ spec = new MethodSpec (MemberKind.Constructor, this, ConstructorBuilder, Parameters, ModFlags);
if (Parent.PartialContainer.IsComImport) {
if (!IsDefault ()) {
return null;
}
++ public static OpType? GetType (string metadata_name)
++ {
++ for (int i = 0; i < names.Length; ++i) {
++ if (names[i][1] == metadata_name)
++ return (OpType) i;
++ }
++
++ return null;
++ }
++
public OpType GetMatchingOperator ()
{
switch (OperatorType) {
--- /dev/null
- public PropertySpec (IMemberDefinition definition, PropertyInfo info, Modifiers modifiers)
- : base (definition, info.Name, modifiers)
+//
+// 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;
+
+ 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;
+
+ 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 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 ();
+ }
+
+ /// <summary>
+ /// Tests whether accessors are not in collision with some method (CS0111)
+ /// </summary>
+ 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;
+
+ // FIXME - PropertyAttributes.HasDefault ?
+
+ PropertyBuilder = Parent.TypeBuilder.DefineProperty (
+ GetFullName (MemberName), PropertyAttributes.None, MemberType, null);
+
+ if (!Get.IsDummy) {
+ PropertyBuilder.SetGetMethod (GetBuilder);
+ Parent.MemberCache.AddMember (GetBuilder, Get);
+ }
+
+ if (!Set.IsDummy) {
+ PropertyBuilder.SetSetMethod (SetBuilder);
+ Parent.MemberCache.AddMember (SetBuilder, Set);
+ }
+
+ TypeManager.RegisterProperty (PropertyBuilder, this);
+ Parent.MemberCache.AddMember (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;
+ }
+ }
+
+ /// </summary>
+ /// 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
+ /// </summary>
+ 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 ();
+ }
+ }
+ }
+
+ /// <summary>
+ /// For case when event is declared like property (with add and remove accessors).
+ /// </summary>
+ 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;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Event is declared like field.
+ /// </summary>
+ 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 ();
+
+ TypeManager.RegisterEventField (EventBuilder, this);
+
+ 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 ();
+ }
+
+ 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);
+ 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);
+
+ Parent.MemberCache.AddMember (EventBuilder, this);
+ Parent.MemberCache.AddMember (AddBuilder, Add);
+ Parent.MemberCache.AddMember (RemoveBuilder, Remove);
+
+ 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 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;
+
+ //
+ // Now name the parameters
+ //
+ PropertyBuilder = Parent.TypeBuilder.DefineProperty (
+ GetFullName (MemberName), PropertyAttributes.None, MemberType, parameters.GetEmitTypes ());
+
+ if (!Get.IsDummy) {
+ PropertyBuilder.SetGetMethod (GetBuilder);
+ Parent.MemberCache.AddMember (GetBuilder, Get);
+ }
+
+ if (!Set.IsDummy) {
+ PropertyBuilder.SetSetMethod (SetBuilder);
+ Parent.MemberCache.AddMember (SetBuilder, Set);
+ }
+
+ TypeManager.RegisterIndexer (PropertyBuilder, parameters);
+ Parent.MemberCache.AddMember (PropertyBuilder, this);
+ 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;
+ }
+ }
+}
linq.cs
literal.cs
location.cs
++membercache.cs
method.cs
modifiers.cs
namespace.cs
statement.cs
support.cs
typemanager.cs
++typespec.cs
symbolwriter.cs
../class/Mono.CompilerServices.SymbolWriter/MonoSymbolFile.cs
../class/Mono.CompilerServices.SymbolWriter/MonoSymbolTable.cs
--- /dev/null
--- /dev/null
++//
++// typespec.cs: Type specification
++//
++// Authors: Marek Safar (marek.safar@gmail.com)
++//
++// Dual licensed under the terms of the MIT X11 or GNU GPL
++//
++// Copyright 2010 Novell, Inc
++//
++
++using System;
++using System.Collections.Generic;
++
++namespace Mono.CSharp
++{
++ public class TypeSpec : MemberSpec
++ {
++ Type info;
++ protected MemberCache cache;
++
++ public TypeSpec (MemberKind kind, ITypeDefinition definition, Type info, string name, Modifiers modifiers)
++ : base (kind, definition, name, modifiers)
++ {
++ this.info = info;
++ }
++
++ public TypeSpec BaseType { get; set; }
++
++ public override Type DeclaringType {
++ get { return info.DeclaringType; }
++ }
++
++ public Type MetaInfo {
++ get { return info; }
++ }
++
++ public MemberCache MemberCache {
++ get {
++ if (cache == null) {
++// cache = new MemberCache (BaseType);
++
++// ((ITypeDefinition) definition).LoadMembers (cache);
++ }
++
++ return cache;
++ }
++ }
++ }
++
++ public interface ITypeDefinition : IMemberDefinition
++ {
++ void LoadMembers (MemberCache cache);
++ }
++/*
++ class InternalType : TypeSpec
++ {
++ public static readonly TypeSpec AnonymousMethod = new InternalType ("anonymous method");
++ public static readonly TypeSpec Arglist = new InternalType ("__arglist");
++// public static readonly TypeSpec Dynamic = new DynamicType ();
++ public static readonly TypeSpec MethodGroup = new InternalType ("method group");
++
++ protected InternalType (string name)
++ : base (null, null, name, Modifiers.PUBLIC)
++ {
++// cache = MemberCache.Empty;
++ }
++ }
++*/
++}