X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fdecl.cs;h=28b142c1030c71d98c0bdeb09260671bb897225b;hb=5319634c9b355ca01ee9baa276b29b211335e820;hp=891f754381c7f42115a4b12aa4032a31ed40bcca;hpb=37e0291a0fae2d1a22f99044c7193410623c356d;p=mono.git diff --git a/mcs/gmcs/decl.cs b/mcs/gmcs/decl.cs old mode 100755 new mode 100644 index 891f754381c..28b142c1030 --- a/mcs/gmcs/decl.cs +++ b/mcs/gmcs/decl.cs @@ -7,6 +7,7 @@ // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) +// (C) 2004 Novell, Inc // // TODO: Move the method verification stuff from the class.cs and interface.cs here // @@ -17,11 +18,12 @@ using System.Collections; using System.Globalization; using System.Reflection.Emit; using System.Reflection; +using System.Xml; namespace Mono.CSharp { public class MemberName { - public string Name; + public readonly string Name; public readonly TypeArguments TypeArguments; public readonly MemberName Left; @@ -39,6 +41,11 @@ namespace Mono.CSharp { this.TypeArguments = args; } + public MemberName (MemberName left, string name) + : this (left, name, null) + { + } + public MemberName (MemberName left, string name, TypeArguments args) : this (name, args) { @@ -48,6 +55,22 @@ namespace Mono.CSharp { public MemberName (MemberName left, MemberName right) : this (left, right.Name, right.TypeArguments) { + Name = right.Name; + Left = (right.Left == null) ? left : new MemberName (left, right.Left); + TypeArguments = right.TypeArguments; + } + + static readonly char [] dot_array = { '.' }; + + public static MemberName FromDotted (string name) + { + string [] elements = name.Split (dot_array); + int count = elements.Length; + int i = 0; + MemberName n = new MemberName (elements [i++]); + while (i < count) + n = new MemberName (n, elements [i++]); + return n; } public string GetName () @@ -110,7 +133,6 @@ namespace Mono.CSharp { public string GetTypeName () { - string suffix = ""; if (Left != null) return Left.GetTypeName () + "." + MakeName (Name, TypeArguments); @@ -156,7 +178,7 @@ namespace Mono.CSharp { return new MemberAccess (lexpr, Name, TypeArguments, loc); } else { if (TypeArguments != null) - return new ConstructedType (Name, TypeArguments, loc); + return new SimpleName (Basename, TypeArguments, loc); else return new SimpleName (Name, loc); } @@ -181,9 +203,6 @@ namespace Mono.CSharp { public override string ToString () { - throw new Exception ("This exception is thrown because someone is miss-using\n" + - "MemberName.ToString in the compiler. Please report this bug"); - string full_name; if (TypeArguments != null) full_name = Name + "<" + TypeArguments + ">"; @@ -195,6 +214,43 @@ namespace Mono.CSharp { else return full_name; } + + public override bool Equals (object other) + { + return Equals (other as MemberName); + } + + public bool Equals (MemberName other) + { + if (this == other) + return true; + if (other == null || Name != other.Name) + return false; + + if ((TypeArguments != null) && + (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count)) + return false; + + if ((TypeArguments == null) && (other.TypeArguments != null)) + return false; + + if (Left == null) + return other.Left == null; + + return Left.Equals (other.Left); + } + + public override int GetHashCode () + { + int hash = Name.GetHashCode (); + for (MemberName n = Left; n != null; n = n.Left) + hash ^= n.Name.GetHashCode (); + + if (TypeArguments != null) + hash ^= TypeArguments.Count << 5; + + return hash & 0x7FFFFFFF; + } } /// @@ -205,26 +261,45 @@ namespace Mono.CSharp { /// /// Public name /// + + protected string cached_name; public string Name { get { - return MemberName.GetName (!(this is GenericMethod) && !(this is Method)); + if (cached_name == null) + cached_name = MemberName.GetName (!(this is GenericMethod) && !(this is Method)); + return cached_name; } } - public readonly MemberName MemberName; + // Is not readonly because of IndexerName attribute + private MemberName member_name; + public MemberName MemberName { + get { return member_name; } + } /// /// Modifier flags that the user specified in the source code /// public int ModFlags; - public readonly TypeContainer Parent; + public /*readonly*/ TypeContainer Parent; /// /// Location where this declaration happens /// public readonly Location Location; + /// + /// XML documentation comment + /// + public string DocComment; + + /// + /// Represents header string for documentation comment + /// for each member types. + /// + public abstract string DocCommentHeader { get; } + [Flags] public enum Flags { Obsolete_Undetected = 1, // Obsolete attribute has not been detected yet @@ -237,7 +312,8 @@ 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 + TestMethodDuplication = 1 << 10, // Test for duplication must be performed + IsUsed = 1 << 11 } /// @@ -249,12 +325,21 @@ namespace Mono.CSharp { Location loc) : base (attrs) { + if (parent is PartialContainer && !(this is PartialContainer)) + throw new InternalErrorException ("A PartialContainer cannot be the direct parent of a member"); + Parent = parent; - MemberName = name; + member_name = name; Location = loc; caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected; } + protected virtual void SetMemberName (MemberName new_name) + { + member_name = new_name; + cached_name = null; + } + /// /// Tests presence of ObsoleteAttribute and report proper error /// @@ -293,7 +378,9 @@ namespace Mono.CSharp { /// public virtual void Emit () { - VerifyObsoleteAttribute (); + // Hack with Parent == null is for EnumMember + if (Parent == null || (GetObsoleteAttribute (Parent) == null && Parent.GetObsoleteAttribute (Parent) == null)) + VerifyObsoleteAttribute (); if (!RootContext.VerifyClsCompliance) return; @@ -307,6 +394,17 @@ namespace Mono.CSharp { } } + public virtual bool IsUsed { + get { + return (caching_flags & Flags.IsUsed) != 0; + } + } + + public void SetMemberIsUsed () + { + caching_flags |= Flags.IsUsed; + } + // // Whehter is it ok to use an unsafe pointer in this type container // @@ -345,7 +443,7 @@ namespace Mono.CSharp { if (obsolete_attr == null) return null; - ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (ds); + ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (ds.EmitContext); if (obsolete == null) return null; @@ -374,7 +472,7 @@ namespace Mono.CSharp { /// /// Returns true when MemberCore is exposed from assembly. /// - protected bool IsExposedFromAssembly (DeclSpace ds) + public bool IsExposedFromAssembly (DeclSpace ds) { if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0) return false; @@ -394,10 +492,11 @@ namespace Mono.CSharp { bool GetClsCompliantAttributeValue (DeclSpace ds) { if (OptAttributes != null) { - Attribute cls_attribute = OptAttributes.GetClsCompliantAttribute (ds.EmitContext); + Attribute cls_attribute = OptAttributes.Search ( + TypeManager.cls_compliant_attribute_type, ds.EmitContext); if (cls_attribute != null) { caching_flags |= Flags.HasClsCompliantAttribute; - return cls_attribute.GetClsCompliantAttributeValue (ds); + return cls_attribute.GetClsCompliantAttributeValue (ds.EmitContext); } } return ds.GetClsCompliantAttributeValue (); @@ -412,6 +511,14 @@ namespace Mono.CSharp { } } + /// + /// It helps to handle error 102 & 111 detection + /// + public virtual bool MarkForDuplicationCheck () + { + return false; + } + /// /// The main virtual method for CLS-Compliant verifications. /// The method returns true if member is CLS-Compliant and false if member is not @@ -421,8 +528,11 @@ namespace Mono.CSharp { protected virtual bool VerifyClsCompliance (DeclSpace ds) { if (!IsClsCompliaceRequired (ds)) { - if ((RootContext.WarningLevel >= 2) && HasClsCompliantAttribute && !IsExposedFromAssembly (ds)) { - Report.Warning (3019, Location, "CLS compliance checking will not be performed on '{0}' because it is private or internal", GetSignatureForError ()); + if (HasClsCompliantAttribute && RootContext.WarningLevel >= 2) { + if (!IsExposedFromAssembly (ds)) + Report.Warning (3019, Location, "CLS compliance checking will not be performed on '{0}' because it is private or internal", GetSignatureForError ()); + if (!CodeGen.Assembly.IsClsCompliant) + Report.Warning (3021, Location, "'{0}' does not need a CLSCompliant attribute because the assembly does not have a CLSCompliant attribute", GetSignatureForError ()); } return false; } @@ -443,6 +553,34 @@ namespace Mono.CSharp { protected abstract void VerifyObsoleteAttribute (); + // + // Raised (and passed an XmlElement that contains the comment) + // when GenerateDocComment is writing documentation expectedly. + // + internal virtual void OnGenerateDocComment (DeclSpace ds, XmlElement intermediateNode) + { + } + + // + // Returns a string that represents the signature for this + // member which should be used in XML documentation. + // + public virtual string GetDocCommentName (DeclSpace ds) + { + if (ds == null || this is DeclSpace) + return DocCommentHeader + Name; + else + return String.Concat (DocCommentHeader, ds.Name, ".", Name); + } + + // + // Generates xml doc comments (if any), and if required, + // handle warning report. + // + internal virtual void GenerateDocComment (DeclSpace ds) + { + DocUtil.GenerateDocComment (this, ds); + } } /// @@ -473,14 +611,15 @@ namespace Mono.CSharp { // public NamespaceEntry NamespaceEntry; - public Hashtable Cache = new Hashtable (); + private Hashtable Cache = new Hashtable (); - public string Basename; + public readonly string Basename; protected Hashtable defined_names; readonly bool is_generic; readonly int count_type_params; + readonly int count_current_type_params; // The emit context for toplevel objects. protected EmitContext ec; @@ -510,11 +649,11 @@ namespace Mono.CSharp { : base (parent, name, attrs, l) { NamespaceEntry = ns; - Basename = name.Name; + Basename = name.Basename; defined_names = new Hashtable (); if (name.TypeArguments != null) { is_generic = true; - count_type_params = name.TypeArguments.Count; + count_type_params = count_current_type_params = name.TypeArguments.Count; } if (parent != null) count_type_params += parent.count_type_params; @@ -523,30 +662,39 @@ namespace Mono.CSharp { /// /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts /// - protected bool AddToContainer (MemberCore symbol, bool is_method, string fullname, string basename) - { - if (basename == Basename && !(this is Interface)) { - Report.SymbolRelatedToPreviousError (this); - Report.Error (542, "'{0}': member names cannot be the same as their enclosing type", symbol.Location, symbol.GetSignatureForError ()); + protected bool AddToContainer (MemberCore symbol, string name) + { + if (name == Basename && !(this is Interface) && !(this is Enum)) { + if (symbol is TypeParameter) + Report.Error (694, "Type parameter `{0}' has same name as " + + "containing type or method", name); + else { + Report.SymbolRelatedToPreviousError (this); + Report.Error (542, "'{0}': member names cannot be the same as their " + + "enclosing type", symbol.Location, symbol.GetSignatureForError ()); + } return false; } - MemberCore mc = (MemberCore)defined_names [fullname]; + MemberCore mc = (MemberCore) defined_names [name]; - if (is_method && (mc is MethodCore || mc is IMethodData)) { - symbol.caching_flags |= Flags.TestMethodDuplication; - mc.caching_flags |= Flags.TestMethodDuplication; + if (mc == null) { + defined_names.Add (name, symbol); return true; } - if (mc != null) { + if (symbol.MarkForDuplicationCheck () && mc.MarkForDuplicationCheck ()) + return true; + + if (symbol is TypeParameter) + Report.Error (692, symbol.Location, "Duplicate type parameter `{0}'", name); + else { Report.SymbolRelatedToPreviousError (mc); - Report.Error (102, symbol.Location, "The type '{0}' already contains a definition for '{1}'", GetSignatureForError (), basename); - return false; + Report.Error (102, symbol.Location, + "The type '{0}' already contains a definition for '{1}'", + GetSignatureForError (), name); } - - defined_names.Add (fullname, symbol); - return true; + return false; } public void RecordDecl () @@ -565,33 +713,6 @@ namespace Mono.CSharp { return (MemberCore)defined_names [name]; } - bool in_transit = false; - - /// - /// This function is used to catch recursive definitions - /// in declarations. - /// - public bool InTransit { - get { - return in_transit; - } - - set { - in_transit = value; - } - } - - /// - /// Looks up the alias for the name - /// - public IAlias LookupAlias (string name) - { - if (NamespaceEntry != null) - return NamespaceEntry.LookupAlias (name); - else - return null; - } - // // root_types contains all the types. All TopLevel types // hence have a parent that points to `root_types', that is @@ -628,6 +749,12 @@ namespace Mono.CSharp { } } + protected virtual TypeAttributes TypeAttr { + get { + return CodeGen.Module.DefaultCharSetType; + } + } + /// /// Should be overriten by the appropriate declaration space /// @@ -652,67 +779,37 @@ namespace Mono.CSharp { } } - public static string MakeFQN (string nsn, string name) - { - if (nsn == "") - return name; - return String.Concat (nsn, ".", name); - } - EmitContext type_resolve_ec; - EmitContext GetTypeResolveEmitContext (TypeContainer parent, Location loc) - { - type_resolve_ec = new EmitContext (parent, this, loc, null, null, ModFlags, false); - type_resolve_ec.ResolvingTypeTree = true; - - return type_resolve_ec; - } - - public Type ResolveNestedType (Type t, Location loc) - { - TypeContainer tc = TypeManager.LookupTypeContainer (t); - if ((tc != null) && tc.IsGeneric) { - if (!IsGeneric) { - int tnum = TypeManager.GetNumberOfTypeArguments (t); - Report.Error (305, loc, - "Using the generic type `{0}' " + - "requires {1} type arguments", - TypeManager.GetFullName (t), tnum); - return null; + protected EmitContext TypeResolveEmitContext { + get { + if (type_resolve_ec == null) { + // FIXME: I think this should really be one of: + // + // a. type_resolve_ec = Parent.EmitContext; + // b. type_resolve_ec = new EmitContext (Parent, Parent, loc, null, null, ModFlags, false); + // + // However, if Parent == RootContext.Tree.Types, its NamespaceEntry will be null. + // + type_resolve_ec = new EmitContext (Parent, this, Location.Null, null, null, ModFlags, false); } - - TypeParameter[] args; - if (this is GenericMethod) - args = Parent.TypeParameters; - else - args = TypeParameters; - - TypeExpr ctype = new ConstructedType (t, args, loc); - ctype = ctype.ResolveAsTypeTerminal (ec); - if (ctype == null) - return null; - - t = ctype.Type; + return type_resolve_ec; } - - return t; } // // Resolves the expression `e' for a type, and will recursively define // types. This should only be used for resolving base types. // - public TypeExpr ResolveTypeExpr (Expression e, Location loc) + public TypeExpr ResolveBaseTypeExpr (Expression e, bool silent, Location loc) { - if (type_resolve_ec == null) - type_resolve_ec = GetTypeResolveEmitContext (Parent, loc); - type_resolve_ec.loc = loc; + TypeResolveEmitContext.loc = loc; + TypeResolveEmitContext.ContainerType = TypeBuilder; if (this is GenericMethod) - type_resolve_ec.ContainerType = Parent.TypeBuilder; + TypeResolveEmitContext.ContainerType = Parent.TypeBuilder; else - type_resolve_ec.ContainerType = TypeBuilder; + TypeResolveEmitContext.ContainerType = TypeBuilder; - return e.ResolveAsTypeTerminal (type_resolve_ec); + return e.ResolveAsTypeTerminal (TypeResolveEmitContext); } public bool CheckAccessLevel (Type check_type) @@ -729,6 +826,12 @@ namespace Mono.CSharp { if (check_type == tb) return true; + 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 (check_type.IsGenericParameter) return true; // FIXME @@ -789,20 +892,9 @@ namespace Mono.CSharp { protected bool NestedAccessible (Type tb, Type check_type) { - string check_type_name = check_type.FullName; - - // At this point, we already know check_type is a nested class. - int cio = check_type_name.LastIndexOf ('+'); - - // Ensure that the string 'container' has a '+' in it to avoid false matches - string container = check_type_name.Substring (0, cio + 1); - - // Ensure that type_name ends with a '+' so that it can match 'container', if necessary - string type_name = tb.FullName + "+"; - - // If the current class is nested inside the container of check_type, - // we can access check_type even if it is private or protected. - return type_name.StartsWith (container); + Type declaring = check_type.DeclaringType; + return TypeBuilder == declaring || + TypeManager.IsNestedChildOf (TypeBuilder, declaring); } protected bool FamilyAccessible (Type tb, Type check_type) @@ -914,69 +1006,6 @@ namespace Mono.CSharp { return ~ (~ mAccess | pAccess) == 0; } - - static DoubleHash dh = new DoubleHash (1000); - - Type DefineTypeAndParents (DeclSpace tc) - { - DeclSpace container = tc.Parent; - - if (container.TypeBuilder == null && container.Name != "") - DefineTypeAndParents (container); - - return tc.DefineType (); - } - - Type LookupInterfaceOrClass (string ns, string name, out bool error) - { - DeclSpace parent; - Type t; - object r; - - error = false; - - if (dh.Lookup (ns, name, out r)) - return (Type) r; - else { - if (ns != ""){ - if (Namespace.IsNamespace (ns)){ - string fullname = (ns != "") ? ns + "." + name : name; - t = TypeManager.LookupType (fullname); - } else - t = null; - } else - t = TypeManager.LookupType (name); - } - - if (t != null) { - dh.Insert (ns, name, t); - return t; - } - - // - // In case we are fed a composite name, normalize it. - // - int p = name.LastIndexOf ('.'); - if (p != -1){ - ns = MakeFQN (ns, name.Substring (0, p)); - name = name.Substring (p+1); - } - - parent = RootContext.Tree.LookupByNamespace (ns, name); - if (parent == null) { - dh.Insert (ns, name, null); - return null; - } - - t = DefineTypeAndParents (parent); - if (t == null){ - error = true; - return null; - } - - dh.Insert (ns, name, t); - return t; - } public static void Error_AmbiguousTypeReference (Location loc, string name, string t1, string t2) { @@ -985,153 +1014,70 @@ namespace Mono.CSharp { name, t1, t2); } - public Type FindNestedType (Location loc, string name, - out DeclSpace containing_ds) + // + // Return the nested type with name @name. Ensures that the nested type + // is defined if necessary. Do _not_ use this when you have a MemberCache handy. + // + public virtual Type FindNestedType (string name) { - Type t; - bool error; - - containing_ds = this; - while (containing_ds != null){ - Type container_type = containing_ds.TypeBuilder; - Type current_type = container_type; - - while (current_type != null && current_type != TypeManager.object_type) { - string pre = current_type.FullName; - - t = LookupInterfaceOrClass (pre, name, out error); - if (error) - return null; - - if ((t != null) && containing_ds.CheckAccessLevel (t)) - return t; - - current_type = current_type.BaseType; - } - containing_ds = containing_ds.Parent; - } - return null; } - /// - /// GetType is used to resolve type names at the DeclSpace level. - /// Use this to lookup class/struct bases, interface bases or - /// delegate type references - /// - /// - /// - /// Contrast this to LookupType which is used inside method bodies to - /// lookup types that have already been defined. GetType is used - /// during the tree resolution process and potentially define - /// recursively the type - /// - public Type FindType (Location loc, string name) + private Type LookupNestedTypeInHierarchy (string name) { - Type t; - bool error; - - // - // For the case the type we are looking for is nested within this one - // or is in any base class - // - DeclSpace containing_ds = this; - - while (containing_ds != null){ - Type container_type = containing_ds.TypeBuilder; - Type current_type = container_type; - - while (current_type != null && current_type != TypeManager.object_type) { - string pre = current_type.FullName; + // if the member cache has been created, lets use it. + // the member cache is MUCH faster. + if (MemberCache != null) + return MemberCache.FindNestedType (name); - t = LookupInterfaceOrClass (pre, name, out error); - if (error) - return null; - - if ((t != null) && containing_ds.CheckAccessLevel (t)) - return ResolveNestedType (t, loc); - - current_type = current_type.BaseType; + // 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) { + DeclSpace decl = this; + if (current_type != TypeBuilder) + decl = TypeManager.LookupDeclSpace (current_type); + t = decl.FindNestedType (name); + } else { + t = TypeManager.GetNestedType (current_type, name); } - containing_ds = containing_ds.Parent; - } - // - // Attempt to lookup the class on our namespace and all it's implicit parents - // - for (NamespaceEntry ns = NamespaceEntry; ns != null; ns = ns.ImplicitParent) { - t = LookupInterfaceOrClass (ns.FullName, name, out error); - if (error) - return null; - - if (t != null) + if (t != null && CheckAccessLevel (t)) return t; } - - // - // Attempt to do a direct unqualified lookup - // - t = LookupInterfaceOrClass ("", name, out error); - if (error) - return null; - - if (t != null) - return t; - - // - // Attempt to lookup the class on any of the `using' - // namespaces - // - for (NamespaceEntry ns = NamespaceEntry; ns != null; ns = ns.Parent){ - - t = LookupInterfaceOrClass (ns.FullName, name, out error); - if (error) - return null; - - if (t != null) - return t; - - if (name.IndexOf ('.') > 0) - continue; + return null; + } - IAlias alias_value = ns.LookupAlias (name); - if (alias_value != null) { - t = LookupInterfaceOrClass ("", alias_value.Name, out error); - if (error) - return null; + // + // Public function used to locate types, this can only + // be used after the ResolveTree function has been invoked. + // + // 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) + { + if (this is PartialContainer) + throw new InternalErrorException ("Should not get here"); - if (t != null) - return t; - } + if (Cache.Contains (name)) + return (FullNamedExpression) Cache [name]; - // - // Now check the using clause list - // - Type match = null; - foreach (Namespace using_ns in ns.GetUsingTable ()) { - match = LookupInterfaceOrClass (using_ns.Name, name, out error); - if (error) - return null; - - if (match != null) { - if (t != null){ - if (CheckAccessLevel (match)) { - Error_AmbiguousTypeReference (loc, name, t.FullName, match.FullName); - return null; - } - continue; - } - - t = match; - } - } - if (t != null) - return t; - } + FullNamedExpression e; + Type t = LookupNestedTypeInHierarchy (name); + if (t != null) + e = new TypeExpression (t, Location.Null); + else if (Parent != null && Parent != RootContext.Tree.Types) + e = Parent.LookupType (name, loc, ignore_cs0104); + else + e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104); - //Report.Error (246, Location, "Can not find type `"+name+"'"); - return null; + Cache [name] = e; + return e; } /// @@ -1152,17 +1098,11 @@ namespace Mono.CSharp { public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { - try { - TypeBuilder.SetCustomAttribute (cb); - } catch (System.ArgumentException e) { - Report.Warning (-21, a.Location, - "The CharSet named property on StructLayout\n"+ - "\tdoes not work correctly on Microsoft.NET\n"+ - "\tYou might want to remove the CharSet declaration\n"+ - "\tor compile using the Mono runtime instead of the\n"+ - "\tMicrosoft .NET runtime\n"+ - "\tThe runtime gave the error: " + e); + 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); } /// @@ -1177,10 +1117,10 @@ namespace Mono.CSharp { caching_flags &= ~Flags.HasCompliantAttribute_Undetected; if (OptAttributes != null) { - Attribute cls_attribute = OptAttributes.GetClsCompliantAttribute (ec); + Attribute cls_attribute = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, ec); if (cls_attribute != null) { caching_flags |= Flags.HasClsCompliantAttribute; - if (cls_attribute.GetClsCompliantAttributeValue (this)) { + if (cls_attribute.GetClsCompliantAttributeValue (ec)) { caching_flags |= Flags.ClsCompliantAttributeTrue; return true; } @@ -1275,7 +1215,7 @@ namespace Mono.CSharp { return type_param_list; } - public void SetParameterInfo (ArrayList constraints_list) + public virtual void SetParameterInfo (ArrayList constraints_list) { if (!is_generic) { if (constraints_list != null) { @@ -1308,8 +1248,7 @@ namespace Mono.CSharp { type_params [i] = new TypeParameter (Parent, name, constraints, Location); - string full_name = Name + "." + name; - AddToContainer (type_params [i], false, full_name, name); + AddToContainer (type_params [i], name); } } @@ -1341,6 +1280,12 @@ namespace Mono.CSharp { } } + public int CountCurrentTypeParameters { + get { + return count_current_type_params; + } + } + public TypeParameterExpr LookupGeneric (string name, Location loc) { if (!IsGeneric) @@ -1555,12 +1500,12 @@ namespace Mono.CSharp { } /// - /// Returns the IMemberContainer of the parent class or null if this + /// 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 parent class. + /// members from the base class. /// - MemberCache ParentCache { + MemberCache BaseCache { get; } @@ -1622,17 +1567,20 @@ namespace Mono.CSharp { Timer.IncrementCounter (CounterType.MemberCache); Timer.StartTimer (TimerType.CacheInit); - // If we have a parent class (we have a parent class unless we're + // 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.ParentCache != null) - member_hash = SetupCache (Container.ParentCache); + if (Container.BaseCache != null) + member_hash = SetupCache (Container.BaseCache); else member_hash = new Hashtable (); // 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.IsGenericParameter) { + if (!(type is TypeBuilder) && !type.IsInterface && + // !(type.IsGenericInstance && (type.GetGenericTypeDefinition () is TypeBuilder)) && + !type.IsGenericInstance && + (Container.BaseCache == null || Container.BaseCache.method_hash != null)) { method_hash = new Hashtable (); AddMethods (type); } @@ -1660,23 +1608,32 @@ namespace Mono.CSharp { } /// - /// Bootstrap this member cache by doing a deep-copy of our parent. + /// Bootstrap this member cache by doing a deep-copy of our base. /// - Hashtable SetupCache (MemberCache parent) + Hashtable SetupCache (MemberCache base_class) { Hashtable hash = new Hashtable (); - if (parent == null) + if (base_class == null) return hash; - IDictionaryEnumerator it = parent.member_hash.GetEnumerator (); + IDictionaryEnumerator it = base_class.member_hash.GetEnumerator (); while (it.MoveNext ()) { hash [it.Key] = ((ArrayList) it.Value).Clone (); - } + } return hash; } + void ClearDeclaredOnly (Hashtable hash) + { + IDictionaryEnumerator it = hash.GetEnumerator (); + while (it.MoveNext ()) { + foreach (CacheEntry ce in (ArrayList) it.Value) + ce.EntryType &= ~EntryType.Declared; + } + } + /// /// Add the contents of `cache' to the member_hash. /// @@ -1752,7 +1709,7 @@ namespace Mono.CSharp { } // When this method is called for the current class, the list will - // already contain all inherited members from our parent classes. + // 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). @@ -1775,7 +1732,16 @@ namespace Mono.CSharp { void AddMethods (BindingFlags bf, Type type) { - MemberInfo [] members = type.GetMethods (bf); + // + // Consider the case: + // + // class X { public virtual int f() {} } + // class Y : X {} + // + // When processing 'Y', the method_cache will already have a copy of 'f', + // with ReflectedType == X. However, we want to ensure that its ReflectedType == Y + // + MethodBase [] members = type.GetMethods (bf); Array.Reverse (members); @@ -1789,6 +1755,35 @@ namespace Mono.CSharp { 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) { + // + // Both mcs and CSC 1.1 seem to emit a somewhat broken + // ...Invoke () function for delegates: it's missing a 'newslot'. + // CSC 2.0 emits a 'newslot' for a delegate's Invoke. + // + // Also, CSC 1.1 appears to emit 'Finalize' without a newslot. + // + if ((curr.Name == "Invoke" && TypeManager.IsDelegateType (curr.DeclaringType)) || + (curr.Name == "Finalize" && curr.GetParameters().Length == 0 && curr.DeclaringType == TypeManager.object_type)) + break; + + Report.SymbolRelatedToPreviousError (base_method); + Report.Warning (-28, + "The method '{0}' is marked 'override'," + + " but doesn't appear to override any virtual or abstract method:" + + " it may be ignored during overload resolution", + TypeManager.CSharpSignature (base_method)); + break; + } + + list.Add (new CacheEntry (null, base_method, MemberTypes.Method, bf)); + curr = base_method; + } + // Unfortunately, the elements returned by Type.GetMethods() aren't // sorted so we need to do this check for every member. BindingFlags new_bf = bf; @@ -1884,10 +1879,10 @@ namespace Mono.CSharp { MaskType = Constructor|Event|Field|Method|Property|NestedType } - protected struct CacheEntry { + protected class CacheEntry { public readonly IMemberContainer Container; - public readonly EntryType EntryType; - public readonly MemberInfo Member; + public EntryType EntryType; + public MemberInfo Member; public CacheEntry (IMemberContainer container, MemberInfo member, MemberTypes mt, BindingFlags bf) @@ -1995,9 +1990,9 @@ namespace Mono.CSharp { // `applicable' is a list of all members with the given member name `name' - // in the current class and all its parent classes. The list is sorted in + // 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 parent). + // 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]; @@ -2048,6 +2043,22 @@ namespace Mono.CSharp { return copy; } + // find the nested type @name in @this. + public Type FindNestedType (string name) + { + ArrayList applicable = (ArrayList) member_hash [name]; + if (applicable == null) + return null; + + for (int i = applicable.Count-1; i >= 0; i--) { + CacheEntry entry = (CacheEntry) applicable [i]; + if ((entry.EntryType & EntryType.NestedType & EntryType.MaskType) != 0) + return (Type) entry.Member; + } + + return null; + } + // // This finds the method or property for us to override. invocationType is the type where // the override is going to be declared, name is the name of the method/property, and