updated the demo application
[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                 SourceFile file;
24                 int symfile_id;
25                 ArrayList using_clauses;
26                 Hashtable aliases;
27                 public bool DeclarationFound = false;
28
29                 //
30                 // This class holds the location where a using definition is
31                 // done, and whether it has been used by the program or not.
32                 //
33                 // We use this to flag using clauses for namespaces that do not
34                 // exist.
35                 //
36                 public class UsingEntry {
37                         public string Name;
38                         public Location Location;
39                         
40                         public UsingEntry (string name, Location loc)
41                         {
42                                 Name = name;
43                                 Location = loc;
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, SourceFile file, string name)
53                 {
54                         this.name = name;
55                         this.file = file;
56                         this.parent = parent;
57
58                         all_namespaces.Add (this);
59                 }
60
61                 static public ArrayList UserDefinedNamespaces {
62                         get {
63                                 return all_namespaces;
64                         }
65                 }
66                 
67                 /// <summary>
68                 ///   The qualified name of the current namespace
69                 /// </summary>
70                 public string Name {
71                         get {
72                                 string pname = parent != null ? parent.Name : "";
73                                 
74                                 if (pname == "")
75                                         return name;
76                                 else
77                                         return String.Concat (parent.Name, ".", name);
78                         }
79                 }
80
81                 /// <summary>
82                 ///   The parent of this namespace, used by the parser to "Pop"
83                 ///   the current namespace declaration
84                 /// </summary>
85                 public Namespace Parent {
86                         get {
87                                 return parent;
88                         }
89                 }
90
91                 public int SymbolFileID {
92                         get {
93                                 return symfile_id;
94                         }
95                 }
96
97                 /// <summary>
98                 ///   Records a new namespace for resolving name references
99                 /// </summary>
100                 public void Using (string ns, Location loc)
101                 {
102                         if (DeclarationFound){
103                                 Report.Error (1529, loc, "A using clause must precede all other namespace elements");
104                                 return;
105                         }
106
107                         if (ns == Name)
108                                 return;
109                         
110                         if (using_clauses == null)
111                                 using_clauses = new ArrayList ();
112
113                         foreach (UsingEntry old_entry in using_clauses){
114                                 if (old_entry.Name == ns){
115                                         Report.Warning (105, loc, "The using directive for '" + ns +
116                                                         "' appeared previously in this namespace");
117                                         return;
118                                 }
119                         }
120                         
121                         UsingEntry ue = new UsingEntry (ns, loc);
122                         using_clauses.Add (ue);
123                 }
124
125                 public ArrayList UsingTable {
126                         get {
127                                 return using_clauses;
128                         }
129                 }
130
131                 public void UsingAlias (string alias, string namespace_or_type, Location loc)
132                 {
133                         if (aliases == null)
134                                 aliases = new Hashtable ();
135                         
136                         if (aliases.Contains (alias)){
137                                 Report.Error (1537, loc, "The using alias `" + alias +
138                                               "' appeared previously in this namespace");
139                                 return;
140                         }
141                                         
142                         aliases [alias] = namespace_or_type;
143                 }
144
145                 public string LookupAlias (string alias)
146                 {
147                         string value = null;
148
149                         // System.Console.WriteLine ("Lookup " + alias + " in " + name);
150
151                         if (aliases != null)
152                                 value = (string) (aliases [alias]);
153                         if (value == null && Parent != null)
154                                 value = Parent.LookupAlias (alias);
155
156                         return value;
157                 }
158
159                 void DefineNamespace (SymbolWriter symwriter)
160                 {
161                         if (symfile_id != 0)
162                                 return;
163                         if (parent != null)
164                                 parent.DefineNamespace (symwriter);
165
166                         string[] using_list;
167                         if (using_clauses != null) {
168                                 using_list = new string [using_clauses.Count];
169                                 for (int i = 0; i < using_clauses.Count; i++)
170                                         using_list [i] = ((UsingEntry) using_clauses [i]).Name;
171                         } else {
172                                 using_list = new string [0];
173                         }                               
174
175                         int parent_id = parent != null ? parent.symfile_id : 0;
176                         symfile_id = symwriter.DefineNamespace (name, file, using_list, parent_id);
177                 }
178
179                 public static void DefineNamespaces (SymbolWriter symwriter)
180                 {
181                         foreach (Namespace ns in all_namespaces)
182                                 ns.DefineNamespace (symwriter);
183                 }
184
185                 /// <summary>
186                 ///   Used to validate that all the using clauses are correct
187                 ///   after we are finished parsing all the files.  
188                 /// </summary>
189                 public static void VerifyUsing ()
190                 {
191                         foreach (Namespace ns in all_namespaces){
192                                 ArrayList uses = ns.UsingTable;
193
194                                 if (uses != null){
195                                         foreach (UsingEntry ue in uses){
196                                                 if (TypeManager.IsNamespace (ue.Name))
197                                                         continue;
198                                                 
199                                                 Report.Error (246, ue.Location, "The namespace `" + ue.Name +
200                                                               "' can not be found (missing assembly reference?)");
201                                         }
202                                 }
203
204                                 if (ns.aliases != null){
205                                         foreach (DictionaryEntry de in ns.aliases){
206                                                 string value = (string) de.Value;
207                                                 
208                                                 if (TypeManager.IsNamespace (value))
209                                                         continue;
210                                                 if (TypeManager.LookupTypeDirect (value) != null)
211                                                         continue;
212                                                 
213                                                 Report.Error (246, String.Format (
214                                                                       "The type or namespace `{0}' could not be found (missing assembly reference?)",
215                                                                       value));
216                                         }
217                                 }
218                         }
219                 }
220         }
221 }