2002-10-21 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mbas / 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 using Mono.Languages;
12
13 namespace Mono.CSharp {
14
15         /// <summary>
16         ///   Keeps track of the namespaces defined in the C# code.
17         /// </summary>
18         public class Namespace {
19                 static ArrayList all_namespaces = new ArrayList ();
20                 
21                 Namespace parent;
22                 string name;
23                 ArrayList using_clauses;
24                 Hashtable aliases;
25                 public bool DeclarationFound = false;
26
27                 //
28                 // This class holds the location where a using definition is
29                 // done, and whether it has been used by the program or not.
30                 //
31                 // We use this to flag using clauses for namespaces that do not
32                 // exist.
33                 //
34                 public class UsingEntry {
35                         public string Name;
36                         public bool Used;
37                         public Location Location;
38                         
39                         public UsingEntry (string name, Location loc)
40                         {
41                                 Name = name;
42                                 Location = loc;
43                                 Used = false;
44                         }
45                 }
46                 
47                 /// <summary>
48                 ///   Constructor Takes the current namespace and the
49                 ///   name.  This is bootstrapped with parent == null
50                 ///   and name = ""
51                 /// </summary>
52                 public Namespace (Namespace parent, string name)
53                 {
54                         this.name = name;
55                         this.parent = parent;
56
57                         all_namespaces.Add (this);
58                 }
59
60                 /// <summary>
61                 ///   The qualified name of the current namespace
62                 /// </summary>
63                 public string Name {
64                         get {
65                                 string pname = parent != null ? parent.Name : "";
66                                 
67                                 if (pname == "")
68                                         return name;
69                                 else
70                                         return parent.Name + "." + name;
71                         }
72                 }
73
74                 /// <summary>
75                 ///   The parent of this namespace, used by the parser to "Pop"
76                 ///   the current namespace declaration
77                 /// </summary>
78                 public Namespace Parent {
79                         get {
80                                 return parent;
81                         }
82                 }
83
84                 /// <summary>
85                 ///   Records a new namespace for resolving name references
86                 /// </summary>
87                 public void Using (string ns, Location loc)
88                 {
89                         if (DeclarationFound){
90                                 Report.Error (1529, loc, "A using clause must precede all other namespace elements");
91                                 return;
92                         }
93
94                         if (using_clauses == null)
95                                 using_clauses = new ArrayList ();
96
97                         UsingEntry ue = new UsingEntry (ns, loc);
98                         using_clauses.Add (ue);
99                 }
100
101                 public ArrayList UsingTable {
102                         get {
103                                 return using_clauses;
104                         }
105                 }
106
107                 public void UsingAlias (string alias, string namespace_or_type, Location loc)
108                 {
109                         if (aliases == null)
110                                 aliases = new Hashtable ();
111                         
112                         if (aliases.Contains (alias)){
113                                 Report.Error (1537, loc, "The using alias `" + alias +
114                                               "' appeared previously in this namespace");
115                                 return;
116                         }
117                                         
118                         aliases [alias] = namespace_or_type;
119                 }
120
121                 public string LookupAlias (string alias)
122                 {
123                         string value = null;
124
125                         // System.Console.WriteLine ("Lookup " + alias + " in " + name);
126
127                         if (aliases != null)
128                                 value = (string) (aliases [alias]);
129                         if (value == null && Parent != null)
130                                 value = Parent.LookupAlias (alias);
131
132                         return value;
133                 }
134
135                 /// <summary>
136                 ///   Used to validate that all the using clauses are correct
137                 ///   after we are finished parsing all the files.  
138                 /// </summary>
139                 public static bool VerifyUsing ()
140                 {
141                         ArrayList unused = new ArrayList ();
142                         int errors = 0;
143                         
144                         foreach (Namespace ns in all_namespaces){
145                                 ArrayList uses = ns.UsingTable;
146                                 if (uses == null)
147                                         continue;
148                                 
149                                 foreach (UsingEntry ue in uses){
150                                         if (ue.Used)
151                                                 continue;
152                                         unused.Add (ue);
153                                 }
154                         }
155
156                         //
157                         // If we have unused using aliases, load all namespaces and check
158                         // whether it is unused, or it was missing
159                         //
160                         if (unused.Count > 0){
161                                 Hashtable namespaces = TypeManager.GetNamespaces ();
162
163                                 foreach (UsingEntry ue in unused){
164                                         if (namespaces.Contains (ue.Name)){
165                                                 Report.Warning (6024, ue.Location, "Unused namespace in `using' declaration");
166                                                 continue;
167                                         }
168
169                                         errors++;
170                                         Report.Error (246, ue.Location, "The namespace `" + ue.Name +
171                                                       "' can not be found (missing assembly reference?)");
172                                 }
173                         }
174                         
175                         return errors == 0;
176                 }
177
178         }
179 }