2003-01-07 Miguel de Icaza <miguel@ximian.com>
[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 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 String.Concat (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 (ns == Name)
95                                 return;
96                         
97                         if (using_clauses == null)
98                                 using_clauses = new ArrayList ();
99
100                         foreach (UsingEntry old_entry in using_clauses){
101                                 if (old_entry.Name == ns){
102                                         Report.Warning (105, loc, "The using directive for '" + ns +
103                                                         "' appeared previously in this namespace");
104                                         return;
105                                 }
106                         }
107                         
108                         UsingEntry ue = new UsingEntry (ns, loc);
109                         using_clauses.Add (ue);
110                 }
111
112                 public ArrayList UsingTable {
113                         get {
114                                 return using_clauses;
115                         }
116                 }
117
118                 public void UsingAlias (string alias, string namespace_or_type, Location loc)
119                 {
120                         if (aliases == null)
121                                 aliases = new Hashtable ();
122                         
123                         if (aliases.Contains (alias)){
124                                 Report.Error (1537, loc, "The using alias `" + alias +
125                                               "' appeared previously in this namespace");
126                                 return;
127                         }
128                                         
129                         aliases [alias] = namespace_or_type;
130                 }
131
132                 public string LookupAlias (string alias)
133                 {
134                         string value = null;
135
136                         // System.Console.WriteLine ("Lookup " + alias + " in " + name);
137
138                         if (aliases != null)
139                                 value = (string) (aliases [alias]);
140                         if (value == null && Parent != null)
141                                 value = Parent.LookupAlias (alias);
142
143                         return value;
144                 }
145
146                 /// <summary>
147                 ///   Used to validate that all the using clauses are correct
148                 ///   after we are finished parsing all the files.  
149                 /// </summary>
150                 public static bool VerifyUsing ()
151                 {
152                         ArrayList unused = new ArrayList ();
153                         int errors = 0;
154                         
155                         foreach (Namespace ns in all_namespaces){
156                                 ArrayList uses = ns.UsingTable;
157                                 if (uses == null)
158                                         continue;
159                                 
160                                 foreach (UsingEntry ue in uses){
161                                         if (ue.Used)
162                                                 continue;
163                                         unused.Add (ue);
164                                 }
165                         }
166
167                         //
168                         // If we have unused using aliases, load all namespaces and check
169                         // whether it is unused, or it was missing
170                         //
171                         if (unused.Count > 0){
172                                 Hashtable namespaces = TypeManager.GetNamespaces ();
173
174                                 foreach (UsingEntry ue in unused){
175                                         if (namespaces.Contains (ue.Name)){
176                                                 Report.Warning (6024, ue.Location, "Unused namespace in `using' declaration");
177                                                 continue;
178                                         }
179
180                                         errors++;
181                                         Report.Error (246, ue.Location, "The namespace `" + ue.Name +
182                                                       "' can not be found (missing assembly reference?)");
183                                 }
184                         }
185                         
186                         return errors == 0;
187                 }
188
189         }
190 }