2 // decl.cs: Declaration base class for structs, classes, enums and interfaces.
4 // Author: Miguel de Icaza (miguel@gnu.org)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 // TODO: Move the method verification stuff from the class.cs and interface.cs here
14 using System.Collections;
15 using System.Reflection.Emit;
16 using System.Reflection;
18 namespace Mono.CSharp {
21 /// Base representation for members. This is only used to keep track
22 /// of Name, Location and Modifier flags.
24 public abstract class MemberCore {
31 /// Modifier flags that the user specified in the source code
36 /// Location where this declaration happens
38 public readonly Location Location;
40 public MemberCore (string name, Location loc)
46 protected void WarningNotHiding (TypeContainer parent)
50 "The member `" + parent.Name + "." + Name + "' does not hide an " +
51 "inherited member. The keyword new is not required");
55 static string MethodBaseName (MethodBase mb)
57 return "`" + mb.ReflectedType.Name + "." + mb.Name + "'";
60 void Error_CannotChangeAccessModifiers (TypeContainer parent, MethodInfo parent_method)
63 // FIXME: report the old/new permissions?
66 507, "`" + parent_method + "." + Name +
67 ": can't change the access modifiers from `" +
68 parent_method.DeclaringType.Name + "." + parent_method.Name + "'");
72 // Performs various checks on the MethodInfo `mb' regarding the modifier flags
73 // that have been defined.
75 // `name' is the user visible name for reporting errors (this is used to
76 // provide the right name regarding method names and properties)
78 protected bool CheckMethodAgainstBase (TypeContainer parent,
79 MethodAttributes my_attrs, MethodInfo mb)
83 if ((ModFlags & Modifiers.OVERRIDE) != 0){
84 if (!(mb.IsAbstract || mb.IsVirtual)){
86 506, Location, parent.MakeName (Name) +
87 ": cannot override inherited member " +
88 MethodBaseName (mb) + " because it is not " +
89 "virtual, abstract or override");
93 // Now we check that the overriden method is not final
96 Report.Error (239, Location, parent.MakeName (Name) + " : cannot " +
97 "override inherited member " + MethodBaseName (mb) +
98 " because it is sealed.");
103 // Check that the permissions are not being changed
105 MethodAttributes thisp = my_attrs & MethodAttributes.MemberAccessMask;
106 MethodAttributes parentp = mb.Attributes & MethodAttributes.MemberAccessMask;
108 if (thisp != parentp){
109 Error_CannotChangeAccessModifiers (parent, mb);
114 if (mb.IsVirtual || mb.IsAbstract){
115 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
116 if (Name != "Finalize" && (RootContext.WarningLevel >= 2)){
118 114, Location, parent.MakeName (Name) +
119 " hides inherited member " + MethodBaseName (mb) +
120 ". To make the current member override that " +
121 "implementation, add the override keyword, " +
122 "otherwise use the new keyword");
130 public abstract bool Define (TypeContainer parent);
133 // Whehter is it ok to use an unsafe pointer in this type container
135 public bool UnsafeOK (DeclSpace parent)
138 // First check if this MemberCore modifier flags has unsafe set
140 if ((ModFlags & Modifiers.UNSAFE) != 0)
143 if (parent.UnsafeContext)
146 Expression.UnsafeError (Location);
152 // FIXME: This is temporary outside DeclSpace, because I have to fix a bug
153 // in MCS that makes it fail the lookup for the enum
157 /// The result value from adding an declaration into
158 /// a struct or a class
160 public enum AdditionResult {
162 /// The declaration has been successfully
163 /// added to the declation space.
168 /// The symbol has already been defined.
173 /// Returned if the declation being added to the
174 /// name space clashes with its container name.
176 /// The only exceptions for this are constructors
177 /// and static constructors
182 /// Returned if a constructor was created (because syntactically
183 /// it looked like a constructor) but was not (because the name
184 /// of the method is not the same as the container class
189 /// This is only used by static constructors to emit the
190 /// error 111, but this error for other things really
191 /// happens at another level for other functions.
197 /// Base class for structs, classes, enumerations and interfaces.
200 /// They all create new declaration spaces. This
201 /// provides the common foundation for managing those name
204 public abstract class DeclSpace : MemberCore {
206 /// this points to the actual definition that is being
207 /// created with System.Reflection.Emit
209 public TypeBuilder TypeBuilder;
212 /// This variable tracks whether we have Closed the type
214 public bool Created = false;
217 // This is the namespace in which this typecontainer
218 // was declared. We use this to resolve names.
220 public Namespace Namespace;
222 public Hashtable Cache = new Hashtable ();
224 public string Basename;
227 /// defined_names is used for toplevel objects
229 protected Hashtable defined_names;
231 TypeContainer parent;
233 public DeclSpace (TypeContainer parent, string name, Location l)
236 Basename = name.Substring (1 + name.LastIndexOf ('.'));
237 defined_names = new Hashtable ();
238 this.parent = parent;
242 /// Returns a status code based purely on the name
243 /// of the member being added
245 protected AdditionResult IsValid (string name)
247 if (name == Basename)
248 return AdditionResult.EnclosingClash;
250 if (defined_names.Contains (name))
251 return AdditionResult.NameExists;
253 return AdditionResult.Success;
257 /// Introduce @name into this declaration space and
258 /// associates it with the object @o. Note that for
259 /// methods this will just point to the first method. o
261 protected void DefineName (string name, object o)
263 defined_names.Add (name, o);
267 /// Returns the object associated with a given name in the declaration
268 /// space. This is the inverse operation of `DefineName'
270 public object GetDefinition (string name)
272 return defined_names [name];
275 bool in_transit = false;
278 /// This function is used to catch recursive definitions
281 public bool InTransit {
291 public TypeContainer Parent {
298 // root_types contains all the types. All TopLevel types
299 // hence have a parent that points to `root_types', that is
300 // why there is a non-obvious test down here.
302 public bool IsTopLevel {
305 if (parent.parent == null)
312 public virtual void CloseType ()
316 TypeBuilder.CreateType ();
319 // The try/catch is needed because
320 // nested enumerations fail to load when they
323 // Even if this is the right order (enumerations
324 // declared after types).
326 // Note that this still creates the type and
327 // it is possible to save it
334 /// Should be overriten by the appropriate declaration space
336 public abstract TypeBuilder DefineType ();
339 // Whether this is an `unsafe context'
341 public bool UnsafeContext {
343 if ((ModFlags & Modifiers.UNSAFE) != 0)
346 return parent.UnsafeContext;
351 public static string MakeFQN (string nsn, string name)
353 string prefix = (nsn == "" ? "" : nsn + ".");
355 return prefix + name;
358 Type LookupInterfaceOrClass (string ns, string name, out bool error)
364 name = MakeFQN (ns, name);
366 t = TypeManager.LookupType (name);
370 parent = (DeclSpace) RootContext.Tree.Decls [name];
374 t = parent.DefineType ();
376 Report.Error (146, "Class definition is circular: `"+name+"'");
384 /// GetType is used to resolve type names at the DeclSpace level.
385 /// Use this to lookup class/struct bases, interface bases or
386 /// delegate type references
390 /// Contrast this to LookupType which is used inside method bodies to
391 /// lookup types that have already been defined. GetType is used
392 /// during the tree resolution process and potentially define
393 /// recursively the type
395 public Type FindType (string name)
401 // For the case the type we are looking for is nested within this one
402 // or is in any base class
404 DeclSpace containing_ds = this;
406 while (containing_ds != null){
407 Type current_type = containing_ds.TypeBuilder;
409 while (current_type != null) {
410 string pre = current_type.FullName;
412 t = LookupInterfaceOrClass (pre, name, out error);
419 current_type = current_type.BaseType;
421 containing_ds = containing_ds.Parent;
425 // Attempt to lookup the class on our namespace and all it's implicit parents
427 for (string ns = Namespace.Name; ns != null; ns = RootContext.ImplicitParent (ns)) {
429 t = LookupInterfaceOrClass (ns, name, out error);
438 // Attempt to do a direct unqualified lookup
440 t = LookupInterfaceOrClass ("", name, out error);
448 // Attempt to lookup the class on any of the `using'
452 for (Namespace ns = Namespace; ns != null; ns = ns.Parent){
454 t = LookupInterfaceOrClass (ns.Name, name, out error);
462 // Now check the using clause list
464 ArrayList using_list = ns.UsingTable;
466 if (using_list == null)
469 foreach (string n in using_list){
470 t = LookupInterfaceOrClass (n, name, out error);
480 Report.Error (246, Location, "Can not find type `"+name+"'");