2003-04-28 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / decl.cs
index 413b1e7ccfa3bd810521f74555fc1828b1042cc1..e293e0ad5a975543950a4bd67e4b065e7912c422 100755 (executable)
@@ -94,16 +94,64 @@ namespace Mono.CSharp {
                                                      "' because it is sealed.");
                                        ok = false;
                                }
-
                                //
                                // Check that the permissions are not being changed
                                //
                                MethodAttributes thisp = my_attrs & MethodAttributes.MemberAccessMask;
                                MethodAttributes parentp = mb.Attributes & MethodAttributes.MemberAccessMask;
 
-                               if (thisp != parentp){
-                                       Error_CannotChangeAccessModifiers (parent, mb, name);
-                                       ok = false;
+                               //
+                               // special case for "protected internal"
+                               //
+
+                               if ((parentp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){
+                                       //
+                                       // when overriding protected internal, the method can be declared
+                                       // protected internal only within the same assembly
+                                       //
+
+                                       if ((thisp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){
+                                               if (parent.TypeBuilder.Assembly != mb.DeclaringType.Assembly){
+                                                       //
+                                                       // assemblies differ - report an error
+                                                       //
+                                                       
+                                                       Error_CannotChangeAccessModifiers (parent, mb, name);
+                                                   ok = false;
+                                               } else if (thisp != parentp) {
+                                                       //
+                                                       // same assembly, but other attributes differ - report an error
+                                                       //
+                                                       
+                                                       Error_CannotChangeAccessModifiers (parent, mb, name);
+                                                       ok = false;
+                                               };
+                                       } else if ((thisp & MethodAttributes.Family) != MethodAttributes.Family) {
+                                               //
+                                               // if it's not "protected internal", it must be "protected"
+                                               //
+
+                                               Error_CannotChangeAccessModifiers (parent, mb, name);
+                                               ok = false;
+                                       } else if (parent.TypeBuilder.Assembly == mb.DeclaringType.Assembly) {
+                                               //
+                                               // protected within the same assembly - an error
+                                               //
+                                               Error_CannotChangeAccessModifiers (parent, mb, name);
+                                               ok = false;
+                                       } else if ((thisp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem)) != 
+                                                  (parentp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem))) {
+                                               //
+                                               // protected ok, but other attributes differ - report an error
+                                               //
+                                               Error_CannotChangeAccessModifiers (parent, mb, name);
+                                               ok = false;
+                                       }
+                               } else {
+                                       if (thisp != parentp){
+                                               Error_CannotChangeAccessModifiers (parent, mb, name);
+                                               ok = false;
+                                       }
                                }
                        }
 
