Add new test
[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                                                 MethodBaseName (mb) + " because it is not " +
77                                                 "virtual, abstract or override");
78                                         ok = false;
79                                 }
80                                 
81                                 // Now we check that the overriden method is not final
82                                 
83                                 if (mb.IsFinal) {
84                                         Report.Error (239, Location, parent.MakeName (Name) + " : cannot " +
85                                                       "override inherited member " + MethodBaseName (mb) +
86                                                       " because it is sealed.");
87                                         ok = false;
88                                 }
89                         }
90
91                         if (mb.IsVirtual || mb.IsAbstract){
92                                 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
93                                         Report.Warning (
94                                                 114, Location, parent.MakeName (Name) + 
95                                                 " hides inherited member " + MethodBaseName (mb) +
96                                                 ".  To make the current member override that " +
97                                                 "implementation, add the override keyword, " +
98                                                 "otherwise use the new keyword");
99                                 }
100                         }
101
102                         return ok;
103                 }
104
105                 public abstract bool Define (TypeContainer parent);
106
107                 // 
108                 // Whehter is it ok to use an unsafe pointer in this type container
109                 //
110                 public bool UnsafeOK (DeclSpace parent)
111                 {
112                         //
113                         // First check if this MemberCore modifier flags has unsafe set
114                         //
115                         if ((ModFlags & Modifiers.UNSAFE) != 0)
116                                 return true;
117
118                         if (parent.UnsafeContext)
119                                 return true;
120
121                         Expression.UnsafeError (Location);
122                         return false;
123                 }
124         }
125
126         //
127         // FIXME: This is temporary outside DeclSpace, because I have to fix a bug
128         // in MCS that makes it fail the lookup for the enum
129         //
130
131                 /// <summary>
132                 ///   The result value from adding an declaration into
133                 ///   a struct or a class
134                 /// </summary>
135                 public enum AdditionResult {
136                         /// <summary>
137                         /// The declaration has been successfully
138                         /// added to the declation space.
139                         /// </summary>
140                         Success,
141
142                         /// <summary>
143                         ///   The symbol has already been defined.
144                         /// </summary>
145                         NameExists,
146
147                         /// <summary>
148                         ///   Returned if the declation being added to the
149                         ///   name space clashes with its container name.
150                         ///
151                         ///   The only exceptions for this are constructors
152                         ///   and static constructors
153                         /// </summary>
154                         EnclosingClash,
155
156                         /// <summary>
157                         ///   Returned if a constructor was created (because syntactically
158                         ///   it looked like a constructor) but was not (because the name
159                         ///   of the method is not the same as the container class
160                         /// </summary>
161                         NotAConstructor,
162
163                         /// <summary>
164                         ///   This is only used by static constructors to emit the
165                         ///   error 111, but this error for other things really
166                         ///   happens at another level for other functions.
167                         /// </summary>
168                         MethodExists
169                 }
170
171         /// <summary>
172         ///   Base class for structs, classes, enumerations and interfaces.  
173         /// </summary>
174         /// <remarks>
175         ///   They all create new declaration spaces.  This
176         ///   provides the common foundation for managing those name
177         ///   spaces.
178         /// </remarks>
179         public abstract class DeclSpace : MemberCore {
180                 /// <summary>
181                 ///   this points to the actual definition that is being
182                 ///   created with System.Reflection.Emit
183                 /// </summary>
184                 TypeBuilder definition;
185                 public bool Created = false;
186                 
187                 //
188                 // This is the namespace in which this typecontainer
189                 // was declared.  We use this to resolve names.
190                 //
191                 public Namespace Namespace;
192
193                 public string Basename;
194                 
195                 /// <summary>
196                 ///   defined_names is used for toplevel objects
197                 /// </summary>
198                 protected Hashtable defined_names;
199
200                 TypeContainer parent;           
201
202                 public DeclSpace (TypeContainer parent, string name, Location l)
203                         : base (name, l)
204                 {
205                         Basename = name.Substring (1 + name.LastIndexOf ('.'));
206                         defined_names = new Hashtable ();
207                         this.parent = parent;
208                 }
209
210                 /// <summary>
211                 ///   Returns a status code based purely on the name
212                 ///   of the member being added
213                 /// </summary>
214                 protected AdditionResult IsValid (string name)
215                 {
216                         if (name == Basename)
217                                 return AdditionResult.EnclosingClash;
218
219                         if (defined_names.Contains (name))
220                                 return AdditionResult.NameExists;
221
222                         return AdditionResult.Success;
223                 }
224
225                 /// <summary>
226                 ///   Introduce @name into this declaration space and
227                 ///   associates it with the object @o.  Note that for
228                 ///   methods this will just point to the first method. o
229                 /// </summary>
230                 protected void DefineName (string name, object o)
231                 {
232                         defined_names.Add (name, o);
233                 }
234
235                 bool in_transit = false;
236                 
237                 /// <summary>
238                 ///   This function is used to catch recursive definitions
239                 ///   in declarations.
240                 /// </summary>
241                 public bool InTransit {
242                         get {
243                                 return in_transit;
244                         }
245
246                         set {
247                                 in_transit = value;
248                         }
249                 }
250
251                 public TypeBuilder TypeBuilder {
252                         get {
253                                 return definition;
254                         }
255
256                         set {
257                                 definition = value;
258                         }
259                 }
260
261                 public TypeContainer Parent {
262                         get {
263                                 return parent;
264                         }
265                 }
266
267                 public virtual void CloseType ()
268                 {
269                         if (!Created){
270                                 try {
271                                         definition.CreateType ();
272                                 } catch {
273                                         //
274                                         // The try/catch is needed because
275                                         // nested enumerations fail to load when they
276                                         // are defined.
277                                         //
278                                         // Even if this is the right order (enumerations
279                                         // declared after types).
280                                         //
281                                         // Note that this still creates the type and
282                                         // it is possible to save it
283                                 }
284                                 Created = true;
285                         }
286                 }
287
288                 //
289                 // Whether this is an `unsafe context'
290                 //
291                 public bool UnsafeContext {
292                         get {
293                                 if ((ModFlags & Modifiers.UNSAFE) != 0)
294                                         return true;
295                                 if (parent != null)
296                                         return parent.UnsafeContext;
297                                 return false;
298                         }
299                 }
300
301         }
302 }