[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