2002-02-11 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / decl.cs
1 //
2 // decl.cs: Declaration base class for structs, classes, enums and interfaces.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10 // TODO: Move the method verification stuff from the class.cs and interface.cs here
11 //
12
13 using System;
14 using System.Collections;
15 using System.Reflection.Emit;
16 using System.Reflection;
17
18 namespace Mono.CSharp {
19
20         /// <summary>
21         ///   Base representation for members.  This is only used to keep track
22         ///   of Name, Location and Modifier flags.
23         /// </summary>
24         public abstract class MemberCore {
25                 /// <summary>
26                 ///   Public name
27                 /// </summary>
28                 public string Name;
29
30                 /// <summary>
31                 ///   Modifier flags that the user specified in the source code
32                 /// </summary>
33                 public int ModFlags;
34
35                 /// <summary>
36                 ///   Location where this declaration happens
37                 /// </summary>
38                 public readonly Location Location;
39
40                 public MemberCore (string name, Location loc)
41                 {
42                         Name = name;
43                         Location = loc;
44                 }
45
46                 protected void WarningNotHiding (TypeContainer parent)
47                 {
48                         Report.Warning (
49                                 109, Location,
50                                 "The member `" + parent.Name + "." + Name + "' does not hide an " +
51                                 "inherited member.  The keyword new is not required");
52                                                            
53                 }
54
55                 static string MethodBaseName (MethodBase mb)
56                 {
57                         return "`" + mb.ReflectedType.Name + "." + mb.Name + "'";
58                 }
59
60                 //
61                 // Performs various checks on the MethodInfo `mb' regarding the modifier flags
62                 // that have been defined.
63                 //
64                 // `name' is the user visible name for reporting errors (this is used to
65                 // provide the right name regarding method names and properties)
66                 //
67                 protected bool CheckMethodAgainstBase (TypeContainer parent, MethodInfo mb)
68                 {
69                         bool ok = true;
70                         
71                         if ((ModFlags & Modifiers.OVERRIDE) != 0){
72                                 if (!(mb.IsAbstract || mb.IsVirtual)){
73                                         Report.Error (
74                                                 506, Location, parent.MakeName (Name) +
75                                                 ": cannot override inherited member `" +
76                                                 mb.ReflectedType.Name + "' because it is not " +
77                                                 "virtual, abstract or override");
78                                         ok = false;
79                                 }
80                         }
81
82                         if (mb.IsVirtual || mb.IsAbstract){
83                                 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
84                                         Report.Warning (
85                                                 114, Location, parent.MakeName (Name) + 
86                                                 " hides inherited member " + MethodBaseName (mb) +
87                                                 ".  To make the current member override that " +
88                                                 "implementation, add the override keyword, " +
89                                                 "otherwise use the new keyword");
90                                 }
91                         }
92
93                         return ok;
94                 }
95
96                 public abstract bool Define (TypeContainer parent);
97
98                 // 
99                 // Whehter is it ok to use an unsafe pointer in this type container
100                 //
101                 public bool UnsafeOK (DeclSpace parent)
102                 {
103                         //
104                         // First check if this MemberCore modifier flags has unsafe set
105                         //
106                         if ((ModFlags & Modifiers.UNSAFE) != 0)
107                                 return true;
108
109                         if (parent.UnsafeContext)
110                                 return true;
111
112                         Expression.UnsafeError (Location);
113                         return false;
114                 }
115         }
116
117         //
118         // FIXME: This is temporary outside DeclSpace, because I have to fix a bug
119         // in MCS that makes it fail the lookup for the enum
120         //
121
122                 /// <summary>
123                 ///   The result value from adding an declaration into
124                 ///   a struct or a class
125                 /// </summary>
126                 public enum AdditionResult {
127                         /// <summary>
128                         /// The declaration has been successfully
129                         /// added to the declation space.
130                         /// </summary>
131                         Success,
132
133                         /// <summary>
134                         ///   The symbol has already been defined.
135                         /// </summary>
136                         NameExists,
137
138                         /// <summary>
139                         ///   Returned if the declation being added to the
140                         ///   name space clashes with its container name.
141                         ///
142                         ///   The only exceptions for this are constructors
143                         ///   and static constructors
144                         /// </summary>
145                         EnclosingClash,
146
147                         /// <summary>
148                         ///   Returned if a constructor was created (because syntactically
149                         ///   it looked like a constructor) but was not (because the name
150                         ///   of the method is not the same as the container class
151                         /// </summary>
152                         NotAConstructor,
153
154                         /// <summary>
155                         ///   This is only used by static constructors to emit the
156                         ///   error 111, but this error for other things really
157                         ///   happens at another level for other functions.
158                         /// </summary>
159                         MethodExists
160                 }
161
162         /// <summary>
163         ///   Base class for structs, classes, enumerations and interfaces.  
164         /// </summary>
165         /// <remarks>
166         ///   They all create new declaration spaces.  This
167         ///   provides the common foundation for managing those name
168         ///   spaces.
169         /// </remarks>
170         public abstract class DeclSpace : MemberCore {
171                 /// <summary>
172                 ///   this points to the actual definition that is being
173                 ///   created with System.Reflection.Emit
174                 /// </summary>
175                 TypeBuilder definition;
176                 public bool Created = false;
177                 
178                 //
179                 // This is the namespace in which this typecontainer
180                 // was declared.  We use this to resolve names.
181                 //
182                 public Namespace Namespace;
183
184                 public string Basename;
185                 
186                 /// <summary>
187                 ///   defined_names is used for toplevel objects
188                 /// </summary>
189                 protected Hashtable defined_names;
190
191                 TypeContainer parent;           
192
193                 public DeclSpace (TypeContainer parent, string name, Location l)
194                         : base (name, l)
195                 {
196                         Basename = name.Substring (1 + name.LastIndexOf ('.'));
197                         defined_names = new Hashtable ();
198                         this.parent = parent;
199                 }
200
201                 /// <summary>
202                 ///   Returns a status code based purely on the name
203                 ///   of the member being added
204                 /// </summary>
205                 protected AdditionResult IsValid (string name)
206                 {
207                         if (name == Basename)
208                                 return AdditionResult.EnclosingClash;
209
210                         if (defined_names.Contains (name))
211                                 return AdditionResult.NameExists;
212
213                         return AdditionResult.Success;
214                 }
215
216                 /// <summary>
217                 ///   Introduce @name into this declaration space and
218                 ///   associates it with the object @o.  Note that for
219                 ///   methods this will just point to the first method. o
220                 /// </summary>
221                 protected void DefineName (string name, object o)
222                 {
223                         defined_names.Add (name, o);
224                 }
225
226                 bool in_transit = false;
227                 
228                 /// <summary>
229                 ///   This function is used to catch recursive definitions
230                 ///   in declarations.
231                 /// </summary>
232                 public bool InTransit {
233                         get {
234                                 return in_transit;
235                         }
236
237                         set {
238                                 in_transit = value;
239                         }
240                 }
241
242                 public TypeBuilder TypeBuilder {
243                         get {
244                                 return definition;
245                         }
246
247                         set {
248                                 definition = value;
249                         }
250                 }
251
252                 public TypeContainer Parent {
253                         get {
254                                 return parent;
255                         }
256                 }
257
258                 public virtual void CloseType ()
259                 {
260                         if (!Created){
261                                 try {
262                                         definition.CreateType ();
263                                 } catch {
264                                         //
265                                         // The try/catch is needed because
266                                         // nested enumerations fail to load when they
267                                         // are defined.
268                                         //
269                                         // Even if this is the right order (enumerations
270                                         // declared after types).
271                                         //
272                                         // Note that this still creates the type and
273                                         // it is possible to save it
274                                 }
275                                 Created = true;
276                         }
277                 }
278
279                 //
280                 // Whether this is an `unsafe context'
281                 //
282                 public bool UnsafeContext {
283                         get {
284                                 if ((ModFlags & Modifiers.UNSAFE) != 0)
285                                         return true;
286                                 if (parent != null)
287                                         return parent.UnsafeContext;
288                                 return false;
289                         }
290                 }
291
292         }
293 }