X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fdecl.cs;h=f98c5ae909d34127577625f819d5228ea96b7732;hb=398ddf57679d166c65418736cdbd540ed5b9e534;hp=c9456015e523ba8a3a8292874adc81506752cc19;hpb=472580b484aeed2f54a7d206badcbbe215a8ec11;p=mono.git diff --git a/mcs/mcs/decl.cs b/mcs/mcs/decl.cs index c9456015e52..f98c5ae909d 100644 --- a/mcs/mcs/decl.cs +++ b/mcs/mcs/decl.cs @@ -4,21 +4,22 @@ // Author: Miguel de Icaza (miguel@gnu.org) // Marek Safar (marek.safar@seznam.cz) // -// Licensed under the terms of the GNU GPL +// Dual licensed under the terms of the MIT X11 or GNU GPL // -// (C) 2001 Ximian, Inc (http://www.ximian.com) -// (C) 2004 Novell, Inc +// Copyright 2001 Ximian, Inc (http://www.ximian.com) +// Copyright 2004-2008 Novell, Inc // // TODO: Move the method verification stuff from the class.cs and interface.cs here // using System; +using System.Text; using System.Collections; using System.Globalization; using System.Reflection.Emit; using System.Reflection; -#if BOOTSTRAP_WITH_OLDLIB +#if BOOTSTRAP_WITH_OLDLIB || NET_2_1 using XmlElement = System.Object; #else using System.Xml; @@ -50,7 +51,8 @@ namespace Mono.CSharp { TypeArguments args, Location loc) : this (left, name, is_double_colon, loc) { - this.TypeArguments = args; + if (args != null && args.Count > 0) + this.TypeArguments = args; } public MemberName (string name) @@ -77,8 +79,8 @@ namespace Mono.CSharp { : this (left, name, false, args, loc) { } - public MemberName (string alias, string name, Location loc) - : this (new MemberName (alias, loc), name, true, loc) + public MemberName (string alias, string name, TypeArguments args, Location loc) + : this (new MemberName (alias, loc), name, true, args, loc) { } public MemberName (MemberName left, MemberName right) @@ -123,19 +125,24 @@ namespace Mono.CSharp { { 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 () + public ATypeNameExpression GetTypeExpression () { - if (Left == null) + if (Left == null) { + if (TypeArguments != null) + return new SimpleName (Basename, TypeArguments, Location); + 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"); - return new QualifiedAliasMember (Left.Name, Name, Location); + return new QualifiedAliasMember (Left.Name, Name, TypeArguments, Location); } Expression lexpr = Left.GetTypeExpression (); @@ -157,32 +164,29 @@ namespace Mono.CSharp { } } - 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; + return Left.FullyQualifiedName + connect + Name; else return Name; } } - public override string ToString () + // Please use this only for error reporting. For normal uses, just use the Equals and GetHashCode methods that make + // MemberName a proper hash key, and avoid tons of memory allocations + string FullyQualifiedName { + get { return TypeArguments == null ? MethodName : MethodName + "<" + TypeArguments.GetSignatureForError () + ">"; } + } + + public string GetSignatureForError () { + string append = TypeArguments == null ? "" : "<" + TypeArguments.GetSignatureForError () + ">"; + if (Left == null) + return Name + append; string connect = is_double_colon ? "::" : "."; - if (Left != null) - return Left.FullName + connect + FullName; - else - return FullName; + return Left.GetSignatureForError () + connect + Name + append; } public override bool Equals (object other) @@ -228,10 +232,12 @@ namespace Mono.CSharp { public int CountTypeArguments { get { - if (TypeArguments == null) - return 0; - else + if (TypeArguments != null) return TypeArguments.Count; + else if (Left != null) + return Left.CountTypeArguments; + else + return 0; } } @@ -247,29 +253,6 @@ namespace Mono.CSharp { { 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; - } } /// @@ -285,7 +268,7 @@ namespace Mono.CSharp { 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; } } @@ -299,9 +282,19 @@ namespace Mono.CSharp { /// /// Modifier flags that the user specified in the source code /// - 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; + public /*readonly*/ DeclSpace Parent; /// /// Location where this declaration happens @@ -333,10 +326,11 @@ namespace Mono.CSharp { ClsCompliantAttributeTrue = 1 << 7, // Type has CLSCompliant (true) Excluded_Undetected = 1 << 8, // Conditional attribute has not been detected yet Excluded = 1 << 9, // Method is conditional - TestMethodDuplication = 1 << 10, // Test for duplication must be performed + MethodOverloadsExist = 1 << 10, // Test for duplication must be performed IsUsed = 1 << 11, IsAssigned = 1 << 12, // Field is assigned - HasExplicitLayout = 1 << 13 + HasExplicitLayout = 1 << 13, + PartialDefinitionExists = 1 << 14 // Set when corresponding partial method definition exists } /// @@ -358,6 +352,64 @@ namespace Mono.CSharp { cached_name = null; } + protected bool CheckAbstractAndExtern (bool has_block) + { + if (Parent.PartialContainer.Kind == Kind.Interface) + return true; + + if (has_block) { + if ((ModFlags & Modifiers.EXTERN) != 0) { + Report.Error (179, Location, "`{0}' cannot declare a body because it is marked extern", + GetSignatureForError ()); + return false; + } + + if ((ModFlags & Modifiers.ABSTRACT) != 0) { + Report.Error (500, Location, "`{0}' cannot declare a body because it is marked abstract", + GetSignatureForError ()); + return false; + } + } else { + if ((ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN | Modifiers.PARTIAL)) == 0) { + if (RootContext.Version >= LanguageVersion.LINQ && this is Property.PropertyMethod) { + Report.Error (840, Location, "`{0}' must have a body because it is not marked abstract or extern. The property can be automatically implemented when you define both accessors", + GetSignatureForError ()); + } else { + Report.Error (501, Location, "`{0}' must have a body because it is not marked abstract, extern, or partial", + GetSignatureForError ()); + } + return false; + } + } + + return true; + } + + public void CheckProtectedModifier () + { + if ((ModFlags & Modifiers.PROTECTED) == 0) + return; + + if (Parent.PartialContainer.Kind == Kind.Struct) { + Report.Error (666, Location, "`{0}': Structs cannot contain protected members", + GetSignatureForError ()); + return; + } + + if ((Parent.ModFlags & Modifiers.STATIC) != 0) { + Report.Error (1057, Location, "`{0}': Static classes cannot contain protected members", + GetSignatureForError ()); + return; + } + + if (((Parent.ModFlags & Modifiers.SEALED) != 0) && + ((ModFlags & Modifiers.OVERRIDE) == 0) && (Name != "Finalize")) { + Report.Warning (628, 4, Location, "`{0}': new protected member declared in sealed class", + GetSignatureForError ()); + return; + } + } + public abstract bool Define (); public virtual string DocComment { @@ -375,9 +427,9 @@ namespace Mono.CSharp { public virtual string GetSignatureForError () { if (Parent == null || Parent.Parent == null) - return member_name.ToString (); + return member_name.GetSignatureForError (); - return String.Concat (Parent.GetSignatureForError (), '.', member_name.ToString ()); + return Parent.GetSignatureForError () + "." + member_name.GetSignatureForError (); } /// @@ -412,7 +464,7 @@ namespace Mono.CSharp { caching_flags &= ~Flags.Obsolete_Undetected; - if (OptAttributes == null) + if (OptAttributes == null || TypeManager.obsolete_attribute_type == null) return null; Attribute obsolete_attr = OptAttributes.Search ( @@ -444,6 +496,159 @@ namespace Mono.CSharp { AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc); } + // Access level of a type. + const int X = 1; + enum AccessLevel + { // Each column represents `is this scope larger or equal to Blah scope' + // Public Assembly Protected + Protected = (0 << 0) | (0 << 1) | (X << 2), + Public = (X << 0) | (X << 1) | (X << 2), + Private = (0 << 0) | (0 << 1) | (0 << 2), + Internal = (0 << 0) | (X << 1) | (0 << 2), + ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2), + } + + static AccessLevel GetAccessLevelFromModifiers (int flags) + { + if ((flags & Modifiers.INTERNAL) != 0) { + + if ((flags & Modifiers.PROTECTED) != 0) + return AccessLevel.ProtectedOrInternal; + else + return AccessLevel.Internal; + + } else if ((flags & Modifiers.PROTECTED) != 0) + return AccessLevel.Protected; + else if ((flags & Modifiers.PRIVATE) != 0) + return AccessLevel.Private; + else + return AccessLevel.Public; + } + + // + // Returns the access level for type `t' + // + static AccessLevel GetAccessLevelFromType (Type t) + { + if (t.IsPublic) + return AccessLevel.Public; + if (t.IsNestedPrivate) + return AccessLevel.Private; + if (t.IsNotPublic) + return AccessLevel.Internal; + + if (t.IsNestedPublic) + return AccessLevel.Public; + if (t.IsNestedAssembly) + return AccessLevel.Internal; + if (t.IsNestedFamily) + return AccessLevel.Protected; + if (t.IsNestedFamORAssem) + return AccessLevel.ProtectedOrInternal; + if (t.IsNestedFamANDAssem) + throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways"); + + // nested private is taken care of + + throw new Exception ("I give up, what are you?"); + } + + // + // Checks whether the type P is as accessible as this member + // + public bool IsAccessibleAs (Type p) + { + // + // if M is private, its accessibility is the same as this declspace. + // we already know that P is accessible to T before this method, so we + // may return true. + // + if ((mod_flags & Modifiers.PRIVATE) != 0) + return true; + + 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 (!IsAccessibleAs (t)) + return false; + } + } +#endif + + for (Type p_parent = null; p != null; p = p_parent) { + p_parent = p.DeclaringType; + AccessLevel pAccess = GetAccessLevelFromType (p); + if (pAccess == AccessLevel.Public) + continue; + + bool same_access_restrictions = false; + for (MemberCore mc = this; !same_access_restrictions && mc != null && mc.Parent != null; mc = mc.Parent) { + AccessLevel al = GetAccessLevelFromModifiers (mc.ModFlags); + switch (pAccess) { + case AccessLevel.Internal: + if (al == AccessLevel.Private || al == AccessLevel.Internal) + same_access_restrictions = TypeManager.IsThisOrFriendAssembly (p.Assembly); + + break; + + case AccessLevel.Protected: + if (al == AccessLevel.Protected) { + same_access_restrictions = mc.Parent.IsBaseType (p_parent); + break; + } + + if (al == AccessLevel.Private) { + // + // When type is private and any of its parents derives from + // protected type then the type is accessible + // + while (mc.Parent != null) { + if (mc.Parent.IsBaseType (p_parent)) + same_access_restrictions = true; + mc = mc.Parent; + } + } + + break; + + case AccessLevel.ProtectedOrInternal: + if (al == AccessLevel.Protected) + same_access_restrictions = mc.Parent.IsBaseType (p_parent); + else if (al == AccessLevel.Internal) + same_access_restrictions = TypeManager.IsThisOrFriendAssembly (p.Assembly); + else if (al == AccessLevel.ProtectedOrInternal) + same_access_restrictions = mc.Parent.IsBaseType (p_parent) && + TypeManager.IsThisOrFriendAssembly (p.Assembly); + + break; + + case AccessLevel.Private: + // + // Both are private and share same parent + // + if (al == AccessLevel.Private) + same_access_restrictions = TypeManager.IsEqual (mc.Parent.TypeBuilder, p_parent); + + break; + + default: + throw new InternalErrorException (al.ToString ()); + } + } + + if (!same_access_restrictions) + return false; + } + + return true; + } + /// /// Analyze whether CLS-Compliant verification must be execute for this MemberCore. /// @@ -490,7 +695,7 @@ namespace Mono.CSharp { caching_flags &= ~Flags.HasCompliantAttribute_Undetected; - if (OptAttributes != null) { + if (OptAttributes != null && TypeManager.cls_compliant_attribute_type != null) { Attribute cls_attribute = OptAttributes.Search ( TypeManager.cls_compliant_attribute_type); if (cls_attribute != null) { @@ -501,6 +706,10 @@ namespace Mono.CSharp { return value; } } + + // It's null for TypeParameter + if (Parent == null) + return false; if (Parent.GetClsCompliantAttributeValue ()) { caching_flags |= Flags.ClsCompliantAttributeTrue; @@ -514,14 +723,17 @@ namespace Mono.CSharp { /// protected bool HasClsCompliantAttribute { get { + if ((caching_flags & Flags.HasCompliantAttribute_Undetected) != 0) + GetClsCompliantAttributeValue (); + return (caching_flags & Flags.HasClsCompliantAttribute) != 0; } } /// - /// It helps to handle error 102 & 111 detection + /// Returns true when a member supports multiple overloads (methods, indexers, etc) /// - public virtual bool MarkForDuplicationCheck () + public virtual bool EnableOverloadChecks (MemberCore overload) { return false; } @@ -535,7 +747,7 @@ namespace Mono.CSharp { protected virtual bool VerifyClsCompliance () { if (!IsClsComplianceRequired ()) { - if (HasClsCompliantAttribute && RootContext.WarningLevel >= 2) { + if (HasClsCompliantAttribute && Report.WarningLevel >= 2) { if (!IsExposedFromAssembly ()) Report.Warning (3019, 2, Location, "CLS compliance checking will not be performed on `{0}' because it is not visible from outside this assembly", GetSignatureForError ()); if (!CodeGen.Assembly.IsClsCompliant) @@ -544,13 +756,19 @@ namespace Mono.CSharp { 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] == '_') { @@ -585,7 +803,11 @@ namespace Mono.CSharp { // internal virtual void GenerateDocComment (DeclSpace ds) { - DocUtil.GenerateDocComment (this, ds); + try { + DocUtil.GenerateDocComment (this, ds); + } catch (Exception e) { + throw new InternalErrorException (this, e); + } } public override IResolveContext ResolveContext { @@ -632,13 +854,19 @@ namespace Mono.CSharp { /// spaces. /// public abstract class DeclSpace : MemberCore { - /// /// This points to the actual definition that is being /// created with System.Reflection.Emit /// public TypeBuilder TypeBuilder; + /// + /// 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. + /// + public Type CurrentType; + // // This is the namespace in which this typecontainer // was declared. We use this to resolve names. @@ -647,17 +875,27 @@ namespace Mono.CSharp { private Hashtable Cache = new Hashtable (); - public string Basename; + public readonly string Basename; protected Hashtable defined_names; public TypeContainer PartialContainer; + protected readonly bool is_generic; + readonly int count_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" }; @@ -667,9 +905,15 @@ namespace Mono.CSharp { : 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 = name.TypeArguments.Count; + } + if (parent != null) + count_type_params += parent.count_type_params; } public override DeclSpace GenericDeclContainer { @@ -688,7 +932,7 @@ namespace Mono.CSharp { return true; } - if (symbol.MarkForDuplicationCheck () && mc.MarkForDuplicationCheck ()) + if (symbol.EnableOverloadChecks (mc)) return true; Report.SymbolRelatedToPreviousError (mc); @@ -701,6 +945,9 @@ namespace Mono.CSharp { 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}'", @@ -719,6 +966,10 @@ namespace Mono.CSharp { { return (MemberCore)defined_names [name]; } + + public bool IsStaticClass { + get { return (ModFlags & Modifiers.STATIC) != 0; } + } // // root_types contains all the types. All TopLevel types @@ -758,7 +1009,7 @@ namespace Mono.CSharp { /// Should be overriten by the appropriate declaration space /// public abstract TypeBuilder DefineType (); - + /// /// 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. @@ -779,18 +1030,45 @@ namespace Mono.CSharp { type.GetSignatureForError ()); } + public override void Emit () + { +#if GMCS_SOURCE + if (type_params != null) { + int offset = count_type_params - type_params.Length; + for (int i = offset; i < type_params.Length; i++) + CurrentTypeParameters [i - offset].Emit (); + } +#endif + + base.Emit (); + } + public override string GetSignatureForError () { + if (IsGeneric) { + return SimpleName.RemoveGenericArity (Name) + TypeParameter.GetSignatureForError (type_params); + } // 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 @@ -800,41 +1078,47 @@ namespace Mono.CSharp { 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: - // - // This test should probably use the declaringtype. - // - return check_type.Assembly == TypeBuilder.Assembly; + + 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; + + return TypeManager.IsThisOrFriendAssembly (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 TypeManager.IsThisOrFriendAssembly (check_type.Assembly) && + FamilyAccessible (tb, check_type); case TypeAttributes.NestedFamORAssem: - return (check_type.Assembly == TypeBuilder.Assembly) || - FamilyAccessible (check_type); + return FamilyAccessible (tb, check_type) || + TypeManager.IsThisOrFriendAssembly (check_type.Assembly); case TypeAttributes.NestedAssembly: - return check_type.Assembly == TypeBuilder.Assembly; + return TypeManager.IsThisOrFriendAssembly (check_type.Assembly); } Console.WriteLine ("HERE: " + check_attr); @@ -842,196 +1126,323 @@ namespace Mono.CSharp { } - 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); } - // Access level of a type. - const int X = 1; - enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope' - // Public Assembly Protected - Protected = (0 << 0) | (0 << 1) | (X << 2), - Public = (X << 0) | (X << 1) | (X << 2), - Private = (0 << 0) | (0 << 1) | (0 << 2), - Internal = (0 << 0) | (X << 1) | (0 << 2), - ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2), + public bool IsBaseType (Type baseType) + { + if (TypeManager.IsInterfaceType (baseType)) + throw new NotImplementedException (); + + Type type = TypeBuilder; + while (type != null) { + if (TypeManager.IsEqual (type, baseType)) + return true; + + type = type.BaseType; + } + + return false; } - - static AccessLevel GetAccessLevelFromModifiers (int flags) + + private Type LookupNestedTypeInHierarchy (string name) { - if ((flags & Modifiers.INTERNAL) != 0) { - - if ((flags & Modifiers.PROTECTED) != 0) - return AccessLevel.ProtectedOrInternal; - else - return AccessLevel.Internal; + Type t = null; + // if the member cache has been created, lets use it. + // the member cache is MUCH faster. + if (MemberCache != null) { + t = MemberCache.FindNestedType (name); + if (t == null) + return null; - } else if ((flags & Modifiers.PROTECTED) != 0) - return AccessLevel.Protected; - - else if ((flags & Modifiers.PRIVATE) != 0) - return AccessLevel.Private; - - else - return AccessLevel.Public; - } + // + // FIXME: This hack is needed because member cache does not work + // with nested base generic types, it does only type name copy and + // not type construction + // +#if !GMCS_SOURCE + return t; +#endif + } - // What is the effective access level of this? - // TODO: Cache this? - AccessLevel EffectiveAccessLevel { - get { - AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags); - if (!IsTopLevel && (Parent != null)) - return myAccess & Parent.EffectiveAccessLevel; - return myAccess; + // no member cache. Do it the hard way -- reflection + for (Type current_type = TypeBuilder; + current_type != null && current_type != TypeManager.object_type; + current_type = current_type.BaseType) { + + 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 (ct, name); + } + + 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; } - // Return the access level for type `t' - static AccessLevel TypeEffectiveAccessLevel (Type t) + public virtual ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc) { - if (t.IsPublic) - return AccessLevel.Public; - if (t.IsNestedPrivate) - return AccessLevel.Private; - if (t.IsNotPublic) - return AccessLevel.Internal; - - // By now, it must be nested - AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType); - - if (t.IsNestedPublic) - return parentLevel; - if (t.IsNestedAssembly) - return parentLevel & AccessLevel.Internal; - if (t.IsNestedFamily) - return parentLevel & AccessLevel.Protected; - if (t.IsNestedFamORAssem) - return parentLevel & AccessLevel.ProtectedOrInternal; - if (t.IsNestedFamANDAssem) - throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways"); - - // nested private is taken care of + return null; + } + + // + // Public function used to locate types. + // + // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors. + // + // Returns: Type or null if they type can not be found. + // + public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104) + { + if (Cache.Contains (name)) + return (FullNamedExpression) Cache [name]; + + FullNamedExpression e; + int errors = Report.Errors; + Type t = LookupNestedTypeInHierarchy (name); + if (t != null) + e = new TypeExpression (t, Location.Null); + else if (Parent != null) + e = Parent.LookupNamespaceOrType (name, loc, ignore_cs0104); + else + e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104); + + if (errors == Report.Errors) + Cache [name] = e; - throw new Exception ("I give up, what are you?"); + return e; + } + + /// + /// This function is broken and not what you're looking for. It should only + /// be used while the type is still being created since it doesn't use the cache + /// and relies on the filter doing the member name check. + /// + /// + // [Obsolete ("Only MemberCache approach should be used")] + public virtual MemberList FindMembers (MemberTypes mt, BindingFlags bf, + MemberFilter filter, object criteria) + { + throw new NotSupportedException (); + } + + /// + /// If we have a MemberCache, return it. This property may return null if the + /// class doesn't have a member cache or while it's still being created. + /// + public abstract MemberCache MemberCache { + get; + } + + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + if (a.Type == TypeManager.required_attr_type) { + Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types"); + return; + } + TypeBuilder.SetCustomAttribute (cb); } // - // This answers `is the type P, as accessible as a member M which has the - // accessability @flags which is declared as a nested member of the type T, this declspace' + // Extensions for generics // - public bool AsAccessible (Type p, int flags) + protected TypeParameter[] type_params; + TypeParameter[] type_param_list; + + 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]; + // - // 1) if M is private, its accessability is the same as this declspace. - // we already know that P is accessible to T before this method, so we - // may return true. + // Register all the names // - - if ((flags & Modifiers.PRIVATE) != 0) - return true; - - while (p.IsArray || p.IsPointer || p.IsByRef) - p = TypeManager.GetElementType (p); - - AccessLevel pAccess = TypeEffectiveAccessLevel (p); - AccessLevel mAccess = this.EffectiveAccessLevel & - GetAccessLevelFromModifiers (flags); - - // for every place from which we can access M, we must - // be able to access P as well. So, we want - // For every bit in M and P, M_i -> P_1 == true - // or, ~ (M -> P) == 0 <-> ~ ( ~M | P) == 0 - - return ~ (~ mAccess | pAccess) == 0; - } + 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; + } + } + } - private Type LookupNestedTypeInHierarchy (string name) - { - // if the member cache has been created, lets use it. - // the member cache is MUCH faster. - if (MemberCache != null) - return MemberCache.FindNestedType (name); + type_params [i] = new TypeParameter ( + Parent, this, name.Name, constraints, name.OptAttributes, + Location); - // no member cache. Do it the hard way -- reflection - Type t = null; - 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); - if (tc != null) - t = tc.FindNestedType (name); - } else { - t = TypeManager.GetNestedType (current_type, name); + 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); } + } + } - if (t != null && CheckAccessLevel (t)) - return t; + 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; } + } - return null; + public TypeParameter[] CurrentTypeParameters { + get { + if (!IsGeneric) + throw new InvalidOperationException (); + + // TODO: Something is seriously broken here + if (type_params == null) + return new TypeParameter [0]; + + return type_params; + } } - // - // Public function used to locate types. - // - // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors. - // - // Returns: Type or null if they type can not be found. - // - public FullNamedExpression LookupType (string name, Location loc, bool ignore_cs0104) + public int CountTypeParameters { + get { + return count_type_params; + } + } + + public TypeParameterExpr LookupGeneric (string name, Location loc) { - if (Cache.Contains (name)) - return (FullNamedExpression) Cache [name]; + if (!IsGeneric) + return null; - FullNamedExpression e; - Type t = LookupNestedTypeInHierarchy (name); - if (t != null) - e = new TypeExpression (t, Location.Null); - else if (Parent != null) - e = Parent.LookupType (name, loc, ignore_cs0104); + TypeParameter [] current_params; + if (this is TypeContainer) + current_params = PartialContainer.CurrentTypeParameters; else - e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104); + current_params = CurrentTypeParameters; - Cache [name] = e; - return e; - } + foreach (TypeParameter type_param in current_params) { + if (type_param.Name == name) + return new TypeParameterExpr (type_param, loc); + } - /// - /// This function is broken and not what you're looking for. It should only - /// be used while the type is still being created since it doesn't use the cache - /// and relies on the filter doing the member name check. - /// - public abstract MemberList FindMembers (MemberTypes mt, BindingFlags bf, - MemberFilter filter, object criteria); + if (Parent != null) + return Parent.LookupGeneric (name, loc); - /// - /// If we have a MemberCache, return it. This property may return null if the - /// class doesn't have a member cache or while it's still being created. - /// - public abstract MemberCache MemberCache { - get; + return null; } - public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + // Used for error reporting only + public virtual Type LookupAnyGeneric (string typeName) { - if (a.Type == TypeManager.required_attr_type) { - Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types"); - return; - } - TypeBuilder.SetCustomAttribute (cb); + return NamespaceEntry.NS.LookForAnyGenericType (typeName); } public override string[] ValidAttributeTargets { @@ -1044,7 +1455,19 @@ namespace Mono.CSharp { 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); @@ -1061,7 +1484,11 @@ namespace Mono.CSharp { 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; } } @@ -1097,7 +1524,7 @@ namespace Mono.CSharp { List = list; } - public static readonly MemberList Empty = new MemberList (new ArrayList ()); + public static readonly MemberList Empty = new MemberList (new ArrayList (0)); /// /// Cast the MemberList into a MemberInfo[] array. @@ -1265,13 +1692,6 @@ namespace Mono.CSharp { /// this method is called multiple times with different BindingFlags. /// MemberList GetMembers (MemberTypes mt, BindingFlags bf); - - /// - /// Return the container's member cache. - /// - MemberCache MemberCache { - get; - } } /// @@ -1314,6 +1734,8 @@ namespace Mono.CSharp { // 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); @@ -1325,6 +1747,15 @@ namespace Mono.CSharp { Timer.StopTimer (TimerType.CacheInit); } + public MemberCache (Type baseType, IMemberContainer container) + { + this.Container = container; + if (baseType == null) + this.member_hash = new Hashtable (); + else + this.member_hash = SetupCache (TypeManager.LookupMemberCache (baseType)); + } + public MemberCache (Type[] ifaces) { // @@ -1341,23 +1772,63 @@ namespace Mono.CSharp { 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); + } + } + } + /// /// Bootstrap this member cache by doing a deep-copy of our base. /// static Hashtable SetupCache (MemberCache base_class) { - Hashtable hash = new Hashtable (); - if (base_class == null) - return hash; + return new Hashtable (); + Hashtable hash = new Hashtable (base_class.member_hash.Count); IDictionaryEnumerator it = base_class.member_hash.GetEnumerator (); while (it.MoveNext ()) { - hash [it.Key] = ((ArrayList) it.Value).Clone (); + hash.Add (it.Key, ((ArrayList) it.Value).Clone ()); } return hash; } + + // + // Converts ModFlags to BindingFlags + // + static BindingFlags GetBindingFlags (int 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; + } /// /// Add the contents of `cache' to the member_hash. @@ -1410,6 +1881,46 @@ namespace Mono.CSharp { 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, MemberCore mc) + { + AddMember (mi.MemberType, GetBindingFlags (mc.ModFlags), Container, mc.MemberName.Basename, 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. + ArrayList list = (ArrayList) member_hash [name]; + if (list == null) { + list = new ArrayList (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)); + } + /// /// Add all members from class `container' with the requested MemberTypes and /// BindingFlags to the cache. This method is called multiple times with different @@ -1422,19 +1933,13 @@ namespace Mono.CSharp { 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); + } } } @@ -1465,7 +1970,7 @@ namespace Mono.CSharp { // We use a name-based hash table of ArrayList's. ArrayList list = (ArrayList) method_hash [name]; if (list == null) { - list = new ArrayList (); + list = new ArrayList (1); method_hash.Add (name, list); } @@ -1580,12 +2085,14 @@ namespace Mono.CSharp { 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, @@ -1655,7 +2162,7 @@ namespace Mono.CSharp { { 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, @@ -1802,16 +2309,84 @@ namespace Mono.CSharp { 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) @@ -1833,7 +2408,7 @@ namespace Mono.CSharp { 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) { @@ -1841,38 +2416,39 @@ namespace Mono.CSharp { // 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; } @@ -1880,13 +2456,27 @@ namespace Mono.CSharp { // // 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. // @@ -1900,34 +2490,27 @@ namespace Mono.CSharp { // 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 (!TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) + 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; @@ -2087,5 +2670,164 @@ namespace Mono.CSharp { throw new NotImplementedException (result.ToString ()); } } + + public bool CheckExistingMembersOverloads (MemberCore member, string name, Parameters parameters) + { + ArrayList entries = (ArrayList)member_hash [name]; + if (entries == null) + 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; + ParameterData pd = null; + if ((ce.EntryType & EntryType.Property) != 0) { + p_types = TypeManager.GetArgumentTypes ((PropertyInfo) ce.Member); + } else { + MethodBase mb = (MethodBase) ce.Member; +#if GMCS_SOURCE + // TODO: This is more like a hack, because we are adding generic methods + // twice with and without arity name + if (mb.IsGenericMethod && !member.MemberName.IsGeneric) + continue; +#endif + 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.ParameterType (ii); + type_b = p_types [ii]; +#if GMCS_SOURCE + if (type_a.IsGenericParameter && type_a.DeclaringMethod != null) + type_a = null; + + if (type_b.IsGenericParameter && type_b.DeclaringMethod != null) + type_b = null; +#endif + } while (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 AbstractPropertyEventMethod)) { + ii = method_param_count; + while (ii-- != 0 && parameters.ParameterModifier (ii) == pd.ParameterModifier (ii) && + 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 { + Report.Error (663, member.Location, + "An 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 int 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.IsInUnsafeScope && method_b.Parent.IsInUnsafeScope) { + if (method_a.IsPartialImplementation) { + method_a.SetPartialDefinition (method_b); + entries.RemoveAt (i); + } else { + method_b.SetPartialDefinition (method_a); + } + 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 ()); + } + + 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; + } } }