2 // namespace.cs: Tracks namespaces
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
10 using System.Collections;
11 using System.Collections.Specialized;
12 using System.Reflection;
14 namespace Mono.CSharp {
16 public class RootNamespace : Namespace
18 static MethodInfo get_namespaces_method;
20 Assembly referenced_assembly;
21 Hashtable cached_namespaces;
23 static RootNamespace ()
25 get_namespaces_method = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance | BindingFlags.NonPublic);
29 // We access GlobalRoot here to beautify the code
31 public static GlobalRootNamespace Global {
33 return GlobalRootNamespace.GlobalRoot;
37 public RootNamespace (Assembly assembly) : base (null, String.Empty)
39 this.referenced_assembly = assembly;
40 this.cached_namespaces = new Hashtable ();
41 this.cached_namespaces.Add ("", null);
43 if (this.referenced_assembly != null)
44 ComputeNamespacesForAssembly (this.referenced_assembly);
47 public virtual Type LookupTypeReflection (string name, Location loc)
49 return GetTypeInAssembly (referenced_assembly, name);
52 public virtual void RegisterNamespace (Namespace ns)
57 protected void ComputeNamespacesForAssembly (Assembly assembly)
59 if (get_namespaces_method != null) {
60 string [] namespaces = (string []) get_namespaces_method.Invoke (assembly, null);
61 foreach (string ns in namespaces) {
65 // Method from parent class Namespace
66 GetNamespace (ns, true);
69 //cached_namespaces.Add ("", null);
70 foreach (Type t in assembly.GetExportedTypes ()) {
71 string ns = t.Namespace;
72 if (ns == null || cached_namespaces.Contains (ns))
75 // Method from parent class Namespace
76 GetNamespace (ns, true);
77 cached_namespaces.Add (ns, null);
82 protected Type GetTypeInAssembly (Assembly assembly, string name)
84 Type t = assembly.GetType (name);
89 throw new InternalErrorException ("Use GetPointerType() to get a pointer");
91 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
92 if (ta != TypeAttributes.NotPublic && ta != TypeAttributes.NestedPrivate &&
93 ta != TypeAttributes.NestedAssembly && ta != TypeAttributes.NestedFamANDAssem)
99 protected Hashtable CachedNamespaces {
101 return cached_namespaces;
107 public class GlobalRootNamespace : RootNamespace
109 static ArrayList all_namespaces;
110 static Hashtable namespaces_map;
111 static Hashtable root_namespaces;
112 internal static GlobalRootNamespace GlobalRoot;
114 Assembly [] assemblies;
117 public static void Reset ()
119 all_namespaces = new ArrayList ();
120 namespaces_map = new Hashtable ();
121 root_namespaces = new Hashtable ();
122 GlobalRoot = new GlobalRootNamespace ();
125 static GlobalRootNamespace ()
130 public GlobalRootNamespace () : base (null)
132 assemblies = new Assembly [0];
133 modules = new Module [0];
136 public void AddAssemblyReference (Assembly assembly)
138 Assembly [] tmp = new Assembly [assemblies.Length + 1];
139 Array.Copy (assemblies, 0, tmp, 0, assemblies.Length);
140 tmp [assemblies.Length] = assembly;
143 ComputeNamespacesForAssembly (assembly);
146 public void AddModuleReference (Module module)
148 Module [] tmp = new Module [modules.Length + 1];
149 Array.Copy (modules, 0, tmp, 0, modules.Length);
150 tmp [modules.Length] = module;
154 if (module != CodeGen.Module.Builder)
155 ComputeNamespacesForModule (module);
158 void ComputeNamespacesForModule (Module module)
160 foreach (Type t in module.GetTypes ()) {
161 string ns = t.Namespace;
162 if (ns == null || CachedNamespaces.Contains (ns))
165 GetNamespace (ns, true);
166 CachedNamespaces.Add (ns, null);
170 public override Type LookupTypeReflection (string name, Location loc)
172 Type found_type = null;
174 foreach (Assembly a in assemblies) {
175 Type t = GetTypeInAssembly (a, name);
179 if (found_type == null) {
184 Report.SymbolRelatedToPreviousError (found_type);
185 Report.SymbolRelatedToPreviousError (t);
186 Report.Error (433, loc, "The imported type `{0}' is defined multiple times", name);
191 foreach (Module module in modules) {
192 Type t = module.GetType (name);
196 if (found_type == null) {
201 Report.SymbolRelatedToPreviousError (t);
202 Report.SymbolRelatedToPreviousError (found_type);
203 Report.Warning (436, 2, loc, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
204 TypeManager.CSharpName (t));
211 public override void RegisterNamespace (Namespace child)
213 all_namespaces.Add (child);
214 if (namespaces_map.Contains (child.Name))
216 namespaces_map [child.Name] = true;
219 public static RootNamespace DefineRootNamespace (string name, Assembly assembly)
221 RootNamespace retval = (RootNamespace) root_namespaces [name];
225 retval = new RootNamespace (assembly);
229 public static bool IsNamespace (string name)
231 return namespaces_map [name] != null;
234 public static ArrayList UserDefinedNamespaces {
235 get { return all_namespaces; }
238 public static void VerifyUsingForAll ()
240 foreach (Namespace ns in all_namespaces)
244 public static void DefineNamespacesForAll (SymbolWriter symwriter)
246 foreach (Namespace ns in all_namespaces)
247 ns.DefineNamespaces (symwriter);
250 public override string ToString ()
252 return "Namespace (<root>)";
255 public override string GetSignatureForError ()
263 /// Keeps track of the namespaces defined in the C# code.
265 /// This is an Expression to allow it to be referenced in the
266 /// compiler parse/intermediate tree during name resolution.
268 public class Namespace : FullNamedExpression {
273 Hashtable namespaces;
274 IDictionary declspaces;
275 Hashtable cached_types;
278 public readonly MemberName MemberName;
281 /// Constructor Takes the current namespace and the
282 /// name. This is bootstrapped with parent == null
285 public Namespace (Namespace parent, string name)
287 // Expression members.
288 this.eclass = ExprClass.Namespace;
290 this.loc = Location.Null;
292 this.parent = parent;
295 this.root = parent.root;
297 this.root = this as RootNamespace;
299 if (this.root == null)
300 throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
302 string pname = parent != null ? parent.Name : "";
307 fullname = parent.Name + "." + name;
309 if (fullname == null)
310 throw new InternalErrorException ("Namespace has a null fullname");
312 if (parent != null && parent.MemberName != MemberName.Null)
313 MemberName = new MemberName (
314 parent.MemberName, name, parent.MemberName.Location);
316 MemberName = MemberName.Null;
318 MemberName = new MemberName (name, Location.Null);
320 entries = new ArrayList ();
321 namespaces = new Hashtable ();
322 cached_types = new Hashtable ();
324 root.RegisterNamespace (this);
327 public override Expression DoResolve (EmitContext ec)
332 public override void Emit (EmitContext ec)
334 throw new InternalErrorException ("Expression tree referenced namespace " + fullname + " during Emit ()");
337 public override string GetSignatureForError ()
342 public Namespace GetNamespace (string name, bool create)
344 int pos = name.IndexOf ('.');
349 first = name.Substring (0, pos);
353 ns = (Namespace) namespaces [first];
358 ns = new Namespace (this, first);
359 namespaces.Add (first, ns);
363 ns = ns.GetNamespace (name.Substring (pos + 1), create);
368 TypeExpr LookupType (string name, Location loc)
370 if (cached_types.Contains (name))
371 return cached_types [name] as TypeExpr;
374 if (declspaces != null) {
375 DeclSpace tdecl = declspaces [name] as DeclSpace;
378 // Note that this is not:
380 // t = tdecl.DefineType ()
382 // This is to make it somewhat more useful when a DefineType
383 // fails due to problems in nested types (more useful in the sense
384 // of fewer misleading error messages)
387 t = tdecl.TypeBuilder;
390 string lookup = t != null ? t.FullName : (fullname == "" ? name : fullname + "." + name);
391 Type rt = root.LookupTypeReflection (lookup, loc);
395 TypeExpr te = t == null ? null : new TypeExpression (t, Location.Null);
396 cached_types [name] = te;
400 public FullNamedExpression Lookup (DeclSpace ds, string name, Location loc)
402 Namespace ns = GetNamespace (name, false);
406 TypeExpr te = LookupType (name, loc);
407 if (te == null || !ds.CheckAccessLevel (te.Type))
413 public void AddNamespaceEntry (NamespaceEntry entry)
418 public void AddDeclSpace (string name, DeclSpace ds)
420 if (declspaces == null)
421 declspaces = new HybridDictionary ();
422 declspaces.Add (name, ds);
426 /// Used to validate that all the using clauses are correct
427 /// after we are finished parsing all the files.
429 public void VerifyUsing ()
431 foreach (NamespaceEntry entry in entries)
432 entry.VerifyUsing ();
435 public void DefineNamespaces (SymbolWriter symwriter)
437 foreach (NamespaceEntry entry in entries)
438 entry.DefineNamespace (symwriter);
442 /// The qualified name of the current namespace
445 get { return fullname; }
448 public override string FullName {
449 get { return fullname; }
453 /// The parent of this namespace, used by the parser to "Pop"
454 /// the current namespace declaration
456 public Namespace Parent {
457 get { return parent; }
460 public override string ToString ()
462 return String.Format ("Namespace ({0})", Name);
466 public class NamespaceEntry
469 NamespaceEntry parent, implicit_parent;
473 ArrayList using_clauses;
474 public bool DeclarationFound = false;
475 public bool UsingFound = false;
478 // This class holds the location where a using definition is
479 // done, and whether it has been used by the program or not.
481 // We use this to flag using clauses for namespaces that do not
484 public class UsingEntry {
485 public readonly MemberName Name;
486 readonly Expression Expr;
487 readonly NamespaceEntry NamespaceEntry;
488 readonly Location Location;
490 public UsingEntry (NamespaceEntry entry, MemberName name, Location loc)
493 Expr = name.GetTypeExpression ();
494 NamespaceEntry = entry;
498 internal Namespace resolved;
500 public Namespace Resolve ()
502 if (resolved != null)
505 DeclSpace root = RootContext.Tree.Types;
506 root.NamespaceEntry = NamespaceEntry;
507 FullNamedExpression fne = Expr.ResolveAsTypeStep (root.EmitContext, false);
508 root.NamespaceEntry = null;
511 Error_NamespaceNotFound (Location, Name.ToString ());
515 resolved = fne as Namespace;
516 if (resolved == null) {
517 Report.Error (138, Location,
518 "`{0} is a type not a namespace. A using namespace directive can only be applied to namespaces", Name.ToString ());
524 public abstract class AliasEntry {
525 public readonly string Name;
526 public readonly NamespaceEntry NamespaceEntry;
527 public readonly Location Location;
529 protected AliasEntry (NamespaceEntry entry, string name, Location loc)
532 NamespaceEntry = entry;
536 protected FullNamedExpression resolved;
538 public abstract FullNamedExpression Resolve ();
541 public class LocalAliasEntry : AliasEntry
543 public readonly Expression Alias;
545 public LocalAliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc) :
546 base (entry, name, loc)
548 Alias = alias.GetTypeExpression ();
551 public override FullNamedExpression Resolve ()
553 if (resolved != null)
556 DeclSpace root = RootContext.Tree.Types;
557 root.NamespaceEntry = NamespaceEntry;
558 resolved = Alias.ResolveAsTypeStep (root.EmitContext, false);
559 root.NamespaceEntry = null;
565 public class ExternAliasEntry : AliasEntry
567 public ExternAliasEntry (NamespaceEntry entry, string name, Location loc) :
568 base (entry, name, loc)
572 public override FullNamedExpression Resolve ()
574 if (resolved != null)
577 resolved = TypeManager.ComputeNamespacesForAlias (Name);
578 if (resolved == null) {
579 Report.Error (430, Location, "The extern alias '" + Name +
580 "' was not specified in a /reference option");
587 public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, Location loc)
589 this.parent = parent;
591 this.IsImplicit = false;
595 ns = parent.NS.GetNamespace (name, true);
596 else if (name != null)
597 ns = RootNamespace.Global.GetNamespace (name, true);
599 ns = RootNamespace.Global;
601 ns.AddNamespaceEntry (this);
605 private NamespaceEntry (NamespaceEntry parent, SourceFile file, Namespace ns)
607 this.parent = parent;
609 this.IsImplicit = true;
615 // According to section 16.3.1 (using-alias-directive), the namespace-or-type-name is
616 // resolved as if the immediately containing namespace body has no using-directives.
618 // Section 16.3.2 says that the same rule is applied when resolving the namespace-name
619 // in the using-namespace-directive.
621 // To implement these rules, the expressions in the using directives are resolved using
622 // the "doppelganger" (ghostly bodiless duplicate).
624 NamespaceEntry doppelganger;
625 NamespaceEntry Doppelganger {
627 if (!IsImplicit && doppelganger == null)
628 doppelganger = new NamespaceEntry (ImplicitParent, file, ns);
633 static int next_id = 0;
634 public readonly int ID;
635 public readonly bool IsImplicit;
637 public Namespace NS {
641 public NamespaceEntry Parent {
642 get { return parent; }
645 public NamespaceEntry ImplicitParent {
649 if (implicit_parent == null) {
650 implicit_parent = (parent.NS == ns.Parent)
652 : new NamespaceEntry (parent, file, ns.Parent);
654 return implicit_parent;
659 /// Records a new namespace for resolving name references
661 public void Using (MemberName name, Location loc)
663 if (DeclarationFound){
664 Report.Error (1529, loc, "A using clause must precede all other namespace elements except extern alias declarations");
668 if (name.Equals (ns.MemberName))
671 if (using_clauses == null)
672 using_clauses = new ArrayList ();
674 foreach (UsingEntry old_entry in using_clauses) {
675 if (name.Equals (old_entry.Name)) {
676 if (RootContext.WarningLevel >= 3)
677 Report.Warning (105, loc, "The using directive for `{0}' appeared previously in this namespace", name);
683 UsingEntry ue = new UsingEntry (Doppelganger, name, loc);
684 using_clauses.Add (ue);
687 public void UsingAlias (string name, MemberName alias, Location loc)
689 if (DeclarationFound){
690 Report.Error (1529, loc, "A using clause must precede all other namespace elements except extern alias declarations");
695 aliases = new Hashtable ();
697 if (aliases.Contains (name)) {
698 AliasEntry ae = (AliasEntry)aliases [name];
699 Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
700 Report.Error (1537, loc, "The using alias `" + name +
701 "' appeared previously in this namespace");
705 if (RootContext.Version == LanguageVersion.Default &&
706 name == "global" && RootContext.WarningLevel >= 2)
707 Report.Warning (440, loc, "An alias named `global' will not be used when resolving 'global::';" +
708 " the global namespace will be used instead");
710 aliases [name] = new LocalAliasEntry (Doppelganger, name, alias, loc);
713 public void UsingExternalAlias (string name, Location loc)
715 if (UsingFound || DeclarationFound) {
716 Report.Error (439, loc, "An extern alias declaration must precede all other elements");
721 aliases = new Hashtable ();
723 if (aliases.Contains (name)) {
724 AliasEntry ae = (AliasEntry) aliases [name];
725 Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
726 Report.Error (1537, loc, "The using alias `" + name +
727 "' appeared previously in this namespace");
731 if (name == "global") {
732 Report.Error (1681, loc, "You cannot redefine the global extern alias");
736 aliases [name] = new ExternAliasEntry (Doppelganger, name, loc);
739 public FullNamedExpression LookupNamespaceOrType (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
741 // Precondition: Only simple names (no dots) will be looked up with this function.
742 FullNamedExpression resolved = null;
743 for (NamespaceEntry curr_ns = this; curr_ns != null; curr_ns = curr_ns.ImplicitParent) {
744 if ((resolved = curr_ns.Lookup (ds, name, loc, ignore_cs0104)) != null)
750 static void Error_AmbiguousTypeReference (Location loc, string name, FullNamedExpression t1, FullNamedExpression t2)
752 Report.Error (104, loc, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
753 name, t1.FullName, t2.FullName);
756 // Looks-up a alias named @name in this and surrounding namespace declarations
757 public FullNamedExpression LookupAlias (string name)
759 AliasEntry entry = null;
760 // We use Parent rather than ImplicitParent since we know implicit namespace declarations
761 // cannot have using entries.
762 for (NamespaceEntry n = this; n != null; n = n.Parent) {
763 if (n.aliases == null)
765 entry = n.aliases [name] as AliasEntry;
767 return entry.Resolve ();
772 private FullNamedExpression Lookup (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
775 // Check whether it's in the namespace.
777 FullNamedExpression fne = NS.Lookup (ds, name, loc);
787 if (aliases != null) {
788 AliasEntry entry = aliases [name] as AliasEntry;
790 return entry.Resolve ();
794 // Check using entries.
796 FullNamedExpression match = null;
797 foreach (Namespace using_ns in GetUsingTable ()) {
798 match = using_ns.Lookup (ds, name, loc);
799 if (match == null || !(match is TypeExpr))
803 Error_AmbiguousTypeReference (loc, name, fne, match);
812 // Our cached computation.
813 readonly Namespace [] empty_namespaces = new Namespace [0];
814 Namespace [] namespace_using_table;
815 Namespace [] GetUsingTable ()
817 if (namespace_using_table != null)
818 return namespace_using_table;
820 if (using_clauses == null) {
821 namespace_using_table = empty_namespaces;
822 return namespace_using_table;
825 ArrayList list = new ArrayList (using_clauses.Count);
827 foreach (UsingEntry ue in using_clauses) {
828 Namespace using_ns = ue.Resolve ();
829 if (using_ns == null)
835 namespace_using_table = new Namespace [list.Count];
836 list.CopyTo (namespace_using_table, 0);
837 return namespace_using_table;
840 readonly string [] empty_using_list = new string [0];
842 public void DefineNamespace (SymbolWriter symwriter)
847 parent.DefineNamespace (symwriter);
849 string [] using_list = empty_using_list;
850 if (using_clauses != null) {
851 using_list = new string [using_clauses.Count];
852 for (int i = 0; i < using_clauses.Count; i++)
853 using_list [i] = ((UsingEntry) using_clauses [i]).Name.ToString ();
856 int parent_id = parent != null ? parent.symfile_id : 0;
857 if (file.SourceFileEntry == null)
860 symfile_id = symwriter.DefineNamespace (
861 ns.Name, file.SourceFileEntry, using_list, parent_id);
864 public int SymbolFileID {
865 get { return symfile_id; }
868 static void MsgtryRef (string s)
870 Console.WriteLine (" Try using -r:" + s);
873 static void MsgtryPkg (string s)
875 Console.WriteLine (" Try using -pkg:" + s);
878 public static void Error_NamespaceNotFound (Location loc, string name)
880 Report.Error (246, loc, "The type or namespace name `{0}' could not be found. Are you missing a using directive or an assembly reference?",
884 case "Gtk": case "GtkSharp":
885 MsgtryPkg ("gtk-sharp");
888 case "Gdk": case "GdkSharp":
889 MsgtryPkg ("gdk-sharp");
892 case "Glade": case "GladeSharp":
893 MsgtryPkg ("glade-sharp");
896 case "System.Drawing":
897 case "System.Web.Services":
900 case "System.Windows.Forms":
907 /// Used to validate that all the using clauses are correct
908 /// after we are finished parsing all the files.
910 public void VerifyUsing ()
912 if (using_clauses != null) {
913 foreach (UsingEntry ue in using_clauses)
917 if (aliases != null) {
918 foreach (DictionaryEntry de in aliases) {
919 AliasEntry alias = (AliasEntry) de.Value;
920 if (alias.Resolve () == null)
921 if (alias is LocalAliasEntry) {
922 LocalAliasEntry local = alias as LocalAliasEntry;
923 Error_NamespaceNotFound (local.Location, local.Alias.ToString ());
929 public string GetSignatureForError ()
931 return ns.GetSignatureForError ();
934 public override string ToString ()
936 return ns.ToString ();