@@ -249,9 +297,9 @@ namespace Mono.CSharp {
                ///   Returns a status code based purely on the name
                ///   of the member being added
                /// </summary>
-               protected AdditionResult IsValid (string name)
+               protected AdditionResult IsValid (string basename, string name)
                {
-                       if (name == Basename)
+                       if (basename == Basename)
                                return AdditionResult.EnclosingClash;
 
                        if (defined_names.Contains (name))
@@ -384,9 +432,9 @@ namespace Mono.CSharp {
 
                public static string MakeFQN (string nsn, string name)
                {
-                       string prefix = (nsn == "" ? "" : nsn + ".");
-
-                       return prefix + name;
+                       if (nsn == "")
+                               return name;
+                       return String.Concat (nsn, ".", name);
                }
 
                EmitContext type_resolve_ec;
@@ -406,9 +454,10 @@ namespace Mono.CSharp {
                        if (type_resolve_ec == null)
                                type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
                        type_resolve_ec.loc = loc;
+                       type_resolve_ec.ContainerType = TypeBuilder;
 
                        int errors = Report.Errors;
-                       Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
+                       Expression d = e.ResolveAsTypeTerminal (type_resolve_ec);
                        
                        if (d == null || d.eclass != ExprClass.Type){
                                if (!silent && errors == Report.Errors){
@@ -417,6 +466,12 @@ namespace Mono.CSharp {
                                return null;
                        }
 
+                       if (!CheckAccessLevel (d.Type)) {
+                               Report. Error (122, loc,  "`" + d.Type + "' " +
+                                      "is inaccessible because of its protection level");
+                               return null;
+                       }
+
                        return d.Type;
                }
 
@@ -428,8 +483,10 @@ namespace Mono.CSharp {
                {
                        if (type_resolve_ec == null)
                                type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
+                       type_resolve_ec.loc = loc;
+                       type_resolve_ec.ContainerType = TypeBuilder;
 
-                       Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
+                       Expression d = e.ResolveAsTypeTerminal (type_resolve_ec);
                         
                        if (d == null || d.eclass != ExprClass.Type){
                                if (!silent){
@@ -441,14 +498,66 @@ namespace Mono.CSharp {
                        return d;
                }
                
+               public bool CheckAccessLevel (Type check_type) 
+               {
+                       if (check_type == TypeBuilder)
+                               return true;
+                       
+                       TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
+                       
+                       //
+                       // Broken Microsoft runtime, return public for arrays, no matter what 
+                       // the accessibility is for their underlying class, and they return 
+                       // NonPublic visibility for pointers
+                       //
+                       if (check_type.IsArray || check_type.IsPointer)
+                               return CheckAccessLevel (check_type.GetElementType ());
+
+                       if (check_attr == TypeAttributes.Public)
+                               return true;
+                       
+                       if (check_attr == TypeAttributes.NestedPublic)
+                               return true;
+
+                       if (check_attr == TypeAttributes.NestedPrivate){
+                               string check_type_name = check_type.FullName;
+                               string type_name = TypeBuilder.FullName;
+                               
+                               int cio = check_type_name.LastIndexOf ("+");
+                               string container = check_type_name.Substring (0, cio);
+
+                               //
+                               // Check if the check_type is a nested class of the current type
+                               //
+                               if (check_type_name.StartsWith (type_name + "+")){
+                                       return true;
+                               }
+                               
+                               if (type_name.StartsWith (container)){
+                                       return true;
+                               }
+
+                               return false;
+                       }
+                       
+                       if (check_type.Assembly == TypeBuilder.Assembly){
+                               return true;
+                       }
+
+                       return false;
+
+               }
+
+
                Type LookupInterfaceOrClass (string ns, string name, out bool error)
                {
                        DeclSpace parent;
                        Type t;
 
                        error = false;
+
                        name = MakeFQN (ns, name);
-                       
+
                        t  = TypeManager.LookupType (name);
                        if (t != null)
                                return t;
@@ -518,7 +627,6 @@ namespace Mono.CSharp {
                        // Attempt to lookup the class on our namespace and all it's implicit parents
                        //
                        for (string ns = Namespace.Name; ns != null; ns = RootContext.ImplicitParent (ns)) {
-
                                t = LookupInterfaceOrClass (ns, name, out error);
                                if (error)
                                        return null;
@@ -572,7 +680,6 @@ namespace Mono.CSharp {
                                                }
                                                
                                                t = match;
-                                               ue.Used = true;
                                        }
                                }
                                if (t != null)
@@ -1180,11 +1287,12 @@ namespace Mono.CSharp {
                        // If this is a method-only search, we try to use the method cache if
                        // possible; a lookup in the method cache will return a MemberInfo with
                        // the correct ReflectedType for inherited methods.
+                       
                        if (method_search && (method_hash != null))
                                applicable = (ArrayList) method_hash [name];
                        else
                                applicable = (ArrayList) member_hash [name];
-
+                       
                        if (applicable == null)
                                return MemberList.Empty;
 
@@ -1238,8 +1346,9 @@ namespace Mono.CSharp {
                        // search, we restart in method-only search mode if the first match is
                        // a method.  This ensures that we return a MemberInfo with the correct
                        // ReflectedType for inherited methods.
-                       if (do_method_search && (list.Count > 0))
+                       if (do_method_search && (list.Count > 0)){
                                return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
+                       }
 
                        return new MemberList (list);
                }