[Mono-dev] [PATCH] Friend access for class members

Carlos Alberto Cortez calberto.cortez at gmail.com
Fri Oct 28 08:53:39 EDT 2005


Hey

> >>
> >>+        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.

Ok, then lemme remove that static element. BTW, 1726 is being reported
already ;-)

I will commit if you don't mind (I will add the test for 1725 as soon as
I find it ;-) )

Carlos.

> 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