+ if (oa != null)
+ 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 (TypeManager.HasElementType (p))
+ 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;