[Mono-dev] [Patch] Extern alias (with modifications)

Marek Safar marek.safar at seznam.cz
Thu Oct 6 05:30:16 EDT 2005


Hello Carlos,

Do you have tests for this? I am expecially wondering about CS1679, CS1680.

BTW: Hari's comments are very good.

Marek

>Hey,
>
>I applied the corrections made by Hari and all my tests are working
>fine. 
>
>Comments and suggestions are welcome.
>
>Carlos.
>  
>
>------------------------------------------------------------------------
>
>Index: typemanager.cs
>===================================================================
>--- typemanager.cs	(revisión: 51315)
>+++ typemanager.cs	(copia de trabajo)
>@@ -215,6 +215,8 @@
> 	// </remarks>
> 	static Assembly [] assemblies;
> 
>+	static Hashtable external_aliases;
>+
> 	// <remarks>
> 	//  Keeps a list of modules. We used this to do lookups
> 	//  on the module using GetType -- needed for arrays
>@@ -278,6 +280,7 @@
> 		// Lets get everything clean so that we can collect before generating code
> 		assemblies = null;
> 		modules = null;
>+		external_aliases = null;
> 		builder_to_declspace = null;
> 		builder_to_member_cache = null;
> 		builder_to_ifaces = null;
>@@ -379,6 +382,7 @@
> 		assemblies = new Assembly [0];
> 		modules = null;
> 		
>+		external_aliases = new Hashtable ();
> 		builder_to_declspace = new PtrHashtable ();
> 		builder_to_member_cache = new PtrHashtable ();
> 		builder_to_method = new PtrHashtable ();
>@@ -504,11 +508,22 @@
> 		assemblies = n;
> 	}
> 
>+	public static void AddExternAlias (string alias, Assembly a)
>+	{
>+		// Keep the new as the chosen one
>+		external_aliases [alias] = a;
>+	}
>+
>         public static Assembly [] GetAssemblies ()
>         {
>                 return assemblies;
>         }
> 
>+	public static Assembly GetExternAlias (string alias)
>+	{
>+		return (Assembly) external_aliases [alias];
>+	}
>+
> 	/// <summary>
> 	///  Registers a module builder to lookup types from
> 	/// </summary>
>@@ -578,60 +593,33 @@
> 		return (Type) ret;
> 	}
> 
>-	public static Type LookupTypeReflection (string name, Location loc)
>+	public static Type LookupTypeInModules (string name)
> 	{
>-		Type found_type = null;
>-
>-		foreach (Assembly a in assemblies) {
>-			Type t = a.GetType (name);
>-			if (t == null)
>-				continue;
>-
>-			if (t.IsPointer)
>-				throw new InternalErrorException ("Use GetPointerType() to get a pointer");
>-
>-			TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
>-			if (ta != TypeAttributes.NotPublic && ta != TypeAttributes.NestedPrivate &&
>-				ta != TypeAttributes.NestedAssembly && ta != TypeAttributes.NestedFamANDAssem) {
>-				if (found_type == null) {
>-					found_type = t;
>-					continue;
>-				}
>-
>-				Report.SymbolRelatedToPreviousError (found_type);
>-				Report.SymbolRelatedToPreviousError (t);
>-				Report.Error (433, loc, "The imported type `{0}' is defined multiple times", name);
>-				return found_type;
>-			}
>-		}
>-
> 		foreach (Module mb in modules) {
> 			Type t = mb.GetType (name);
>-			if (t == null)
>-				continue;
>-			
>-			if (found_type == null) {
>-				found_type = t;
>-				continue;
>-			}
>-
>-			Report.SymbolRelatedToPreviousError (t);
>-			Report.SymbolRelatedToPreviousError (found_type);
>-			Report.Warning (436, 2, loc, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
>-				TypeManager.CSharpName (t));
>-			return t;
>+			if (t != null)
>+				return t;
> 		}
> 
>-		return found_type;
>+		return null;
> 	}
>+	
>+	//
>+	// We use this for retrieving GetNamespaces method if avalaible
>+	//
>+	static MethodInfo assembly_get_namespaces;
> 
> 	/// <summary>
> 	///   Computes the namespaces that we import from the assemblies we reference.
> 	/// </summary>
> 	public static void ComputeNamespaces ()
> 	{
>-		MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
>+		if (assembly_get_namespaces == null)
>+			assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
> 
>+		foreach (Assembly assembly in assemblies)
>+			Namespace.Root.AddAssemblyReference (assembly);
>+		
> 		Hashtable cache = null;
> 
> 		//
>@@ -682,8 +670,43 @@
> 				cache.Add (ns, null);
> 			}
> 		}
>+
> 	}
> 
>+	public static Namespace ComputeNamespacesForAlias (string name)
>+	{
>+		Assembly assembly = (Assembly) external_aliases [name];
>+		if (assembly == null)
>+			return null;
>+		
>+		if (assembly_get_namespaces == null)
>+			assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
>+		
>+		Namespace retval = Namespace.DefineRootNamespace (name, assembly);
>+		if (assembly_get_namespaces != null) {
>+			string [] namespaces = (string []) assembly_get_namespaces.Invoke (assembly, null);
>+			foreach (string ns in namespaces) {
>+				if (ns.Length == 0)
>+					continue;
>+				
>+				retval.GetNamespace (ns, true);
>+			}
>+		} else {
>+			Hashtable alias_cache = new Hashtable ();
>+			alias_cache.Add ("", null);
>+			foreach (Type t in assembly.GetExportedTypes ()) {
>+				string ns = t.Namespace;
>+				if (ns == null || alias_cache.Contains (ns))
>+					continue;
>+
>+				retval.GetNamespace (ns, true);
>+				alias_cache.Add (ns, null);
>+			}
>+		}
>+
>+		return retval;
>+	}
>+
> 	/// <summary>
> 	/// Fills static table with exported types from all referenced assemblies.
> 	/// This information is required for CLS Compliance tests.
>Index: namespace.cs
>===================================================================
>--- namespace.cs	(revisión: 51315)
>+++ namespace.cs	(copia de trabajo)
>@@ -9,9 +9,101 @@
> using System;
> using System.Collections;
> using System.Collections.Specialized;
>+using System.Reflection;
> 
> namespace Mono.CSharp {
> 
>+	public class RootNamespace : Namespace
>+	{
>+		Assembly referenced_assembly;
>+
>+		public RootNamespace (Assembly assembly) : base (null, String.Empty)
>+		{
>+			this.referenced_assembly = assembly;
>+			this.root = this;
>+		}
>+
>+		public virtual Type LookupTypeReflection (string name, Location loc)
>+		{
>+			Console.WriteLine ("Looking for type = {0} in assembly = {1}", name, referenced_assembly.FullName);
>+			Type t = referenced_assembly.GetType (name);
>+			if (t == null)
>+				return null;
>+
>+			if (t.IsPointer)
>+				throw new InternalErrorException ("Use GetPointerType() to get a pointer");
>+			
>+			TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
>+			if (ta != TypeAttributes.NotPublic && ta != TypeAttributes.NestedPrivate &&
>+					ta != TypeAttributes.NestedAssembly && ta != TypeAttributes.NestedFamANDAssem)
>+				return t;
>+
>+			return null;
>+		}
>+
>+	}
>+
>+	public class GlobalRootNamespace : RootNamespace
>+	{
>+		Assembly [] assemblies;
>+		
>+		public GlobalRootNamespace () : base (null)
>+		{
>+			assemblies = new Assembly [0];
>+		}
>+
>+		public void AddAssemblyReference (Assembly assembly)
>+		{
>+			Assembly [] tmp = new Assembly [assemblies.Length + 1];
>+			Array.Copy (assemblies, 0, tmp, 0, assemblies.Length);
>+			tmp [assemblies.Length] = assembly;
>+
>+			assemblies = tmp;
>+		}
>+
>+		public override Type LookupTypeReflection (string name, Location loc)
>+		{
>+			Type found_type = null;
>+		
>+			foreach (Assembly a in assemblies) {
>+				Type t = a.GetType (name);
>+				if (t == null)
>+					continue;
>+				
>+				if (t.IsPointer)
>+					throw new InternalErrorException ("Use GetPointerType() to get a pointer");
>+			
>+				TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
>+				if (ta != TypeAttributes.NotPublic && ta != TypeAttributes.NestedPrivate &&
>+						ta != TypeAttributes.NestedAssembly && ta != TypeAttributes.NestedFamANDAssem) {
>+					if (found_type == null) {
>+						found_type = t;
>+						continue;
>+					}
>+				
>+					Report.SymbolRelatedToPreviousError (found_type);
>+					Report.SymbolRelatedToPreviousError (t);
>+					Report.Error (433, loc, "The imported type `{0}' is defined multiple times", name);
>+					return found_type;
>+				}
>+			}
>+
>+			Type t2 = TypeManager.LookupTypeInModules (name);
>+			if (t2 != null) {
>+				if (found_type != null) {
>+					Report.SymbolRelatedToPreviousError (t2);
>+					Report.SymbolRelatedToPreviousError (found_type);
>+					Report.Warning (436, 2, loc, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
>+							TypeManager.CSharpName (t2));
>+				}
>+
>+				return t2;
>+			}
>+
>+			return found_type;
>+		}
>+	}
>+
> 	/// <summary>
> 	///   Keeps track of the namespaces defined in the C# code.
> 	///
>@@ -21,6 +113,7 @@
> 	public class Namespace : FullNamedExpression {
> 		static ArrayList all_namespaces;
> 		static Hashtable namespaces_map;
>+		static Hashtable root_namespaces;
> 		
> 		Namespace parent;
> 		string fullname;
>@@ -28,10 +121,11 @@
> 		Hashtable namespaces;
> 		IDictionary declspaces;
> 		Hashtable cached_types;
>+		protected RootNamespace root;
> 
> 		public readonly MemberName MemberName;
> 
>-		public static Namespace Root;
>+		public static GlobalRootNamespace Root;
> 
> 		static Namespace ()
> 		{
>@@ -42,8 +136,9 @@
> 		{
> 			all_namespaces = new ArrayList ();
> 			namespaces_map = new Hashtable ();
>+			root_namespaces = new Hashtable ();
> 
>-			Root = new Namespace (null, "");
>+			Root = new GlobalRootNamespace ();
> 		}
> 
> 		/// <summary>
>@@ -60,6 +155,12 @@
> 
> 			this.parent = parent;
> 
>+			if (parent != null)
>+				if (parent is RootNamespace)
>+					this.root = parent as RootNamespace;
>+				else
>+					this.root = parent.root;
>+			
> 			string pname = parent != null ? parent.Name : "";
> 				
> 			if (pname == "")
>@@ -81,10 +182,12 @@
> 			namespaces = new Hashtable ();
> 			cached_types = new Hashtable ();
> 
>-			all_namespaces.Add (this);
>-			if (namespaces_map.Contains (fullname))
>-				return;
>-			namespaces_map [fullname] = true;
>+			if (this.root == Root) {
>+				all_namespaces.Add (this);
>+				if (namespaces_map.Contains (fullname))
>+					return;
>+				namespaces_map [fullname] = true;
>+			}
> 		}
> 
> 		public override Expression DoResolve (EmitContext ec)
>@@ -138,6 +241,16 @@
> 			return Root.GetNamespace (name, create);
> 		}
> 
>+		public static RootNamespace DefineRootNamespace (string name, Assembly assembly)
>+		{
>+			RootNamespace retval = (RootNamespace) root_namespaces [name];
>+			if (retval != null)
>+				return retval;
>+
>+			retval = new RootNamespace (assembly);
>+			return retval;
>+		}
>+
> 		TypeExpr LookupType (string name, Location loc)
> 		{
> 			if (cached_types.Contains (name))
>@@ -161,7 +274,7 @@
> 				}
> 			}
> 			string lookup = t != null ? t.FullName : (fullname == "" ? name : fullname + "." + name);
>-			Type rt = TypeManager.LookupTypeReflection (lookup, loc);
>+			Type rt = root.LookupTypeReflection (lookup, loc);
> 			if (t == null)
> 				t = rt;
> 
>@@ -256,6 +369,7 @@
> 		Hashtable aliases;
> 		ArrayList using_clauses;
> 		public bool DeclarationFound = false;
>+		public bool UsingFound;
> 
> 		//
> 		// This class holds the location where a using definition is
>@@ -304,24 +418,34 @@
> 			}
> 		}
> 
>-		public class AliasEntry {
>+		public abstract class AliasEntry {
> 			public readonly string Name;
> 			public readonly Expression Alias;
> 			public readonly NamespaceEntry NamespaceEntry;
> 			public readonly Location Location;
> 			
>-			public AliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc)
>+			protected AliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc)
> 			{
> 				Name = name;
>-				Alias = alias.GetTypeExpression ();
>+				Alias = alias != null ? alias.GetTypeExpression () : null;
> 				NamespaceEntry = entry;
> 				Location = loc;
> 			}
>+			
>+			protected FullNamedExpression resolved;
> 
>-			FullNamedExpression resolved;
>+			public abstract FullNamedExpression Resolve ();
>+		}
> 
>-			public FullNamedExpression Resolve ()
>+		public class LocalAliasEntry : AliasEntry
>+		{
>+			public LocalAliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc) :
>+				base (entry, name, alias, loc)
> 			{
>+			}
>+
>+			public override FullNamedExpression Resolve ()
>+			{
> 				if (resolved != null)
> 					return resolved;
> 
>@@ -334,6 +458,24 @@
> 			}
> 		}
> 
>+		public class ExternAliasEntry : AliasEntry 
>+		{
>+			public ExternAliasEntry (NamespaceEntry entry, string name, Location loc) :
>+				base (entry, name, null, loc)
>+			{
>+			}
>+
>+			public override FullNamedExpression Resolve ()
>+			{
>+				if (resolved != null)
>+					return resolved;
>+
>+				resolved = TypeManager.ComputeNamespacesForAlias (Name);
>+				
>+				return resolved;
>+			}
>+		}
>+
> 		public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, Location loc)
> 		{
> 			this.parent = parent;
>@@ -431,6 +573,7 @@
> 
> 			UsingEntry ue = new UsingEntry (Doppelganger, name, loc);
> 			using_clauses.Add (ue);
>+			UsingFound = true;
> 		}
> 
> 		public void UsingAlias (string name, MemberName alias, Location loc)
>@@ -456,9 +599,36 @@
> 				Report.Warning (440, loc, "An alias named `global' will not be used when resolving 'global::';" +
> 					" the global namespace will be used instead");
> 
>-			aliases [name] = new AliasEntry (Doppelganger, name, alias, loc);
>+			aliases [name] = new LocalAliasEntry (Doppelganger, name, alias, loc);
>+			UsingFound = true;
> 		}
> 
>+		public void UsingExternalAlias (string name, Location loc)
>+		{
>+			if (UsingFound || DeclarationFound) {
>+				Report.Error (439, loc, "An extern alias declaration must precede all other elements");
>+				return;
>+			}
>+			
>+			if (aliases == null)
>+				aliases = new Hashtable ();
>+			
>+			if (aliases.Contains (name)) {
>+				AliasEntry ae = (AliasEntry) aliases [name];
>+				Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
>+				Report.Error (1537, loc, "The using alias `" + name +
>+					      "' appeared previously in this namespace");
>+				return;
>+			}
>+
>+			if (name == "global") {
>+				Report.Error (1681, loc, "You cannot redefine the global extern alias");
>+				return;
>+			}
>+
>+			aliases [name] = new ExternAliasEntry (Doppelganger, name, loc);
>+		}
>+
> 		public FullNamedExpression LookupNamespaceOrType (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
> 		{
> 			// Precondition: Only simple names (no dots) will be looked up with this function.
>@@ -641,7 +811,12 @@
> 				foreach (DictionaryEntry de in aliases) {
> 					AliasEntry alias = (AliasEntry) de.Value;
> 					if (alias.Resolve () == null)
>-						Error_NamespaceNotFound (alias.Location, alias.Alias.ToString ());
>+						if (alias is LocalAliasEntry)
>+							Error_NamespaceNotFound (alias.Location, alias.Alias.ToString ());
>+						else if (alias is ExternAliasEntry) {
>+							Report.Error (430, alias.Location, "The extern alias '" + alias.Name +
>+									"' was not specified in a /reference option");
>+						}
> 				}
> 			}
> 		}
>Index: cs-parser.jay
>===================================================================
>--- cs-parser.jay	(revisión: 51315)
>+++ cs-parser.jay	(copia de trabajo)
>@@ -309,10 +309,31 @@
>         ;
>  
> outer_declaration
>-        : using_directive
>+	: extern_alias_directive
>+        | using_directive 
>         | namespace_member_declaration
>         ;
>-  
>+
>+extern_alias_directives
>+	: extern_alias_directive
>+	| extern_alias_directives extern_alias_directive;
>+
>+extern_alias_directive
>+	: EXTERN IDENTIFIER IDENTIFIER SEMICOLON
>+	  {
>+		LocatedToken lt = (LocatedToken) $2;
>+		string s = lt.Value;
>+		if (s != "alias"){
>+			Report.Error (1003, lt.Location, "'alias' expected");
>+		} else if (RootContext.Version == LanguageVersion.ISO_1) {
>+			Report.FeatureIsNotStandardized (lt.Location, "external alias");
>+		} else {
>+			lt = (LocatedToken) $3; 
>+			current_namespace.UsingExternalAlias (lt.Value, lt.Location);
>+		}
>+	  }
>+	;
>+ 
> using_directives
> 	: using_directive 
> 	| using_directives using_directive
>@@ -393,6 +414,7 @@
> 		if (RootContext.Documentation != null)
> 			Lexer.doc_state = XmlCommentState.Allowed;
> 	  }
>+	  opt_extern_alias_directives
> 	  opt_using_directives
> 	  opt_namespace_member_declarations
> 	  CLOSE_BRACE
>@@ -403,6 +425,11 @@
> 	| using_directives
> 	;
> 
>+opt_extern_alias_directives
>+	: /* empty */
>+	| extern_alias_directives
>+	;
>+
> opt_namespace_member_declarations
> 	: /* empty */
> 	| namespace_member_declarations
>Index: driver.cs
>===================================================================
>--- driver.cs	(revisión: 51315)
>+++ driver.cs	(copia de trabajo)
>@@ -42,7 +42,12 @@
> 		//
> 		static ArrayList soft_references;
> 
>+		// 
>+		// External aliases for assemblies.
> 		//
>+		static Hashtable external_aliases;
>+
>+		//
> 		// Modules to be linked
> 		//
> 		static ArrayList modules;
>@@ -305,6 +310,11 @@
> 
> 		static public void LoadAssembly (string assembly, bool soft)
> 		{
>+			LoadAssembly (assembly, null, soft);
>+		}
>+
>+		static public void LoadAssembly (string assembly, string alias, bool soft)
>+		{
> 			Assembly a;
> 			string total_log = "";
> 
>@@ -319,7 +329,11 @@
> 						ass = assembly.Substring (0, assembly.Length - 4);
> 					a = Assembly.Load (ass);
> 				}
>-				TypeManager.AddAssembly (a);
>+				// Extern aliased refs require special handling
>+				if (alias == null)
>+					TypeManager.AddAssembly (a);
>+				else
>+					TypeManager.AddExternAlias (alias, a);
> 
> 			} catch (FileNotFoundException){
> 				foreach (string dir in link_paths){
>@@ -329,7 +343,10 @@
> 
> 					try {
> 						a = Assembly.LoadFrom (full_path);
>-						TypeManager.AddAssembly (a);
>+						if (alias == null)
>+							TypeManager.AddAssembly (a);
>+						else
>+							TypeManager.AddExternAlias (alias, a);
> 						return;
> 					} catch (FileNotFoundException ff) {
> 						total_log += ff.FusionLog;
>@@ -405,6 +422,9 @@
> 
> 			foreach (string r in soft_references)
> 				LoadAssembly (r, true);
>+
>+			foreach (DictionaryEntry entry in external_aliases)
>+				LoadAssembly ((string) entry.Value, (string) entry.Key, false);
> 			
> 			return;
> 		}
>@@ -800,7 +820,25 @@
> 					Environment.Exit (1);
> 				}
> 				
>-				references.Add (args [++i]);
>+				string val = args [++i];
>+				int idx = val.IndexOf ('=');
>+				if (idx > -1) {
>+					string alias = val.Substring (0, idx);
>+					string assembly = val.Substring (idx + 1);
>+					if (assembly.Length == 0) {
>+						Report.Error (1680, "Invalid reference alias '" + alias + "='. Missing filename");
>+						Environment.Exit (1);
>+					}
>+					if (!IsExternAliasValid (alias)) {
>+						Report.Error (1679, "Invalid extern alias for /reference. Alias '" + alias + "' is not a valid identifier");
>+						Environment.Exit (1);
>+					}
>+					external_aliases [alias] = assembly;
>+					val = assembly;
>+					return true;
>+				}
>+
>+				references.Add (val);
> 				return true;
> 				
> 			case "-L":
>@@ -1092,7 +1130,24 @@
> 
> 				string [] refs = value.Split (new char [] { ';', ',' });
> 				foreach (string r in refs){
>-					references.Add (r);
>+					string val = r;
>+					int index = val.IndexOf ("=");
>+					if (index > -1) {
>+						string alias = r.Substring (0, index);
>+						string assembly = r.Substring (index + 1);
>+						if (assembly.Length == 0) {
>+							Report.Error (1680, "Invalid reference alias '" + alias + "='. Missing filename");
>+							Environment.Exit (1);
>+						}
>+						if (!IsExternAliasValid (alias)) {
>+							Report.Error (1679, "Invalid extern alias for /reference. Alias '" + alias + "' is not a valid identifier");
>+							Environment.Exit (1);
>+						}
>+						external_aliases [alias] = assembly;
>+						val = assembly;
>+						return true;
>+					}
>+					references.Add (val);
> 				}
> 				return true;
> 			}
>@@ -1351,6 +1406,28 @@
> 
> 			return new_args;
> 		}
>+
>+		static bool IsExternAliasValid (string identifier)
>+		{
>+			if (identifier.Length == 0)
>+				return false;
>+			if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
>+				return false;
>+
>+			for (int i = 1; i < identifier.Length; i++) {
>+				char c = identifier [i];
>+				if (Char.IsLetter (c) || Char.IsDigit (c))
>+					continue;
>+
>+				UnicodeCategory category = Char.GetUnicodeCategory (c);
>+				if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
>+						category != UnicodeCategory.SpacingCombiningMark ||
>+						category != UnicodeCategory.ConnectorPunctuation)
>+					return false;
>+			}
>+			
>+			return true;
>+		}
> 		
> 		/// <summary>
> 		///    Parses the arguments, and drives the compilation
>@@ -1377,6 +1454,7 @@
> 			encoding = default_encoding;
> 
> 			references = new ArrayList ();
>+			external_aliases = new Hashtable ();
> 			soft_references = new ArrayList ();
> 			modules = new ArrayList ();
> 			link_paths = new ArrayList ();
>  
>
>------------------------------------------------------------------------
>
>_______________________________________________
>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