2 // namespace.cs: Tracks namespaces
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
10 using System.Collections;
12 namespace Mono.CSharp {
15 /// Keeps track of the namespaces defined in the C# code.
17 public class Namespace {
18 static ArrayList all_namespaces = new ArrayList ();
21 string name, fullname;
26 /// Constructor Takes the current namespace and the
27 /// name. This is bootstrapped with parent == null
30 public Namespace (Namespace parent, string name)
35 string pname = parent != null ? parent.Name : "";
40 fullname = parent.Name + "." + name;
42 entries = new ArrayList ();
43 namespaces = new Hashtable ();
45 all_namespaces.Add (this);
48 public static Namespace Root = new Namespace (null, "");
50 public Namespace GetNamespace (string name, bool create)
52 int pos = name.IndexOf ('.');
57 first = name.Substring (0, pos);
61 ns = (Namespace) namespaces [first];
66 ns = new Namespace (this, first);
67 namespaces.Add (first, ns);
71 ns = ns.GetNamespace (name.Substring (pos + 1), create);
76 public static Namespace LookupNamespace (string name, bool create)
78 return Root.GetNamespace (name, create);
81 public void AddNamespaceEntry (NamespaceEntry entry)
86 static public ArrayList UserDefinedNamespaces {
88 return all_namespaces;
93 /// The qualified name of the current namespace
102 /// The parent of this namespace, used by the parser to "Pop"
103 /// the current namespace declaration
105 public Namespace Parent {
111 public static void DefineNamespaces (SymbolWriter symwriter)
113 foreach (Namespace ns in all_namespaces) {
114 foreach (NamespaceEntry entry in ns.entries)
115 entry.DefineNamespace (symwriter);
120 /// Used to validate that all the using clauses are correct
121 /// after we are finished parsing all the files.
123 public static void VerifyUsing ()
125 foreach (Namespace ns in all_namespaces) {
126 foreach (NamespaceEntry entry in ns.entries)
127 entry.VerifyUsing ();
131 public override string ToString ()
134 return "Namespace (<root>)";
136 return String.Format ("Namespace ({0})", Name);
140 public class NamespaceEntry
143 NamespaceEntry parent, implicit_parent;
147 ArrayList using_clauses;
148 public bool DeclarationFound = false;
151 // This class holds the location where a using definition is
152 // done, and whether it has been used by the program or not.
154 // We use this to flag using clauses for namespaces that do not
157 public class UsingEntry {
158 public readonly string Name;
159 public readonly NamespaceEntry NamespaceEntry;
160 public readonly Location Location;
162 public UsingEntry (NamespaceEntry entry, string name, Location loc)
165 NamespaceEntry = entry;
169 Namespace resolved_ns;
171 public Namespace Resolve ()
173 if (resolved_ns != null)
176 Namespace curr_ns = NamespaceEntry.NS;
177 while ((curr_ns != null) && (resolved_ns == null)) {
178 string full_name = DeclSpace.MakeFQN (curr_ns.Name, Name);
179 resolved_ns = curr_ns.GetNamespace (Name, false);
181 if (resolved_ns == null)
182 curr_ns = curr_ns.Parent;
189 public class AliasEntry {
190 public readonly string Name;
191 public readonly string Alias;
192 public readonly NamespaceEntry NamespaceEntry;
193 public readonly Location Location;
195 public AliasEntry (NamespaceEntry entry, string name, string alias, Location loc)
199 NamespaceEntry = entry;
205 public object Resolve ()
207 if (resolved != null)
210 int pos = Alias.IndexOf ('.');
212 string first = Alias.Substring (0, pos);
215 NamespaceEntry curr_ns = NamespaceEntry;
216 while ((curr_ns != null) && (resolved == null)) {
217 string full_name = DeclSpace.MakeFQN (curr_ns.Name, Alias);
218 resolved = curr_ns.LookupName (Alias);
220 if (resolved == null)
221 curr_ns = curr_ns.Parent;
228 public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name)
229 : this (parent, file, name, false)
232 protected NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, bool is_implicit)
234 this.parent = parent;
236 this.IsImplicit = is_implicit;
239 if (!is_implicit && (parent != null))
240 ns = parent.NS.GetNamespace (name, true);
241 else if (name != null)
242 ns = Namespace.LookupNamespace (name, true);
245 ns.AddNamespaceEntry (this);
247 if ((parent != null) && (parent.NS != ns.Parent))
248 implicit_parent = new NamespaceEntry (parent, file, ns.Parent.Name, true);
250 implicit_parent = parent;
253 static int next_id = 0;
254 public readonly int ID;
255 public readonly bool IsImplicit;
263 public Namespace NS {
269 public NamespaceEntry Parent {
275 public NamespaceEntry ImplicitParent {
277 return implicit_parent;
282 /// Records a new namespace for resolving name references
284 public void Using (string ns, Location loc)
286 if (DeclarationFound){
287 Report.Error (1529, loc, "A using clause must precede all other namespace elements");
294 if (using_clauses == null)
295 using_clauses = new ArrayList ();
297 foreach (UsingEntry old_entry in using_clauses){
298 if (old_entry.Name == ns){
299 Report.Warning (105, loc, "The using directive for '" + ns +
300 "' appeared previously in this namespace");
305 UsingEntry ue = new UsingEntry (this, ns, loc);
306 using_clauses.Add (ue);
309 public void UsingAlias (string alias, string namespace_or_type, Location loc)
312 aliases = new Hashtable ();
314 if (aliases.Contains (alias)){
315 Report.Error (1537, loc, "The using alias `" + alias +
316 "' appeared previously in this namespace");
320 aliases [alias] = new AliasEntry (this, alias, namespace_or_type, loc);
323 protected AliasEntry GetAliasEntry (string alias)
325 AliasEntry entry = null;
328 entry = (AliasEntry) aliases [alias];
329 if (entry == null && Parent != null)
330 entry = Parent.GetAliasEntry (alias);
335 public string LookupAlias (string alias)
337 AliasEntry entry = GetAliasEntry (alias);
342 object resolved = entry.Resolve ();
343 if (resolved == null)
345 else if (resolved is Namespace)
346 return ((Namespace) resolved).Name;
348 return ((Type) resolved).FullName;
351 public object LookupName (string name)
353 Namespace ns = Namespace.LookupNamespace (name, false);
357 int pos = name.IndexOf ('.');
358 AliasEntry alias = null;
360 string first = name.Substring (0, pos);
361 string last = name.Substring (pos + 1);
363 alias = GetAliasEntry (first);
365 return LookupName (DeclSpace.MakeFQN (alias.Alias, last));
368 Type t = TypeManager.LookupType (name);
372 alias = GetAliasEntry (name);
374 return LookupName (alias.Alias);
379 public Namespace[] GetUsingTable ()
381 ArrayList list = new ArrayList ();
383 if (using_clauses == null)
384 return new Namespace [0];
386 foreach (UsingEntry ue in using_clauses) {
387 Namespace using_ns = ue.Resolve ();
388 if (using_ns == null)
394 Namespace[] retval = new Namespace [list.Count];
395 list.CopyTo (retval, 0);
399 public void DefineNamespace (SymbolWriter symwriter)
404 parent.DefineNamespace (symwriter);
407 if (using_clauses != null) {
408 using_list = new string [using_clauses.Count];
409 for (int i = 0; i < using_clauses.Count; i++)
410 using_list [i] = ((UsingEntry) using_clauses [i]).Name;
412 using_list = new string [0];
415 int parent_id = parent != null ? parent.symfile_id : 0;
416 symfile_id = symwriter.DefineNamespace (ns.Name, file, using_list, parent_id);
419 public int SymbolFileID {
425 static void Msgtry (string s)
427 Console.WriteLine (" Try using -r:" + s);
430 protected void error246 (Location loc, string name)
432 if (TypeManager.LookupType (name) != null)
433 Report.Error (138, loc, "The using keyword only lets you specify a namespace, " +
434 "`" + name + "' is a class not a namespace.");
436 Report.Error (246, loc, "The namespace `" + name +
437 "' can not be found (missing assembly reference?)");
440 case "Gtk": case "GtkSharp":
441 Msgtry ("gtk-sharp");
444 case "Gdk": case "GdkSharp":
445 Msgtry ("gdk-sharp");
448 case "Glade": case "GladeSharp":
449 Msgtry ("glade-sharp");
452 case "System.Drawing":
453 Msgtry ("System.Drawing");
456 case "System.Web.Services":
457 Msgtry ("System.Web.Services");
461 Msgtry ("System.Web");
465 Msgtry ("System.Data");
468 case "System.Windows.Forms":
469 Msgtry ("System.Windows.Forms");
476 /// Used to validate that all the using clauses are correct
477 /// after we are finished parsing all the files.
479 public void VerifyUsing ()
481 if (using_clauses != null){
482 foreach (UsingEntry ue in using_clauses){
483 if (ue.Resolve () != null)
486 error246 (ue.Location, ue.Name);
490 if (aliases != null){
491 foreach (DictionaryEntry de in aliases){
492 AliasEntry alias = (AliasEntry) de.Value;
494 if (alias.Resolve () != null)
497 error246 (alias.Location, alias.Alias);
502 public override string ToString ()
504 if (NS == Namespace.Root)
505 return "NamespaceEntry (<root>)";
507 return String.Format ("NamespaceEntry ({0},{1},{2})", Name, IsImplicit, ID);