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