📄 decl.cs
字号:
} return true; } // // Raised (and passed an XmlElement that contains the comment) // when GenerateDocComment is writing documentation expectedly. // internal virtual void OnGenerateDocComment (DeclSpace ds, XmlElement intermediateNode) { } // // Returns a string that represents the signature for this // member which should be used in XML documentation. // public virtual string GetDocCommentName (DeclSpace ds) { if (ds == null || this is DeclSpace) return DocCommentHeader + Name; else return String.Concat (DocCommentHeader, ds.Name, ".", Name); } // // Generates xml doc comments (if any), and if required, // handle warning report. // internal virtual void GenerateDocComment (DeclSpace ds) { DocUtil.GenerateDocComment (this, ds); } } /// <summary> /// Base class for structs, classes, enumerations and interfaces. /// </summary> /// <remarks> /// They all create new declaration spaces. This /// provides the common foundation for managing those name /// spaces. /// </remarks> public abstract class DeclSpace : MemberCore { /// <summary> /// This points to the actual definition that is being /// created with System.Reflection.Emit /// </summary> public TypeBuilder TypeBuilder; // // This is the namespace in which this typecontainer // was declared. We use this to resolve names. // public NamespaceEntry NamespaceEntry; private Hashtable Cache = new Hashtable (); public string Basename; protected Hashtable defined_names; // The emit context for toplevel objects. protected EmitContext ec; public override EmitContext EmitContext { get { return ec; } } static string[] attribute_targets = new string [] { "type" }; public DeclSpace (NamespaceEntry ns, TypeContainer parent, MemberName name, Attributes attrs) : base (parent, name, attrs) { NamespaceEntry = ns; Basename = name.Name; defined_names = new Hashtable (); } /// <summary> /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts /// </summary> protected bool AddToContainer (MemberCore symbol, string name) { if (name == Basename && !(this is Interface) && !(this is Enum)) { Report.SymbolRelatedToPreviousError (this); Report.Error (542, symbol.Location, "`{0}': member names cannot be the same as their enclosing type", symbol.GetSignatureForError ()); return false; } MemberCore mc = (MemberCore) defined_names [name]; if (mc == null) { defined_names.Add (name, symbol); return true; } if (symbol.MarkForDuplicationCheck () && mc.MarkForDuplicationCheck ()) return true; Report.SymbolRelatedToPreviousError (mc); if (symbol is PartialContainer || mc is PartialContainer) { Report.Error (260, symbol.Location, "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists", name); return false; } if (this is RootTypes) { Report.Error (101, symbol.Location, "The namespace `{0}' already contains a definition for `{1}'", ((DeclSpace)symbol).NamespaceEntry.GetSignatureForError (), symbol.MemberName.Name); } else { Report.Error (102, symbol.Location, "The type `{0}' already contains a definition for `{1}'", GetSignatureForError (), symbol.MemberName.Name); } return false; } /// <summary> /// Returns the MemberCore associated with a given name in the declaration /// space. It doesn't return method based symbols !! /// </summary> /// public MemberCore GetDefinition (string name) { return (MemberCore)defined_names [name]; } // // root_types contains all the types. All TopLevel types // hence have a parent that points to `root_types', that is // why there is a non-obvious test down here. // public bool IsTopLevel { get { return (Parent != null && Parent.Parent == null); } } public virtual void CloseType () { if ((caching_flags & Flags.CloseTypeCreated) == 0){ try { TypeBuilder.CreateType (); } catch { // // The try/catch is needed because // nested enumerations fail to load when they // are defined. // // Even if this is the right order (enumerations // declared after types). // // Note that this still creates the type and // it is possible to save it } caching_flags |= Flags.CloseTypeCreated; } } protected virtual TypeAttributes TypeAttr { get { return CodeGen.Module.DefaultCharSetType; } } /// <remarks> /// Should be overriten by the appropriate declaration space /// </remarks> public abstract TypeBuilder DefineType (); /// <summary> /// Define all members, but don't apply any attributes or do anything which may /// access not-yet-defined classes. This method also creates the MemberCache. /// </summary> public virtual bool DefineMembers (TypeContainer parent) { if (((ModFlags & Modifiers.NEW) != 0) && IsTopLevel) { Report.Error (1530, Location, "Keyword `new' is not allowed on namespace elements"); return false; } return true; } public override string GetSignatureForError () { // Parent.GetSignatureForError return Name; } // // Whether this is an `unsafe context' // public bool UnsafeContext { get { if ((ModFlags & Modifiers.UNSAFE) != 0) return true; if (Parent != null) return Parent.UnsafeContext; return false; } } EmitContext type_resolve_ec; protected EmitContext TypeResolveEmitContext { get { if (type_resolve_ec == null) { // FIXME: I think this should really be one of: // // a. type_resolve_ec = Parent.EmitContext; // b. type_resolve_ec = new EmitContext (Parent, Parent, loc, null, null, ModFlags, false); // // However, if Parent == RootContext.Tree.Types, its NamespaceEntry will be null. // type_resolve_ec = new EmitContext (Parent, this, Location.Null, null, null, ModFlags, false); } return type_resolve_ec; } } // <summary> // Resolves the expression `e' for a type, and will recursively define // types. This should only be used for resolving base types. // </summary> public TypeExpr ResolveBaseTypeExpr (Expression e, bool silent, Location loc) { TypeResolveEmitContext.loc = loc; return e.ResolveAsTypeTerminal (TypeResolveEmitContext, silent); } public bool CheckAccessLevel (Type check_type) { if (check_type == TypeBuilder) return true; TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask; // // Broken Microsoft runtime, return public for arrays, no matter what // the accessibility is for their underlying class, and they return // NonPublic visibility for pointers // if (check_type.IsArray || check_type.IsPointer) return CheckAccessLevel (TypeManager.GetElementType (check_type)); if (TypeBuilder == null) // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases(). // However, this is invoked again later -- so safe to return true. // May also be null when resolving top-level attributes. return true; switch (check_attr){ case TypeAttributes.Public: return true; case TypeAttributes.NotPublic: // // This test should probably use the declaringtype. // return check_type.Assembly == TypeBuilder.Assembly; case TypeAttributes.NestedPublic: return true; case TypeAttributes.NestedPrivate: return NestedAccessible (check_type); case TypeAttributes.NestedFamily: return FamilyAccessible (check_type); case TypeAttributes.NestedFamANDAssem: return (check_type.Assembly == TypeBuilder.Assembly) && FamilyAccessible (check_type); case TypeAttributes.NestedFamORAssem: return (check_type.Assembly == TypeBuilder.Assembly) || FamilyAccessible (check_type); case TypeAttributes.NestedAssembly: return check_type.Assembly == TypeBuilder.Assembly; } Console.WriteLine ("HERE: " + check_attr); return false; } protected bool NestedAccessible (Type check_type) { Type declaring = check_type.DeclaringType; return TypeBuilder == declaring || TypeManager.IsNestedChildOf (TypeBuilder, declaring); } protected bool FamilyAccessible (Type check_type) { Type declaring = check_type.DeclaringType; return TypeManager.IsNestedFamilyAccessible (TypeBuilder, declaring); } // Access level of a type. const int X = 1; enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope' // Public Assembly Protected Protected = (0 << 0) | (0 << 1) | (X << 2), Public = (X << 0) | (X << 1) | (X << 2), Private = (0 << 0) | (0 << 1) | (0 << 2), Internal = (0 << 0) | (X << 1) | (0 << 2), ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2), } static AccessLevel GetAccessLevelFromModifiers (int flags) { if ((flags & Modifiers.INTERNAL) != 0) { if ((flags & Modifiers.PROTECTED) != 0) return AccessLevel.ProtectedOrInternal; else return AccessLevel.Internal; } else if ((flags & Modifiers.PROTECTED) != 0) return AccessLevel.Protected; else if ((flags & Modifiers.PRIVATE) != 0) return AccessLevel.Private; else return AccessLevel.Public; } // What is the effective access level of this? // TODO: Cache this? AccessLevel EffectiveAccessLevel { get { AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags); if (!IsTopLevel && (Parent != null)) return myAccess & Parent.EffectiveAccessLevel; else return myAccess; } } // Return the access level for type `t' static AccessLevel TypeEffectiveAccessLevel (Type t) { if (t.IsPublic) return AccessLevel.Public; if (t.IsNestedPrivate) return AccessLevel.Private; if (t.IsNotPublic) return AccessLevel.Internal; // By now, it must be nested AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType); if (t.IsNestedPublic) return parentLevel; if (t.IsNestedAssembly) return parentLevel & AccessLevel.Internal; if (t.IsNestedFamily) return parentLevel & AccessLevel.Protected; if (t.IsNestedFamORAssem) return parentLevel & AccessLevel.ProtectedOrInternal; if (t.IsNestedFamANDAssem) throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways"); // nested private is taken care of throw new Exception ("I give up, what are you?"); } // // This answers `is the type P, as accessible as a member M which has the // accessability @flags which is declared as a nested member of the type T, this declspace' // public bool AsAccessible (Type p, int flags) { // // 1) if M is private, its accessability is the same as this declspace. // we already know that P is accessible to T before this method, so we // may return true. // if ((flags & Modifiers.PRIVATE) != 0) return true; while (p.IsArray || p.IsPointer || p.IsByRef) p = TypeManager.GetElementType (p); AccessLevel pAccess = TypeEffectiveAccessLevel (p); AccessLevel mAccess = this.EffectiveAccessLevel & GetAccessLevelFromModifiers (flags); // for every place from which we can access M, we must // be able to access P as well. So, we want // For every bit in M and P, M_i -> P_1 == true // or, ~ (M -> P) == 0 <-> ~ ( ~M | P) == 0 return ~ (~ mAccess | pAccess) == 0; } // // Return the nested type with name @name. Ensures that the nested type // is defined if necessary. Do _not_ use this when you have a MemberCache handy. // public virtual Type FindNestedType (string name) { return null; } private Type LookupNestedTypeInHierarchy (string name) { // if the member cache has been created, lets use it. // the member cache is MUCH faster. if (MemberCache != null) return MemberCache.FindNestedType (name); // no member cache. Do it the hard way -- reflection Type t = null; for (Type current_type = TypeBuilder; current_type != null && current_type != TypeManager.object_type; current_type = current_type.BaseType) { if (current_type is TypeBuilder) { DeclSpace decl = this; if (current_type != TypeBuilder) decl = TypeManager.LookupDeclSpace (current_type); t = decl.FindNestedType (name); } else { t = TypeManager.GetNestedType (current_type, name); } if (t != null && CheckAccessLevel (t)) return t; } return null; } // // Public function used to locate types. // // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors. // // Returns: Type or null if they type can not be found. // public FullNamedExpression LookupType (string name, Location loc, bool ignore_cs0104) { if (this is PartialContainer) throw new InternalErrorException ("Should not get here"); if (Cache.Contains (name)) return (FullNamedExpression) Cache [name]; FullNamedExpression e; Type t = LookupNestedTypeInHierarchy (name); if (t != null) e = new TypeExpression (t, Location.Null); else if (Parent != null && Parent != RootContext.Tree.Types) e = Parent.LookupType (name, loc, ignore_cs0104); else e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104); Cache [name] = e; return e; } /// <remarks> /// This function is broken and not what you're looking for. It should only /// be used while the type is still being created since it doesn't use the cache /// and relies on the filter doing the member name check. /// </remarks> public abstract MemberList FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria); /// <remarks> /// If we have a MemberCache, return it. This property may return null if the /// class doesn't have a member cache or while it's still being created. /// </remarks> public abstract MemberCache MemberCache { get; } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { if (a.Type == TypeManager.required_attr_type) { Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types"); return; } TypeBuilder.SetCustomAttribute (cb); } /// <summary> /// Goes through class hierarchy and get value of first CLSCompliantAttribute that found. /// If no is attribute exists then return assembly CLSCompliantAttribute. /// </summary> public bool GetClsCompliantAttributeValue () { if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0) return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0; caching_flags &= ~Flags.HasCompliantAttribute_Undetected; if (OptAttributes != null) { Attribute cls_attribute = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, ec); if (cls_attribute != null) { caching_flags |= Flags.HasClsCompliantAttribute; if (cls_attribute.GetClsCompliantAttributeValue (ec)) { caching_flags |= Flags.ClsCompliantAttributeTrue; return true; } return false; } } if (Parent == null) { if (CodeGen.Assembly.IsClsCompliant) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -