//
using System;
+using System.Text;
using System.Collections;
using System.Globalization;
using System.Reflection.Emit;
public class MemberName {
public readonly string Name;
+ public readonly TypeArguments TypeArguments;
+
public readonly MemberName Left;
public readonly Location Location;
this.Left = left;
}
+ private MemberName (MemberName left, string name, bool is_double_colon,
+ TypeArguments args, Location loc)
+ : this (left, name, is_double_colon, loc)
+ {
+ this.TypeArguments = args;
+ }
+
public MemberName (string name)
: this (name, Location.Null)
{ }
: this (null, name, false, loc)
{ }
+ public MemberName (string name, TypeArguments args, Location loc)
+ : this (null, name, false, args, loc)
+ { }
+
public MemberName (MemberName left, string name)
: this (left, name, left != null ? left.Location : Location.Null)
{ }
: this (left, name, false, loc)
{ }
+ public MemberName (MemberName left, string name, TypeArguments args, Location loc)
+ : this (left, name, false, args, loc)
+ { }
+
public MemberName (string alias, string name, Location loc)
: this (new MemberName (alias, loc), name, true, loc)
{ }
{ }
public MemberName (MemberName left, MemberName right, Location loc)
- : this (null, right.Name, false, loc)
+ : this (null, right.Name, false, right.TypeArguments, loc)
{
if (right.is_double_colon)
throw new InternalErrorException ("Cannot append double_colon member name");
public bool IsGeneric {
get {
- return false;
+ if (TypeArguments != null)
+ return true;
+ else if (Left != null)
+ return Left.IsGeneric;
+ else
+ return false;
}
}
{
string connect = is_double_colon ? "::" : ".";
if (Left != null)
- return Left.GetTypeName () + connect + Name;
+ return Left.GetTypeName () + connect + MakeName (Name, TypeArguments);
else
- return Name;
+ return MakeName (Name, TypeArguments);
}
public Expression GetTypeExpression ()
{
- if (Left == null)
- return new SimpleName (Name, Location);
+#if GMCS_SOURCE
+ if (IsUnbound) {
+ if (!CheckUnbound (Location))
+ return null;
+
+ return new UnboundTypeExpression (this, Location);
+ }
+#endif
+
+ if (Left == null) {
+ if (TypeArguments != null)
+ return new SimpleName (Basename, TypeArguments, Location);
+ else
+ return new SimpleName (Name, Location);
+ }
+
if (is_double_colon) {
if (Left.Left != null)
throw new InternalErrorException ("The left side of a :: should be an identifier");
}
Expression lexpr = Left.GetTypeExpression ();
- return new MemberAccess (lexpr, Name);
+ return new MemberAccess (lexpr, Name, TypeArguments, Location);
}
public MemberName Clone ()
{
MemberName left_clone = Left == null ? null : Left.Clone ();
- return new MemberName (left_clone, Name, is_double_colon, Location);
+ return new MemberName (left_clone, Name, is_double_colon, TypeArguments, Location);
}
public string Basename {
- get { return Name; }
+ get {
+ if (TypeArguments != null)
+ return MakeName (Name, TypeArguments);
+ else
+ return Name;
+ }
+ }
+
+ public string FullName {
+ get {
+ if (TypeArguments != null)
+ return Name + "<" + TypeArguments + ">";
+ else
+ return Name;
+ }
+ }
+
+ public string MethodName {
+ get {
+ string connect = is_double_colon ? "::" : ".";
+ if (Left != null)
+ return Left.FullName + connect + Name;
+ else
+ return Name;
+ }
}
public override string ToString ()
{
string connect = is_double_colon ? "::" : ".";
if (Left != null)
- return Left + connect + Name;
+ return Left.FullName + connect + FullName;
else
- return Name;
+ return FullName;
}
public override bool Equals (object other)
return false;
if (is_double_colon != other.is_double_colon)
return false;
-#if NET_2_0
- if (TypeArguments == null)
- return other.TypeArguments == null;
- if (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count)
+ if ((TypeArguments != null) &&
+ (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count))
return false;
-#endif
+
+ if ((TypeArguments == null) && (other.TypeArguments != null))
+ return false;
+
if (Left == null)
return other.Left == null;
hash ^= n.Name.GetHashCode ();
if (is_double_colon)
hash ^= 0xbadc01d;
-#if NET_2_0
+
if (TypeArguments != null)
hash ^= TypeArguments.Count << 5;
-#endif
return hash & 0x7FFFFFFF;
}
+
+ public int CountTypeArguments {
+ get {
+ if (TypeArguments == null)
+ return 0;
+ else
+ return TypeArguments.Count;
+ }
+ }
+
+ public static string MakeName (string name, TypeArguments args)
+ {
+ if (args == null)
+ return name;
+ else
+ return name + "`" + args.Count;
+ }
+
+ public static string MakeName (string name, int count)
+ {
+ return name + "`" + count;
+ }
+
+ protected bool IsUnbound {
+ get {
+ if ((Left != null) && Left.IsUnbound)
+ return true;
+ else if (TypeArguments == null)
+ return false;
+ else
+ return TypeArguments.IsUnbound;
+ }
+ }
+
+ protected bool CheckUnbound (Location loc)
+ {
+ if ((Left != null) && !Left.CheckUnbound (loc))
+ return false;
+ if ((TypeArguments != null) && !TypeArguments.IsUnbound) {
+ Report.Error (1031, loc, "Type expected");
+ return false;
+ }
+
+ return true;
+ }
}
/// <summary>
public string Name {
get {
if (cached_name == null)
- cached_name = MemberName.GetName (false);
+ cached_name = MemberName.GetName (!(this is GenericMethod) && !(this is Method));
return cached_name;
}
}
/// <summary>
/// Modifier flags that the user specified in the source code
/// </summary>
- public int ModFlags;
+ private int mod_flags;
+ public int ModFlags {
+ set {
+ mod_flags = value;
+ if ((value & Modifiers.COMPILER_GENERATED) != 0)
+ caching_flags = Flags.IsUsed | Flags.IsAssigned;
+ }
+ get {
+ return mod_flags;
+ }
+ }
public readonly DeclSpace Parent;
return false;
}
- if (!CodeGen.Assembly.IsClsCompliant) {
- if (HasClsCompliantAttribute) {
+ if (HasClsCompliantAttribute) {
+ if (CodeGen.Assembly.ClsCompliantAttribute == null && !CodeGen.Assembly.IsClsCompliant) {
Report.Error (3014, Location,
"`{0}' cannot be marked as CLS-compliant because the assembly is not marked as CLS-compliant",
GetSignatureForError ());
+ return false;
+ }
+
+ if (!Parent.IsClsComplianceRequired ()) {
+ Report.Warning (3018, 1, Location, "`{0}' cannot be marked as CLS-compliant because it is a member of non CLS-compliant type `{1}'",
+ GetSignatureForError (), Parent.GetSignatureForError ());
+ return false;
}
- return false;
}
if (member_name.Name [0] == '_') {
/// spaces.
/// </remarks>
public abstract class DeclSpace : MemberCore {
-
/// <summary>
/// This points to the actual definition that is being
/// created with System.Reflection.Emit
/// </summary>
public TypeBuilder TypeBuilder;
+ /// <summary>
+ /// If we are a generic type, this is the type we are
+ /// currently defining. We need to lookup members on this
+ /// instead of the TypeBuilder.
+ /// </summary>
+ public Type CurrentType;
+
//
// This is the namespace in which this typecontainer
// was declared. We use this to resolve names.
private Hashtable Cache = new Hashtable ();
- public string Basename;
+ public readonly string Basename;
protected Hashtable defined_names;
public TypeContainer PartialContainer;
+ readonly bool is_generic;
+ readonly int count_type_params;
+ readonly int count_current_type_params;
+
//
// Whether we are Generic
//
public bool IsGeneric {
- get { return false; }
+ get {
+ if (is_generic)
+ return true;
+ else if (Parent != null)
+ return Parent.IsGeneric;
+ else
+ return false;
+ }
}
static string[] attribute_targets = new string [] { "type" };
: base (parent, name, attrs)
{
NamespaceEntry = ns;
- Basename = name.Name;
+ Basename = name.Basename;
defined_names = new Hashtable ();
PartialContainer = null;
+ if (name.TypeArguments != null) {
+ is_generic = true;
+ count_type_params = count_current_type_params = name.TypeArguments.Count;
+ }
+ if (parent != null)
+ count_type_params += parent.count_type_params;
}
public override DeclSpace GenericDeclContainer {
Report.Error (101, symbol.Location,
"The namespace `{0}' already contains a definition for `{1}'",
((DeclSpace)symbol).NamespaceEntry.GetSignatureForError (), symbol.MemberName.Name);
+ } else if (symbol is TypeParameter) {
+ Report.Error (692, symbol.Location,
+ "Duplicate type parameter `{0}'", name);
} else {
Report.Error (102, symbol.Location,
"The type `{0}' already contains a definition for `{1}'",
{
return (MemberCore)defined_names [name];
}
+
+ public bool IsStaticClass {
+ get { return (ModFlags & Modifiers.STATIC) != 0; }
+ }
//
// root_types contains all the types. All TopLevel types
/// Should be overriten by the appropriate declaration space
/// </remarks>
public abstract TypeBuilder DefineType ();
-
+
/// <summary>
/// Define all members, but don't apply any attributes or do anything which may
/// access not-yet-defined classes. This method also creates the MemberCache.
public override string GetSignatureForError ()
{
+ if (IsGeneric) {
+ return SimpleName.RemoveGenericArity (Name) + TypeParameter.GetSignatureForError (CurrentTypeParameters);
+ }
// Parent.GetSignatureForError
return Name;
}
public bool CheckAccessLevel (Type check_type)
{
- if (check_type == TypeBuilder)
+ TypeBuilder tb;
+ if (this is GenericMethod)
+ tb = Parent.TypeBuilder;
+ else
+ tb = TypeBuilder;
+
+ check_type = TypeManager.DropGenericTypeArguments (check_type);
+ if (check_type == tb)
return true;
- TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
+ if (TypeBuilder == null)
+ // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases().
+ // However, this is invoked again later -- so safe to return true.
+ // May also be null when resolving top-level attributes.
+ return true;
//
// Broken Microsoft runtime, return public for arrays, no matter what
if (check_type.IsArray || check_type.IsPointer)
return CheckAccessLevel (TypeManager.GetElementType (check_type));
- if (TypeBuilder == null)
- // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases().
- // However, this is invoked again later -- so safe to return true.
- // May also be null when resolving top-level attributes.
- return true;
+ if (TypeManager.IsGenericParameter(check_type))
+ return true; // FIXME
+
+ TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
switch (check_attr){
case TypeAttributes.Public:
return true;
case TypeAttributes.NotPublic:
+
+ if (TypeBuilder == null)
+ // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases().
+ // However, this is invoked again later -- so safe to return true.
+ // May also be null when resolving top-level attributes.
+ return true;
//
// This test should probably use the declaringtype.
//
- return check_type.Assembly == TypeBuilder.Assembly;
+ return check_type.Assembly == TypeBuilder.Assembly ||
+ TypeManager.IsFriendAssembly (check_type.Assembly);
case TypeAttributes.NestedPublic:
return true;
case TypeAttributes.NestedPrivate:
- return NestedAccessible (check_type);
+ return NestedAccessible (tb, check_type);
case TypeAttributes.NestedFamily:
- return FamilyAccessible (check_type);
+ //
+ // Only accessible to methods in current type or any subtypes
+ //
+ return FamilyAccessible (tb, check_type);
case TypeAttributes.NestedFamANDAssem:
- return (check_type.Assembly == TypeBuilder.Assembly) &&
- FamilyAccessible (check_type);
+ return ((check_type.Assembly == tb.Assembly) ||
+ TypeManager.IsFriendAssembly (check_type.Assembly)) &&
+ FamilyAccessible (tb, check_type);
case TypeAttributes.NestedFamORAssem:
- return (check_type.Assembly == TypeBuilder.Assembly) ||
- FamilyAccessible (check_type);
+ return (check_type.Assembly == tb.Assembly) ||
+ FamilyAccessible (tb, check_type) ||
+ TypeManager.IsFriendAssembly (check_type.Assembly);
case TypeAttributes.NestedAssembly:
- return check_type.Assembly == TypeBuilder.Assembly;
+ return check_type.Assembly == tb.Assembly ||
+ TypeManager.IsFriendAssembly (check_type.Assembly);
}
Console.WriteLine ("HERE: " + check_attr);
}
- protected bool NestedAccessible (Type check_type)
+ protected bool NestedAccessible (Type tb, Type check_type)
{
Type declaring = check_type.DeclaringType;
return TypeBuilder == declaring ||
TypeManager.IsNestedChildOf (TypeBuilder, declaring);
}
- protected bool FamilyAccessible (Type check_type)
+ protected bool FamilyAccessible (Type tb, Type check_type)
{
Type declaring = check_type.DeclaringType;
return TypeManager.IsNestedFamilyAccessible (TypeBuilder, declaring);
} else if ((flags & Modifiers.PROTECTED) != 0)
return AccessLevel.Protected;
-
else if ((flags & Modifiers.PRIVATE) != 0)
return AccessLevel.Private;
-
else
return AccessLevel.Public;
}
return AccessLevel.Internal;
// By now, it must be nested
- AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType);
+ AccessLevel parent_level = TypeEffectiveAccessLevel (t.DeclaringType);
if (t.IsNestedPublic)
- return parentLevel;
+ return parent_level;
if (t.IsNestedAssembly)
- return parentLevel & AccessLevel.Internal;
+ return parent_level & AccessLevel.Internal;
if (t.IsNestedFamily)
- return parentLevel & AccessLevel.Protected;
+ return parent_level & AccessLevel.Protected;
if (t.IsNestedFamORAssem)
- return parentLevel & AccessLevel.ProtectedOrInternal;
+ return parent_level & AccessLevel.ProtectedOrInternal;
if (t.IsNestedFamANDAssem)
throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways");
while (p.IsArray || p.IsPointer || p.IsByRef)
p = TypeManager.GetElementType (p);
-
+
+#if GMCS_SOURCE
+ if (p.IsGenericParameter)
+ return true;
+
+ if (TypeManager.IsGenericType (p)) {
+ foreach (Type t in p.GetGenericArguments ()) {
+ if (!AsAccessible (t, flags))
+ return false;
+ }
+ }
+#endif
AccessLevel pAccess = TypeEffectiveAccessLevel (p);
AccessLevel mAccess = this.EffectiveAccessLevel &
GetAccessLevelFromModifiers (flags);
for (Type current_type = TypeBuilder;
current_type != null && current_type != TypeManager.object_type;
current_type = current_type.BaseType) {
- if (current_type is TypeBuilder) {
- TypeContainer tc = current_type == TypeBuilder
- ? PartialContainer
- : TypeManager.LookupTypeContainer (current_type);
+
+ Type ct = TypeManager.DropGenericTypeArguments (current_type);
+ if (ct is TypeBuilder) {
+ TypeContainer tc = ct == TypeBuilder
+ ? PartialContainer : TypeManager.LookupTypeContainer (ct);
if (tc != null)
t = tc.FindNestedType (name);
} else {
- t = TypeManager.GetNestedType (current_type, name);
+ t = TypeManager.GetNestedType (ct, name);
}
- if (t != null && CheckAccessLevel (t))
+ if ((t == null) || !CheckAccessLevel (t))
+ continue;
+
+#if GMCS_SOURCE
+ if (!TypeManager.IsGenericType (current_type))
return t;
+
+ Type[] args = TypeManager.GetTypeArguments (current_type);
+ Type[] targs = TypeManager.GetTypeArguments (t);
+ for (int i = 0; i < args.Length; i++)
+ targs [i] = args [i];
+
+ t = t.MakeGenericType (targs);
+#endif
+
+ return t;
}
return null;
}
+ public virtual ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name)
+ {
+ return null;
+ }
+
//
// Public function used to locate types.
//
//
// Returns: Type or null if they type can not be found.
//
- public FullNamedExpression LookupType (string name, Location loc, bool ignore_cs0104)
+ public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
{
if (Cache.Contains (name))
return (FullNamedExpression) Cache [name];
if (t != null)
e = new TypeExpression (t, Location.Null);
else if (Parent != null)
- e = Parent.LookupType (name, loc, ignore_cs0104);
+ e = Parent.LookupNamespaceOrType (name, loc, ignore_cs0104);
else
e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104);
TypeBuilder.SetCustomAttribute (cb);
}
+ //
+ // Extensions for generics
+ //
+ TypeParameter[] type_params;
+ TypeParameter[] type_param_list;
+
+ protected string GetInstantiationName ()
+ {
+ StringBuilder sb = new StringBuilder (Name);
+ sb.Append ("<");
+ for (int i = 0; i < type_param_list.Length; i++) {
+ if (i > 0)
+ sb.Append (",");
+ sb.Append (type_param_list [i].Name);
+ }
+ sb.Append (">");
+ return sb.ToString ();
+ }
+
+ bool check_type_parameter (ArrayList list, int start, string name)
+ {
+ for (int i = 0; i < start; i++) {
+ TypeParameter param = (TypeParameter) list [i];
+
+ if (param.Name != name)
+ continue;
+
+ Report.SymbolRelatedToPreviousError (Parent);
+ // TODO: Location is wrong (parent instead of child)
+ Report.Warning (693, 3, Location,
+ "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
+ name, Parent.GetSignatureForError ());
+
+ return false;
+ }
+
+ return true;
+ }
+
+ TypeParameter[] initialize_type_params ()
+ {
+ if (type_param_list != null)
+ return type_param_list;
+
+ DeclSpace the_parent = Parent;
+ if (this is GenericMethod)
+ the_parent = null;
+
+ int start = 0;
+ ArrayList list = new ArrayList ();
+ if (the_parent != null && the_parent.IsGeneric) {
+ // FIXME: move generics info out of DeclSpace
+ TypeParameter[] parent_params = the_parent.PartialContainer.TypeParameters;
+ start = parent_params.Length;
+ list.AddRange (parent_params);
+ }
+
+ int count = type_params != null ? type_params.Length : 0;
+ for (int i = 0; i < count; i++) {
+ TypeParameter param = type_params [i];
+ check_type_parameter (list, start, param.Name);
+ list.Add (param);
+ }
+
+ type_param_list = new TypeParameter [list.Count];
+ list.CopyTo (type_param_list, 0);
+ return type_param_list;
+ }
+
+ public virtual void SetParameterInfo (ArrayList constraints_list)
+ {
+ if (!is_generic) {
+ if (constraints_list != null) {
+ Report.Error (
+ 80, Location, "Constraints are not allowed " +
+ "on non-generic declarations");
+ }
+
+ return;
+ }
+
+ TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
+ type_params = new TypeParameter [names.Length];
+
+ //
+ // Register all the names
+ //
+ for (int i = 0; i < type_params.Length; i++) {
+ TypeParameterName name = names [i];
+
+ Constraints constraints = null;
+ if (constraints_list != null) {
+ int total = constraints_list.Count;
+ for (int ii = 0; ii < total; ++ii) {
+ Constraints constraints_at = (Constraints)constraints_list[ii];
+ // TODO: it is used by iterators only
+ if (constraints_at == null) {
+ constraints_list.RemoveAt (ii);
+ --total;
+ continue;
+ }
+ if (constraints_at.TypeParameter == name.Name) {
+ constraints = constraints_at;
+ constraints_list.RemoveAt(ii);
+ break;
+ }
+ }
+ }
+
+ type_params [i] = new TypeParameter (
+ Parent, this, name.Name, constraints, name.OptAttributes,
+ Location);
+
+ AddToContainer (type_params [i], name.Name);
+ }
+
+ if (constraints_list != null && constraints_list.Count > 0) {
+ foreach (Constraints constraint in constraints_list) {
+ Report.Error(699, constraint.Location, "`{0}': A constraint references nonexistent type parameter `{1}'",
+ GetSignatureForError (), constraint.TypeParameter);
+ }
+ }
+ }
+
+ public TypeParameter[] TypeParameters {
+ get {
+ if (!IsGeneric)
+ throw new InvalidOperationException ();
+ if ((PartialContainer != null) && (PartialContainer != this))
+ return PartialContainer.TypeParameters;
+ if (type_param_list == null)
+ initialize_type_params ();
+
+ return type_param_list;
+ }
+ }
+
+ public TypeParameter[] CurrentTypeParameters {
+ get {
+ if (!IsGeneric)
+ throw new InvalidOperationException ();
+ if ((PartialContainer != null) && (PartialContainer != this))
+ return PartialContainer.CurrentTypeParameters;
+ if (type_params != null)
+ return type_params;
+ else
+ return new TypeParameter [0];
+ }
+ }
+
+ public int CountTypeParameters {
+ get {
+ return count_type_params;
+ }
+ }
+
+ public int CountCurrentTypeParameters {
+ get {
+ return count_current_type_params;
+ }
+ }
+
+ public TypeParameterExpr LookupGeneric (string name, Location loc)
+ {
+ if (!IsGeneric)
+ return null;
+
+ TypeParameter [] current_params;
+ if (this is TypeContainer)
+ current_params = PartialContainer.CurrentTypeParameters;
+ else
+ current_params = CurrentTypeParameters;
+
+ foreach (TypeParameter type_param in current_params) {
+ if (type_param.Name == name)
+ return new TypeParameterExpr (type_param, loc);
+ }
+
+ if (Parent != null)
+ return Parent.LookupGeneric (name, loc);
+
+ return null;
+ }
+
+ // Used for error reporting only
+ public virtual Type LookupAnyGeneric (string typeName)
+ {
+ return NamespaceEntry.NS.LookForAnyGenericType (typeName);
+ }
+
public override string[] ValidAttributeTargets {
get { return attribute_targets; }
}
return false;
}
+ if (type_params != null) {
+ foreach (TypeParameter tp in type_params) {
+ if (tp.Constraints == null)
+ continue;
+
+ tp.Constraints.VerifyClsCompliance ();
+ }
+ }
+
IDictionary cache = TypeManager.AllClsTopLevelTypes;
+ if (cache == null)
+ return true;
+
string lcase = Name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
if (!cache.Contains (lcase)) {
cache.Add (lcase, this);
else {
Report.SymbolRelatedToPreviousError ((DeclSpace)val);
}
+#if GMCS_SOURCE
+ Report.Warning (3005, 1, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
+#else
Report.Error (3005, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
+#endif
return true;
}
}
// 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 Hashtable ();
AddMethods (type);
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 Hashtable ();
+
+ 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>
AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
}
+ void AddMember (MemberTypes mt, BindingFlags bf, IMemberContainer container,
+ string name, MemberInfo member)
+ {
+ // We use a name-based hash table of ArrayList's.
+ ArrayList list = (ArrayList) member_hash [name];
+ if (list == null) {
+ list = new ArrayList ();
+ 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
foreach (MemberInfo member in members) {
string name = member.Name;
- // We use a name-based hash table of ArrayList's.
- ArrayList list = (ArrayList) member_hash [name];
- if (list == null) {
- list = new ArrayList ();
- member_hash.Add (name, list);
- }
+ AddMember (mt, bf, container, name, member);
- // 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));
+ if (member is MethodInfo) {
+ string gname = TypeManager.GetMethodName ((MethodInfo) member);
+ if (gname != name)
+ AddMember (mt, bf, container, gname, member);
+ }
}
}
Property = 0x200,
NestedType = 0x400,
+ NotExtensionMethod = 0x800,
+
MaskType = Constructor|Event|Field|Method|Property|NestedType
}
protected class CacheEntry {
public readonly IMemberContainer Container;
- public readonly EntryType EntryType;
+ public EntryType EntryType;
public readonly MemberInfo Member;
public CacheEntry (IMemberContainer container, MemberInfo member,
return null;
}
+
+ public MemberInfo FindBaseEvent (Type invocation_type, string name)
+ {
+ ArrayList applicable = (ArrayList) member_hash [name];
+ if (applicable == null)
+ return null;
+
+ //
+ // Walk the chain of events, starting from the top.
+ //
+ for (int i = applicable.Count - 1; i >= 0; i--)
+ {
+ CacheEntry entry = (CacheEntry) 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 ArrayList FindExtensionMethods (Type extensionType, string name, bool publicOnly)
+ {
+ ArrayList entries;
+ if (method_hash != null)
+ entries = (ArrayList)method_hash [name];
+ else
+ entries = (ArrayList)member_hash [name];
+
+ if (entries == null)
+ return null;
+
+ EntryType entry_type = EntryType.Static | EntryType.Method | EntryType.NotExtensionMethod;
+ if (publicOnly) {
+ entry_type |= EntryType.Public;
+ }
+ EntryType found_entry_type = entry_type & ~EntryType.NotExtensionMethod;
+
+ ArrayList candidates = null;
+ foreach (CacheEntry entry in entries) {
+ if ((entry.EntryType & entry_type) == found_entry_type) {
+ MethodBase mb = (MethodBase)entry.Member;
+
+ IMethodData md = TypeManager.GetMethod (mb);
+ ParameterData pd = md == null ?
+ TypeManager.GetParameterData (mb) : md.ParameterInfo;
+
+ Type ex_type = pd.ExtensionMethodType;
+ if (ex_type == null) {
+ entry.EntryType |= EntryType.NotExtensionMethod;
+ continue;
+ }
+
+ //if (implicit conversion between ex_type and extensionType exist) {
+ if (candidates == null)
+ candidates = new ArrayList (2);
+ candidates.Add (mb);
+ //}
+ }
+ }
+
+ return candidates;
+ }
//
- // This finds the method or property for us to override. invocationType is the type where
+ // 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
- // paramTypes is the parameters, if any to the method or property
+ // 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 invocationType, string name, Type [] paramTypes, bool is_property)
+ public MemberInfo FindMemberToOverride (Type invocation_type, string name, Type [] param_types, GenericMethod generic_method, bool is_property)
{
ArrayList applicable;
if (method_hash != null && !is_property)
PropertyInfo pi = null;
MethodInfo mi = null;
FieldInfo fi = null;
- Type [] cmpAttrs = null;
+ Type [] cmp_attrs = null;
if (is_property) {
if ((entry.EntryType & EntryType.Field) != 0) {
// TODO: For this case we ignore member type
//fb = TypeManager.GetField (fi);
- //cmpAttrs = new Type[] { fb.MemberType };
+ //cmp_attrs = new Type[] { fb.MemberType };
} else {
pi = (PropertyInfo) entry.Member;
- cmpAttrs = TypeManager.GetArgumentTypes (pi);
+ cmp_attrs = TypeManager.GetArgumentTypes (pi);
}
} else {
mi = (MethodInfo) entry.Member;
- cmpAttrs = TypeManager.GetParameterData (mi).Types;
+ cmp_attrs = TypeManager.GetParameterData (mi).Types;
}
if (fi != null) {
// TODO: Almost duplicate !
// Check visibility
switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
- 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 (invocationType != entry.Container.Type &
- TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
- continue;
-
- break;
- case FieldAttributes.FamANDAssem:
- case FieldAttributes.Assembly:
- //
- // Check for assembly methods
- //
- if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
- continue;
- break;
+ 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 (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
+ continue;
+ break;
}
return entry.Member;
}
//
// Check the arguments
//
- if (cmpAttrs.Length != paramTypes.Length)
+ if (cmp_attrs.Length != param_types.Length)
continue;
- for (int j = cmpAttrs.Length - 1; j >= 0; j --)
- if (paramTypes [j] != cmpAttrs [j])
- goto next;
-
+ int j;
+ for (j = 0; j < cmp_attrs.Length; ++j)
+ if (!TypeManager.IsEqual (param_types [j], cmp_attrs [j]))
+ break;
+ if (j < cmp_attrs.Length)
+ continue;
+
+ //
+ // check generic arguments for methods
+ //
+ if (mi != null) {
+ Type [] cmpGenArgs = TypeManager.GetGenericArguments (mi);
+ if (generic_method == null && cmpGenArgs.Length != 0)
+ continue;
+ if (generic_method != null && cmpGenArgs.Length != generic_method.TypeParameters.Length)
+ continue;
+ }
+
//
// get one of the methods because this has the visibility info.
//
// 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 (invocationType == entry.Container.Type ||
- TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
- return entry.Member;
-
+ 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 (mi.DeclaringType.Assembly == CodeGen.Assembly.Builder)
- return entry.Member;
-
+ if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
+ continue;
break;
- default:
- //
- // A protected method is ok, because we are overriding.
- // public is always ok.
- //
- return entry.Member;
}
- next:
- ;
+ return entry.Member;
}
return null;