[Mono-dev] [PATCH] Friend access for class members
Marek Safar
marek.safar at seznam.cz
Fri Oct 28 10:37:59 EDT 2005
Hello,
>>My comments.
>>
>>+ foreach (object o in attrs) {
>>+ InternalsVisibleToAttribute attr = o as
>>InternalsVisibleToAttribute;
>>
>>I think you can use InternalsVisibleToAttribute directly in foreach
>>
>>+ static string this_fullname;
>>+
>>+ static void Error_FriendAccessNameNotMatching (string other_name)
>>+ {
>>+ if (this_fullname == null)
>>+ this_fullname = CodeGen.Assembly.Name.FullName;
>>+
>>+ Report.Error (281, "Friend access was granted to `" + other_name +
>>+ "', but the output assembly is named `" + this_fullname +
>>+ "'. Try adding a reference to `" + other_name +
>>+ "' or change the output assembly name to match it.");
>>+ }
>>
>>1. Do you really need this `string this_fullname'
>>
>>
>
>Well, every time we access to AssemblyName.FullName, a new string is
>created. I know keeping this temporary string could be a little ugly, so
>I created this method.
>
>
I think it is not worthwhile as this is used only when multiple errors
occur.
It would be nice to implement errors 1725 and 1726 as well.
Marek
>
>
>>2. Please don't end error message with '.'
>>3. Please use "bla `{0}' bla" syntax, it is easier to read.
>>
>>
>
>Ok, fixed the styles of the error messages.
>
>Carlos.
>
>
>
>>Marek
>>
>>
>>
>>
>>>I forgot to attach the patch ;-)
>>>
>>>Carlos.
>>>
>>>
>>>El vie, 28-10-2005 a las 16:23 +0530, Raja R Harinath escribió:
>>>
>>>
>>>
>>>
>>>>Hi,
>>>>
>>>>Carlos Alberto Cortez <calberto.cortez at gmail.com> writes:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>The attached patch implements friend access for class members (methods,
>>>>>properties, fields).
>>>>>
>>>>>I'm not including the type-check section, since that part will be
>>>>>modified (next merge to gmcs) and I'm waiting for that to happen.
>>>>>However, that change should be small (I will send the patch).
>>>>>
>>>>>
>>>>>
>>>>>
>>>>I have completed the merge of the relevant parts. Please post an
>>>>updated patch.
>>>>
>>>>Meanwhile, I have some comments:
>>>>
>>>>[snip]
>>>>
>>>>
>>>>
>>>>
>>>>>@@ -2646,25 +2726,38 @@
>>>>> MethodBase mb = (MethodBase) m;
>>>>> MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
>>>>>
>>>>>+ if (ma == MethodAttributes.Public)
>>>>>+ return true;
>>>>>
>>>>>
>>>>>
>>>>>
>>>>Ok.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> if (ma == MethodAttributes.Private)
>>>>> return private_ok ||
>>>>> IsPrivateAccessible (invocation_type, m.DeclaringType) ||
>>>>> IsNestedChildOf (invocation_type, m.DeclaringType);
>>>>>
>>>>>- if (invocation_assembly == mb.DeclaringType.Assembly) {
>>>>>+ if (invocation_assembly == mb.DeclaringType.Assembly)
>>>>> if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
>>>>> return true;
>>>>>- } else {
>>>>>- if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
>>>>>- return false;
>>>>>
>>>>>
>>>>>
>>>>>
>>>>I would retain the old code, and change the check to:
>>>>
>>>> if (invocation_assembly == mb.DeclaringType.Assembly ||
>>>> TypeManager.InternalsVisibleTo (invocation_assembly, mb.DeclaringType.Assembly))
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>+
>>>>>+ if (ma == MethodAttributes.Family ||
>>>>>+ ma == MethodAttributes.FamANDAssem ||
>>>>>+ ma == MethodAttributes.FamORAssem) {
>>>>>+ if (!CheckValidFamilyAccess (mb.IsStatic, m)) {
>>>>>+ if (ma == MethodAttributes.Family || ma == MethodAttributes.FamANDAssem)
>>>>>+ return false;
>>>>>+ } else {
>>>>>+ // We are valid
>>>>>+ if (ma == MethodAttributes.Family || ma == MethodAttributes.FamORAssem)
>>>>>+ return true;
>>>>>+
>>>>>+ // Check for FamANDAssem
>>>>>+ if (invocation_assembly == mb.DeclaringType.Assembly)
>>>>>+ return true;
>>>>>+ }
>>>>> }
>>>>>- if (ma == MethodAttributes.Family ||
>>>>>- ma == MethodAttributes.FamANDAssem ||
>>>>>- ma == MethodAttributes.FamORAssem)
>>>>>- return CheckValidFamilyAccess (mb.IsStatic, m);
>>>>>
>>>>>
>>>>>
>>>>>
>>>>I don't like this too much. I'd much rather keep the old code.
>>>>
>>>>- Hari
>>>>
>>>>
>>>>------------------------------------------------------------------------
>>>>
>>>>Index: typemanager.cs
>>>>===================================================================
>>>>--- typemanager.cs (revisión: 52315)
>>>>+++ typemanager.cs (copia de trabajo)
>>>>@@ -252,6 +252,8 @@
>>>> static Hashtable fieldbuilders_to_fields;
>>>> static Hashtable fields;
>>>>
>>>>+ static PtrHashtable assembly_internals_vis_attrs;
>>>>+
>>>> struct Signature {
>>>> public string name;
>>>> public Type [] args;
>>>>@@ -274,6 +276,8 @@
>>>> priv_fields_events = null;
>>>>
>>>> type_hash = null;
>>>>+
>>>>+ assembly_internals_vis_attrs = null;
>>>>
>>>> CleanUpGenerics ();
>>>> TypeHandle.CleanUp ();
>>>>@@ -375,6 +379,8 @@
>>>> fieldbuilders_to_fields = new Hashtable ();
>>>> fields = new Hashtable ();
>>>> type_hash = new DoubleHash ();
>>>>+
>>>>+ assembly_internals_vis_attrs = new PtrHashtable ();
>>>>
>>>> InitGenerics ();
>>>> }
>>>>@@ -1654,6 +1660,80 @@
>>>> return false;
>>>> }
>>>>
>>>>+ //
>>>>+ // Checks whether `extern_type' is friend of the output assembly
>>>>+ //
>>>>+ public static bool IsFriendAssembly (Assembly assembly)
>>>>+ {
>>>>+ if (assembly_internals_vis_attrs.Contains (assembly))
>>>>+ return (bool)(assembly_internals_vis_attrs [assembly]);
>>>>+
>>>>+ object [] attrs = assembly.GetCustomAttributes (internals_visible_attr_type, false);
>>>>+ if (attrs.Length == 0) {
>>>>+ AddFriendAssembly (assembly, false);
>>>>+ return false;
>>>>+ }
>>>>+
>>>>+ AssemblyName this_name = CodeGen.Assembly.Name;
>>>>+ byte [] this_token = this_name.GetPublicKeyToken ();
>>>>+ bool is_friend = false;
>>>>+ foreach (object o in attrs) {
>>>>+ InternalsVisibleToAttribute attr = o as InternalsVisibleToAttribute;
>>>>+ if (attr.AssemblyName == null || attr.AssemblyName.Length == 0)
>>>>+ continue;
>>>>+
>>>>+ AssemblyName aname = null;
>>>>+ try {
>>>>+ aname = new AssemblyName (attr.AssemblyName);
>>>>+ } catch (FileLoadException) {
>>>>+ } catch (ArgumentException) {
>>>>+ }
>>>>+
>>>>+ if (aname == null || aname.Name != this_name.Name)
>>>>+ continue;
>>>>+
>>>>+ byte [] key_token = aname.GetPublicKeyToken ();
>>>>+ if (key_token != null) {
>>>>+ if (this_token == null) {
>>>>+ // Same name, but key token is null
>>>>+ Error_FriendAccessNameNotMatching (aname.FullName);
>>>>+ break;
>>>>+ }
>>>>+
>>>>+ if (!CompareKeyTokens (this_token, key_token))
>>>>+ continue;
>>>>+ }
>>>>+
>>>>+ is_friend = true;
>>>>+ break;
>>>>+ }
>>>>+
>>>>+ AddFriendAssembly (assembly, is_friend);
>>>>+ return is_friend;
>>>>+ }
>>>>+
>>>>+ static bool CompareKeyTokens (byte [] token1, byte [] token2)
>>>>+ {
>>>>+ for (int i = 0; i < token1.Length; i++)
>>>>+ if (token1 [i] != token2 [i])
>>>>+ return false;
>>>>+
>>>>+ return true;
>>>>+ }
>>>>+
>>>>+ static string this_fullname;
>>>>+
>>>>+ static void Error_FriendAccessNameNotMatching (string other_name)
>>>>+ {
>>>>+ if (this_fullname == null)
>>>>+ this_fullname = CodeGen.Assembly.Name.FullName;
>>>>+
>>>>+ Report.Error (281, "Friend access was granted to `" + other_name +
>>>>+ "', but the output assembly is named `" + this_fullname +
>>>>+ "'. Try adding a reference to `" + other_name +
>>>>+ "' or change the output assembly name to match it.");
>>>>+ }
>>>>+
>>>> //
>>>> // Do the right thing when returning the element type of an
>>>> // array type based on whether we are compiling corlib or not
>>>>@@ -2478,12 +2558,16 @@
>>>> MethodBase mb = (MethodBase) m;
>>>> MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
>>>>
>>>>+ if (ma == MethodAttributes.Public)
>>>>+ return true;
>>>>+
>>>> if (ma == MethodAttributes.Private)
>>>> return private_ok ||
>>>> IsPrivateAccessible (invocation_type, m.DeclaringType) ||
>>>> IsNestedChildOf (invocation_type, m.DeclaringType);
>>>>
>>>>- if (invocation_assembly == mb.DeclaringType.Assembly) {
>>>>+ if (invocation_assembly == mb.DeclaringType.Assembly ||
>>>>+ TypeManager.IsFriendAssembly (mb.DeclaringType.Assembly)) {
>>>> if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
>>>> return true;
>>>> } else {
>>>>@@ -2491,25 +2575,24 @@
>>>> return false;
>>>> }
>>>>
>>>>- if (ma == MethodAttributes.Family ||
>>>>- ma == MethodAttributes.FamANDAssem ||
>>>>- ma == MethodAttributes.FamORAssem)
>>>>- return CheckValidFamilyAccess (mb.IsStatic, m);
>>>>-
>>>>- // Public.
>>>>- return true;
>>>>+ // Family, FamORAssem or FamANDAssem
>>>>+ return CheckValidFamilyAccess (mb.IsStatic, m);
>>>> }
>>>>
>>>> if (m is FieldInfo){
>>>> FieldInfo fi = (FieldInfo) m;
>>>> FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
>>>>
>>>>+ if (fa == FieldAttributes.Public)
>>>>+ return true;
>>>>+
>>>> if (fa == FieldAttributes.Private)
>>>> return private_ok ||
>>>> IsPrivateAccessible (invocation_type, m.DeclaringType) ||
>>>> IsNestedChildOf (invocation_type, m.DeclaringType);
>>>>
>>>>- if (invocation_assembly == fi.DeclaringType.Assembly) {
>>>>+ if (invocation_assembly == fi.DeclaringType.Assembly ||
>>>>+ TypeManager.IsFriendAssembly (fi.DeclaringType.Assembly)) {
>>>> if (fa == FieldAttributes.Assembly || fa == FieldAttributes.FamORAssem)
>>>> return true;
>>>> } else {
>>>>@@ -2517,13 +2600,8 @@
>>>> return false;
>>>> }
>>>>
>>>>- if (fa == FieldAttributes.Family ||
>>>>- fa == FieldAttributes.FamANDAssem ||
>>>>- fa == FieldAttributes.FamORAssem)
>>>>- return CheckValidFamilyAccess (fi.IsStatic, m);
>>>>-
>>>>- // Public.
>>>>- return true;
>>>>+ // Family, FamORAssem or FamANDAssem
>>>>+ return CheckValidFamilyAccess (fi.IsStatic, m);
>>>> }
>>>>
>>>> //
>>>>@@ -2784,6 +2862,11 @@
>>>> }
>>>> return false;
>>>> }
>>>>+
>>>>+ static void AddFriendAssembly (Assembly assembly, bool is_friend)
>>>>+ {
>>>>+ assembly_internals_vis_attrs.Add (assembly, is_friend);
>>>>+ }
>>>>
>>>>#endregion
>>>>
>>>>Index: namespace.cs
>>>>===================================================================
>>>>--- namespace.cs (revisión: 52314)
>>>>+++ namespace.cs (copia de trabajo)
>>>>@@ -112,12 +112,17 @@
>>>> if (t.IsPointer)
>>>> throw new InternalErrorException ("Use GetPointerType() to get a pointer");
>>>>
>>>>+
>>>> TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
>>>>+ if (ta == TypeAttributes.NestedPrivate)
>>>>+ return null;
>>>>+
>>>> if (ta == TypeAttributes.NotPublic ||
>>>>- ta == TypeAttributes.NestedPrivate ||
>>>>- ta == TypeAttributes.NestedAssembly ||
>>>>- ta == TypeAttributes.NestedFamANDAssem)
>>>>- return null;
>>>>+ ta == TypeAttributes.NestedAssembly ||
>>>>+ /*ta == TypeAttributes.NestedFamORAssem ||*/
>>>>+ ta == TypeAttributes.NestedFamANDAssem)
>>>>+ if (!TypeManager.IsFriendAssembly (t.Assembly))
>>>>+ return null;
>>>>
>>>> return t;
>>>> }
>>>>Index: ecore.cs
>>>>===================================================================
>>>>--- ecore.cs (revisión: 52315)
>>>>+++ ecore.cs (copia de trabajo)
>>>>@@ -156,6 +156,9 @@
>>>>
>>>> must_do_cs1540_check = false; // by default we do not check for this
>>>>
>>>>+ if (ma == MethodAttributes.Public)
>>>>+ return true;
>>>>+
>>>> //
>>>> // If only accessible to the current class or children
>>>> //
>>>>@@ -163,7 +166,8 @@
>>>> return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
>>>> TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
>>>>
>>>>- if (mi.DeclaringType.Assembly == invocation_type.Assembly) {
>>>>+ if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
>>>>+ TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
>>>> if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
>>>> return true;
>>>> } else {
>>>>@@ -173,18 +177,12 @@
>>>>
>>>> // Family and FamANDAssem require that we derive.
>>>> // FamORAssem requires that we derive if in different assemblies.
>>>>- if (ma == MethodAttributes.Family ||
>>>>- ma == MethodAttributes.FamANDAssem ||
>>>>- ma == MethodAttributes.FamORAssem) {
>>>>- if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
>>>>- return false;
>>>>+ if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
>>>>+ return false;
>>>>
>>>>- if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
>>>>- must_do_cs1540_check = true;
>>>>+ if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
>>>>+ must_do_cs1540_check = true;
>>>>
>>>>- return true;
>>>>- }
>>>>-
>>>> return true;
>>>> }
>>>>
>>>>Index: decl.cs
>>>>===================================================================
>>>>--- decl.cs (revisión: 52314)
>>>>+++ decl.cs (copia de trabajo)
>>>>@@ -925,7 +925,8 @@
>>>> //
>>>> // This test should probably use the declaringtype.
>>>> //
>>>>- return check_type.Assembly == TypeBuilder.Assembly;
>>>>+ return check_type.Assembly == TypeBuilder.Assembly ||
>>>>+ TypeManager.IsFriendAssembly (check_type.Assembly);
>>>>
>>>> case TypeAttributes.NestedPublic:
>>>> return true;
>>>>@@ -940,15 +941,18 @@
>>>> return FamilyAccessible (tb, check_type);
>>>>
>>>> case TypeAttributes.NestedFamANDAssem:
>>>>- return (check_type.Assembly == tb.Assembly) &&
>>>>+ return ((check_type.Assembly == tb.Assembly) ||
>>>>+ TypeManager.IsFriendAssembly (check_type.Assembly)) &&
>>>> FamilyAccessible (tb, check_type);
>>>>
>>>> case TypeAttributes.NestedFamORAssem:
>>>> return (check_type.Assembly == tb.Assembly) ||
>>>>- FamilyAccessible (tb, check_type);
>>>>+ FamilyAccessible (tb, check_type) ||
>>>>+ TypeManager.IsFriendAssembly (check_type.Assembly);
>>>>
>>>> case TypeAttributes.NestedAssembly:
>>>>- return check_type.Assembly == tb.Assembly;
>>>>+ return check_type.Assembly == tb.Assembly ||
>>>>+ TypeManager.IsFriendAssembly (check_type.Assembly);
>>>> }
>>>>
>>>> Console.WriteLine ("HERE: " + check_attr);
>>>>
>>>>
>>>>------------------------------------------------------------------------
>>>>
>>>>_______________________________________________
>>>>Mono-devel-list mailing list
>>>>Mono-devel-list at lists.ximian.com
>>>>http://lists.ximian.com/mailman/listinfo/mono-devel-list
>>>>
>>>>
>>>>
>>>>
>
>
>
>
More information about the Mono-devel-list
mailing list