* TypeTranslator.cs, XmlCustomFormatter.cs: Added support for base64. This
[mono.git] / mcs / mcs / namespace.cs
1 //
2 // namespace.cs: Tracks namespaces
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 using System;
10 using System.Collections;
11
12 namespace Mono.CSharp {
13
14         /// <summary>
15         ///   Keeps track of the namespaces defined in the C# code.
16         /// </summary>
17         public class Namespace {
18                 static ArrayList all_namespaces = new ArrayList ();
19                 static Hashtable namespaces_map = new Hashtable ();
20                 
21                 Namespace parent;
22                 string fullname;
23                 ArrayList entries;
24                 Hashtable namespaces;
25                 Hashtable defined_names;
26
27                 /// <summary>
28                 ///   Constructor Takes the current namespace and the
29                 ///   name.  This is bootstrapped with parent == null
30                 ///   and name = ""
31                 /// </summary>
32                 public Namespace (Namespace parent, string name)
33                 {
34                         this.parent = parent;
35
36                         string pname = parent != null ? parent.Name : "";
37                                 
38                         if (pname == "")
39                                 fullname = name;
40                         else
41                                 fullname = parent.Name + "." + name;
42
43                         entries = new ArrayList ();
44                         namespaces = new Hashtable ();
45                         defined_names = new Hashtable ();
46
47                         all_namespaces.Add (this);
48                         if (namespaces_map.Contains (fullname))
49                                 return;
50                         namespaces_map [fullname] = true;
51                 }
52
53                 public static bool IsNamespace (string name)
54                 {
55                         return namespaces_map [name] != null;
56                 }
57                 
58                 public static Namespace Root = new Namespace (null, "");
59
60                 public Namespace GetNamespace (string name, bool create)
61                 {
62                         int pos = name.IndexOf ('.');
63
64                         Namespace ns;
65                         string first;
66                         if (pos >= 0)
67                                 first = name.Substring (0, pos);
68                         else
69                                 first = name;
70
71                         ns = (Namespace) namespaces [first];
72                         if (ns == null) {
73                                 if (!create)
74                                         return null;
75
76                                 ns = new Namespace (this, first);
77                                 namespaces.Add (first, ns);
78                         }
79
80                         if (pos >= 0)
81                                 ns = ns.GetNamespace (name.Substring (pos + 1), create);
82
83                         return ns;
84                 }
85
86                 public static Namespace LookupNamespace (string name, bool create)
87                 {
88                         return Root.GetNamespace (name, create);
89                 }
90
91                 public object Lookup (DeclSpace ds, string name)
92                 {
93                         object o = Lookup (name);
94
95                         Type t;
96                         DeclSpace tdecl = o as DeclSpace;
97                         if (tdecl != null) {
98                                 t = tdecl.DefineType ();
99
100                                 if ((ds == null) || ds.CheckAccessLevel (t))
101                                         return t;
102                         }
103
104                         Namespace ns = GetNamespace (name, false);
105                         if (ns != null)
106                                 return ns;
107
108                         t = TypeManager.LookupType (DeclSpace.MakeFQN (fullname, name));
109                         if ((t == null) || ((ds != null) && !ds.CheckAccessLevel (t)))
110                                 return null;
111
112                         return t;
113                 }
114
115                 public void AddNamespaceEntry (NamespaceEntry entry)
116                 {
117                         entries.Add (entry);
118                 }
119
120                 public void DefineName (string name, object o)
121                 {
122                         defined_names.Add (name, o);
123                 }
124
125                 public object Lookup (string name)
126                 {
127                         return defined_names [name];
128                 }
129
130                 static public ArrayList UserDefinedNamespaces {
131                         get {
132                                 return all_namespaces;
133                         }
134                 }
135
136                 /// <summary>
137                 ///   The qualified name of the current namespace
138                 /// </summary>
139                 public string Name {
140                         get {
141                                 return fullname;
142                         }
143                 }
144
145                 /// <summary>
146                 ///   The parent of this namespace, used by the parser to "Pop"
147                 ///   the current namespace declaration
148                 /// </summary>
149                 public Namespace Parent {
150                         get {
151                                 return parent;
152                         }
153                 }
154
155                 public static void DefineNamespaces (SymbolWriter symwriter)
156                 {
157                         foreach (Namespace ns in all_namespaces) {
158                                 foreach (NamespaceEntry entry in ns.entries)
159                                         entry.DefineNamespace (symwriter);
160                         }
161                 }
162
163                 /// <summary>
164                 ///   Used to validate that all the using clauses are correct
165                 ///   after we are finished parsing all the files.  
166                 /// </summary>
167                 public static void VerifyUsing ()
168                 {
169                         foreach (Namespace ns in all_namespaces) {
170                                 foreach (NamespaceEntry entry in ns.entries)
171                                         entry.VerifyUsing ();
172                         }
173                 }
174
175                 public override string ToString ()
176                 {
177                         if (this == Root)
178                                 return "Namespace (<root>)";
179                         else
180                                 return String.Format ("Namespace ({0})", Name);
181                 }
182         }
183
184         public class NamespaceEntry
185         {
186                 Namespace ns;
187                 NamespaceEntry parent, implicit_parent;
188                 SourceFile file;
189                 int symfile_id;
190                 Hashtable aliases;
191                 ArrayList using_clauses;
192                 public bool DeclarationFound = false;
193
194                 //
195                 // This class holds the location where a using definition is
196                 // done, and whether it has been used by the program or not.
197                 //
198                 // We use this to flag using clauses for namespaces that do not
199                 // exist.
200                 //
201                 public class UsingEntry {
202                         public readonly string Name;
203                         public readonly NamespaceEntry NamespaceEntry;
204                         public readonly Location Location;
205                         
206                         public UsingEntry (NamespaceEntry entry, string name, Location loc)
207                         {
208                                 Name = name;
209                                 NamespaceEntry = entry;
210                                 Location = loc;
211                         }
212
213                         Namespace resolved_ns;
214
215                         public Namespace Resolve ()
216                         {
217                                 if (resolved_ns != null)
218                                         return resolved_ns;
219
220                                 Namespace curr_ns = NamespaceEntry.NS;
221                                 while ((curr_ns != null) && (resolved_ns == null)) {
222                                         resolved_ns = curr_ns.GetNamespace (Name, false);
223
224                                         if (resolved_ns == null)
225                                                 curr_ns = curr_ns.Parent;
226                                 }
227
228                                 return resolved_ns;
229                         }
230                 }
231
232                 public class AliasEntry {
233                         public readonly string Name;
234                         public readonly Expression Alias;
235                         public readonly NamespaceEntry NamespaceEntry;
236                         public readonly Location Location;
237                         
238                         public AliasEntry (NamespaceEntry entry, string name, Expression alias, Location loc)
239                         {
240                                 Name = name;
241                                 Alias = alias;
242                                 NamespaceEntry = entry;
243                                 Location = loc;
244                         }
245
246                         object resolved;
247
248                         public object Resolve ()
249                         {
250                                 if (resolved != null)
251                                         return resolved;
252
253                                 NamespaceEntry curr_ns = NamespaceEntry;
254
255                                 string alias = Alias.ToString ();
256                                 while ((curr_ns != null) && (resolved == null)) {
257                                         resolved = curr_ns.Lookup (null, alias, false, Location);
258
259                                         if (resolved == null)
260                                                 curr_ns = curr_ns.Parent;
261                                 }
262
263                                 return resolved;
264                         }
265                 }
266
267                 public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, Location loc)
268                         : this (parent, file, name, false, loc)
269                 { }
270
271                 protected NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, bool is_implicit, Location loc)
272                 {
273                         this.parent = parent;
274                         this.file = file;
275                         this.IsImplicit = is_implicit;
276                         this.ID = ++next_id;
277
278                         if (!is_implicit && (parent != null))
279                                 ns = parent.NS.GetNamespace (name, true);
280                         else if (name != null)
281                                 ns = Namespace.LookupNamespace (name, true);
282                         else
283                                 ns = Namespace.Root;
284                         ns.AddNamespaceEntry (this);
285
286                         if ((parent != null) && (parent.NS != ns.Parent))
287                                 implicit_parent = new NamespaceEntry (parent, file, ns.Parent.Name, true, loc);
288                         else
289                                 implicit_parent = parent;
290
291                         this.FullName = ns.Name;
292                 }
293
294                 static int next_id = 0;
295                 public readonly string FullName;
296                 public readonly int ID;
297                 public readonly bool IsImplicit;
298
299                 public Namespace NS {
300                         get {
301                                 return ns;
302                         }
303                 }
304
305                 public NamespaceEntry Parent {
306                         get {
307                                 return parent;
308                         }
309                 }
310
311                 public NamespaceEntry ImplicitParent {
312                         get {
313                                 return implicit_parent;
314                         }
315                 }
316
317                 public void DefineName (string name, object o)
318                 {
319                         ns.DefineName (name, o);
320                 }
321
322                 /// <summary>
323                 ///   Records a new namespace for resolving name references
324                 /// </summary>
325                 public void Using (string ns, Location loc)
326                 {
327                         if (DeclarationFound){
328                                 Report.Error (1529, loc, "A using clause must precede all other namespace elements");
329                                 return;
330                         }
331
332                         if (ns == FullName)
333                                 return;
334                         
335                         if (using_clauses == null)
336                                 using_clauses = new ArrayList ();
337
338                         foreach (UsingEntry old_entry in using_clauses){
339                                 if (old_entry.Name == ns){
340                                         Report.Warning (105, loc, "The using directive for '" + ns +
341                                                         "' appeared previously in this namespace");
342                                         return;
343                                 }
344                         }
345                         
346                         UsingEntry ue = new UsingEntry (this, ns, loc);
347                         using_clauses.Add (ue);
348                 }
349
350                 public void UsingAlias (string alias, Expression namespace_or_type, Location loc)
351                 {
352                         if (DeclarationFound){
353                                 Report.Error (1529, loc, "A using clause must precede all other namespace elements");
354                                 return;
355                         }
356
357                         if (aliases == null)
358                                 aliases = new Hashtable ();
359                         
360                         if (aliases.Contains (alias)){
361                                 Report.Error (1537, loc, "The using alias `" + alias +
362                                               "' appeared previously in this namespace");
363                                 return;
364                         }
365
366                         aliases [alias] = new AliasEntry (this, alias, namespace_or_type, loc);
367                 }
368
369                 protected AliasEntry GetAliasEntry (string alias)
370                 {
371                         AliasEntry entry = null;
372
373                         if (aliases != null)
374                                 entry = (AliasEntry) aliases [alias];
375                         if (entry == null && Parent != null)
376                                 entry = Parent.GetAliasEntry (alias);
377
378                         return entry;
379                 }
380
381                 public string LookupAlias (string alias)
382                 {
383                         AliasEntry entry = GetAliasEntry (alias);
384
385                         if (entry == null)
386                                 return null;
387
388                         object resolved = entry.Resolve ();
389                         if (resolved == null)
390                                 return null;
391                         else if (resolved is Namespace)
392                                 return ((Namespace) resolved).Name;
393                         else
394                                 return ((Type) resolved).FullName;
395                 }
396
397                 public object Lookup (DeclSpace ds, string name, bool silent, Location loc)
398                 {
399                         object o;
400                         Namespace ns;
401
402                         //
403                         // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
404                         //
405                         int pos = name.IndexOf ('.');
406                         if (pos >= 0) {
407                                 string first = name.Substring (0, pos);
408                                 string last = name.Substring (pos + 1);
409
410                                 o = Lookup (ds, first, silent, loc);
411                                 if (o == null)
412                                         return null;
413
414                                 ns = o as Namespace;
415                                 if (ns != null)
416                                         return ns.Lookup (ds, last);
417
418                                 Type nested = TypeManager.LookupType ((((Type) o).Name + "." + last));
419                                 if ((nested == null) || ((ds != null) && !ds.CheckAccessLevel (nested)))
420                                         return null;
421
422                                 return nested;
423                         }
424
425                         //
426                         // Check whether it's a namespace.
427                         //
428                         o = NS.Lookup (ds, name);
429                         if (o != null)
430                                 return o;
431
432                         //
433                         // Check aliases.
434                         //
435                         AliasEntry entry = GetAliasEntry (name);
436                         if (entry != null) {
437                                 o = entry.Resolve ();
438                                 if (o != null)
439                                         return o;
440                         }
441
442                         if (name.IndexOf ('.') > 0)
443                                 return null;
444
445                         //
446                         // Check using entries.
447                         //
448                         Type t = null, match = null;
449                         foreach (Namespace using_ns in GetUsingTable ()) {
450                                 match = using_ns.Lookup (ds, name) as Type;
451                                 if (match != null){
452                                         if (t != null) {
453                                                 if (!silent)
454                                                         DeclSpace.Error_AmbiguousTypeReference (loc, name, t, match);
455                                                 return null;
456                                         } else {
457                                                 t = match;
458                                         }
459                                 }
460                         }
461
462                         return t;
463                 }
464
465                 // Our cached computation.
466                 Namespace [] namespace_using_table;
467                 public Namespace[] GetUsingTable ()
468                 {
469                         if (namespace_using_table != null)
470                                 return namespace_using_table;
471                         
472                         if (using_clauses == null)
473                                 return new Namespace [0];
474
475                         ArrayList list = new ArrayList (using_clauses.Count);
476
477                         foreach (UsingEntry ue in using_clauses) {
478                                 Namespace using_ns = ue.Resolve ();
479                                 if (using_ns == null)
480                                         continue;
481
482                                 list.Add (using_ns);
483                         }
484
485                         namespace_using_table = new Namespace [list.Count];
486                         list.CopyTo (namespace_using_table, 0);
487                         return namespace_using_table;
488                 }
489
490                 public void DefineNamespace (SymbolWriter symwriter)
491                 {
492                         if (symfile_id != 0)
493                                 return;
494                         if (parent != null)
495                                 parent.DefineNamespace (symwriter);
496
497                         string[] using_list;
498                         if (using_clauses != null) {
499                                 using_list = new string [using_clauses.Count];
500                                 for (int i = 0; i < using_clauses.Count; i++)
501                                         using_list [i] = ((UsingEntry) using_clauses [i]).Name;
502                         } else {
503                                 using_list = new string [0];
504                         }
505
506                         int parent_id = parent != null ? parent.symfile_id : 0;
507                         symfile_id = symwriter.DefineNamespace (ns.Name, file, using_list, parent_id);
508                 }
509
510                 public int SymbolFileID {
511                         get {
512                                 return symfile_id;
513                         }
514                 }
515
516                 static void Msgtry (string s)
517                 {
518                         Console.WriteLine ("    Try using -r:" + s);
519                 }
520
521                 protected void error246 (Location loc, string name)
522                 {
523                         if (TypeManager.LookupType (name) != null)
524                                 Report.Error (138, loc, "The using keyword only lets you specify a namespace, " +
525                                               "`" + name + "' is a class not a namespace.");
526                         else {
527                                 Report.Error (246, loc, "The namespace `" + name +
528                                               "' can not be found (missing assembly reference?)");
529
530                                 switch (name){
531                                 case "Gtk": case "GtkSharp":
532                                         Msgtry ("gtk-sharp");
533                                         break;
534
535                                 case "Gdk": case "GdkSharp":
536                                         Msgtry ("gdk-sharp");
537                                         break;
538
539                                 case "Glade": case "GladeSharp":
540                                         Msgtry ("glade-sharp");
541                                         break;
542                                                         
543                                 case "System.Drawing":
544                                         Msgtry ("System.Drawing");
545                                         break;
546                                                         
547                                 case "System.Web.Services":
548                                         Msgtry ("System.Web.Services");
549                                         break;
550
551                                 case "System.Web":
552                                         Msgtry ("System.Web");
553                                         break;
554                                                         
555                                 case "System.Data":
556                                         Msgtry ("System.Data");
557                                         break;
558
559                                 case "System.Windows.Forms":
560                                         Msgtry ("System.Windows.Forms");
561                                         break;
562                                 }
563                         }
564                 }
565
566                 /// <summary>
567                 ///   Used to validate that all the using clauses are correct
568                 ///   after we are finished parsing all the files.  
569                 /// </summary>
570                 public void VerifyUsing ()
571                 {
572                         if (using_clauses != null){
573                                 foreach (UsingEntry ue in using_clauses){
574                                         if (ue.Resolve () != null)
575                                                 continue;
576
577                                         error246 (ue.Location, ue.Name);
578                                 }
579                         }
580
581                         if (aliases != null){
582                                 foreach (DictionaryEntry de in aliases){
583                                         AliasEntry alias = (AliasEntry) de.Value;
584
585                                         if (alias.Resolve () != null)
586                                                 continue;
587
588                                         error246 (alias.Location, alias.Alias.ToString ());
589                                 }
590                         }
591                 }
592
593                 public override string ToString ()
594                 {
595                         if (NS == Namespace.Root)
596                                 return "NamespaceEntry (<root>)";
597                         else
598                                 return String.Format ("NamespaceEntry ({0},{1},{2})", FullName, IsImplicit, ID);
599                 }
600         }
601 }