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.MakeName (Name) + " does not hide an " +
51 "inherited member. The keyword new is not required");
55 void Error_CannotChangeAccessModifiers (TypeContainer parent, MethodInfo parent_method,
59 // FIXME: report the old/new permissions?
62 507, Location, parent.MakeName (Name) +
63 ": can't change the access modifiers when overriding inherited " +
64 "member `" + name + "'");
68 // Performs various checks on the MethodInfo `mb' regarding the modifier flags
69 // that have been defined.
71 // `name' is the user visible name for reporting errors (this is used to
72 // provide the right name regarding method names and properties)
74 protected bool CheckMethodAgainstBase (TypeContainer parent, MethodAttributes my_attrs,
75 MethodInfo mb, string name)
79 if ((ModFlags & Modifiers.OVERRIDE) != 0){
80 if (!(mb.IsAbstract || mb.IsVirtual)){
82 506, Location, parent.MakeName (Name) +
83 ": cannot override inherited member `" +
84 name + "' because it is not " +
85 "virtual, abstract or override");
89 // Now we check that the overriden method is not final
92 Report.Error (239, Location, parent.MakeName (Name) + " : cannot " +
93 "override inherited member `" + name +
94 "' because it is sealed.");
99 // Check that the permissions are not being changed
101 MethodAttributes thisp = my_attrs & MethodAttributes.MemberAccessMask;
102 MethodAttributes parentp = mb.Attributes & MethodAttributes.MemberAccessMask;
104 if (thisp != parentp){
105 Error_CannotChangeAccessModifiers (parent, mb, name);
110 if (mb.IsVirtual || mb.IsAbstract){
111 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
112 if (Name != "Finalize" && (RootContext.WarningLevel >= 2)){
114 114, Location, parent.MakeName (Name) +
115 " hides inherited member `" + name +
116 "'. To make the current member override that " +
117 "implementation, add the override keyword, " +
118 "otherwise use the new keyword");
122 if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
123 if (Name != "Finalize" && (RootContext.WarningLevel >= 1)){
125 108, Location, "The keyword new is required on " +
126 parent.MakeName (Name) + " because it hides " +
127 "inherited member `" + name + "'");
135 public abstract bool Define (TypeContainer parent);
138 // Whehter is it ok to use an unsafe pointer in this type container
140 public bool UnsafeOK (DeclSpace parent)
143 // First check if this MemberCore modifier flags has unsafe set
145 if ((ModFlags & Modifiers.UNSAFE) != 0)
148 if (parent.UnsafeContext)
151 Expression.UnsafeError (Location);
157 // FIXME: This is temporary outside DeclSpace, because I have to fix a bug
158 // in MCS that makes it fail the lookup for the enum
162 /// The result value from adding an declaration into
163 /// a struct or a class
165 public enum AdditionResult {
167 /// The declaration has been successfully
168 /// added to the declation space.
173 /// The symbol has already been defined.
178 /// Returned if the declation being added to the
179 /// name space clashes with its container name.
181 /// The only exceptions for this are constructors
182 /// and static constructors
187 /// Returned if a constructor was created (because syntactically
188 /// it looked like a constructor) but was not (because the name
189 /// of the method is not the same as the container class
194 /// This is only used by static constructors to emit the
195 /// error 111, but this error for other things really
196 /// happens at another level for other functions.
202 /// Base class for structs, classes, enumerations and interfaces.
205 /// They all create new declaration spaces. This
206 /// provides the common foundation for managing those name
209 public abstract class DeclSpace : MemberCore {
211 /// this points to the actual definition that is being
212 /// created with System.Reflection.Emit
214 public TypeBuilder TypeBuilder;
217 /// This variable tracks whether we have Closed the type
219 public bool Created = false;
222 // This is the namespace in which this typecontainer
223 // was declared. We use this to resolve names.
225 public Namespace Namespace;
227 public Hashtable Cache = new Hashtable ();
229 public string Basename;
232 /// defined_names is used for toplevel objects
234 protected Hashtable defined_names;
236 TypeContainer parent;
238 public DeclSpace (TypeContainer parent, string name, Location l)
241 Basename = name.Substring (1 + name.LastIndexOf ('.'));
242 defined_names = new Hashtable ();
243 this.parent = parent;
247 /// Returns a status code based purely on the name
248 /// of the member being added
250 protected AdditionResult IsValid (string name)
252 if (name == Basename)
253 return AdditionResult.EnclosingClash;
255 if (defined_names.Contains (name))
256 return AdditionResult.NameExists;
258 return AdditionResult.Success;
262 /// Introduce @name into this declaration space and
263 /// associates it with the object @o. Note that for
264 /// methods this will just point to the first method. o
266 protected void DefineName (string name, object o)
268 defined_names.Add (name, o);
272 /// Returns the object associated with a given name in the declaration
273 /// space. This is the inverse operation of `DefineName'
275 public object GetDefinition (string name)
277 return defined_names [name];
280 bool in_transit = false;
283 /// This function is used to catch recursive definitions
286 public bool InTransit {
296 public TypeContainer Parent {
303 /// Looks up the alias for the name
305 public string LookupAlias (string name)
307 if (Namespace != null)
308 return Namespace.LookupAlias (name);
314 // root_types contains all the types. All TopLevel types
315 // hence have a parent that points to `root_types', that is
316 // why there is a non-obvious test down here.
318 public bool IsTopLevel {
321 if (parent.parent == null)
328 public virtual void CloseType ()
332 TypeBuilder.CreateType ();
335 // The try/catch is needed because
336 // nested enumerations fail to load when they
339 // Even if this is the right order (enumerations
340 // declared after types).
342 // Note that this still creates the type and
343 // it is possible to save it
350 /// Should be overriten by the appropriate declaration space
352 public abstract TypeBuilder DefineType ();
355 /// Define all members, but don't apply any attributes or do anything which may
356 /// access not-yet-defined classes. This method also creates the MemberCache.
358 public abstract bool DefineMembers (TypeContainer parent);
361 // Whether this is an `unsafe context'
363 public bool UnsafeContext {
365 if ((ModFlags & Modifiers.UNSAFE) != 0)
368 return parent.UnsafeContext;
373 public static string MakeFQN (string nsn, string name)
375 string prefix = (nsn == "" ? "" : nsn + ".");
377 return prefix + name;
380 EmitContext type_resolve_ec;
381 EmitContext GetTypeResolveEmitContext (TypeContainer parent, Location loc)
383 type_resolve_ec = new EmitContext (parent, this, loc, null, null, ModFlags, false);
384 type_resolve_ec.ResolvingTypeTree = true;
386 return type_resolve_ec;
390 // Looks up the type, as parsed into the expression `e'
392 public Type ResolveType (Expression e, bool silent, Location loc)
394 if (type_resolve_ec == null)
395 type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
396 type_resolve_ec.loc = loc;
397 Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
398 if (d == null || d.eclass != ExprClass.Type){
400 Report.Error (246, loc, "Cannot find type `"+ e.ToString () +"'");
409 // Resolves the expression `e' for a type, and will recursively define
412 public Expression ResolveTypeExpr (Expression e, bool silent, Location loc)
414 if (type_resolve_ec == null)
415 type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
417 Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
418 if (d == null || d.eclass != ExprClass.Type){
420 Report.Error (246, loc, "Cannot find type `"+ e +"'");
428 Type LookupInterfaceOrClass (string ns, string name, out bool error)
434 name = MakeFQN (ns, name);
436 t = TypeManager.LookupType (name);
440 parent = (DeclSpace) RootContext.Tree.Decls [name];
444 t = parent.DefineType ();
446 Report.Error (146, "Class definition is circular: `"+name+"'");
454 /// GetType is used to resolve type names at the DeclSpace level.
455 /// Use this to lookup class/struct bases, interface bases or
456 /// delegate type references
460 /// Contrast this to LookupType which is used inside method bodies to
461 /// lookup types that have already been defined. GetType is used
462 /// during the tree resolution process and potentially define
463 /// recursively the type
465 public Type FindType (string name)
471 // For the case the type we are looking for is nested within this one
472 // or is in any base class
474 DeclSpace containing_ds = this;
476 while (containing_ds != null){
477 Type current_type = containing_ds.TypeBuilder;
479 while (current_type != null) {
480 string pre = current_type.FullName;
482 t = LookupInterfaceOrClass (pre, name, out error);
489 current_type = current_type.BaseType;
491 containing_ds = containing_ds.Parent;
495 // Attempt to lookup the class on our namespace and all it's implicit parents
497 for (string ns = Namespace.Name; ns != null; ns = RootContext.ImplicitParent (ns)) {
499 t = LookupInterfaceOrClass (ns, name, out error);
508 // Attempt to do a direct unqualified lookup
510 t = LookupInterfaceOrClass ("", name, out error);
518 // Attempt to lookup the class on any of the `using'
522 for (Namespace ns = Namespace; ns != null; ns = ns.Parent){
524 t = LookupInterfaceOrClass (ns.Name, name, out error);
532 // Now check the using clause list
534 ArrayList using_list = ns.UsingTable;
536 if (using_list == null)
539 foreach (string n in using_list){
540 t = LookupInterfaceOrClass (n, name, out error);
550 //Report.Error (246, Location, "Can not find type `"+name+"'");
555 /// This function is broken and not what you're looking for. It should only
556 /// be used while the type is still being created since it doesn't use the cache
557 /// and relies on the filter doing the member name check.
559 internal abstract MemberList FindMembers (MemberTypes mt, BindingFlags bf,
560 MemberFilter filter, object criteria);
563 /// If we have a MemberCache, return it. This property may return null if the
564 /// class doesn't have a member cache or while it's still being created.
566 public abstract MemberCache MemberCache {