📄 decl.cs
字号:
//// decl.cs: Declaration base class for structs, classes, enums and interfaces.//// Author: Miguel de Icaza (miguel@gnu.org)// Marek Safar (marek.safar@seznam.cz)//// Licensed under the terms of the GNU GPL//// (C) 2001 Ximian, Inc (http://www.ximian.com)// (C) 2004 Novell, Inc//// TODO: Move the method verification stuff from the class.cs and interface.cs here//using System;using System.Collections;using System.Globalization;using System.Reflection.Emit;using System.Reflection;#if BOOTSTRAP_WITH_OLDLIBusing XmlElement = System.Object;#elseusing System.Xml;#endifnamespace Mono.CSharp { public class MemberName { public readonly string Name; public readonly MemberName Left; public readonly Location Location; bool is_double_colon; public static readonly MemberName Null = new MemberName (""); private MemberName (MemberName left, string name, bool is_double_colon, Location loc) { this.Name = name; this.Location = loc; this.is_double_colon = is_double_colon; this.Left = left; } public MemberName (string name) : this (null, name, false, Location.Null) { } public MemberName (MemberName left, string name) : this (left, name, false, left != null ? left.Location : Location.Null) { } public MemberName (string name, Location loc) : this (null, name, false, loc) { } public MemberName (MemberName left, string name, Location loc) : this (left, name, false, loc) { } public MemberName (string alias, string name, Location loc) : this (new MemberName (alias), name, true, loc) { } public MemberName (MemberName left, MemberName right) : this (left, right, right.Location) { } public MemberName (MemberName left, MemberName right, Location loc) : this (null, right.Name, false, loc) { if (right.is_double_colon) throw new InternalErrorException ("Cannot append double_colon member name"); this.Left = (right.Left == null) ? left : new MemberName (left, right.Left); } static readonly char [] dot_array = { '.' }; public static MemberName FromDotted (string name) { string [] elements = name.Split (dot_array); int count = elements.Length; int i = 0; MemberName n = new MemberName (elements [i++]); while (i < count) n = new MemberName (n, elements [i++]); return n; } public string GetName () { return GetName (false); } public string GetName (bool is_generic) { string name = is_generic ? Basename : Name; string connect = is_double_colon ? "::" : "."; if (Left != null) return Left.GetName (is_generic) + connect + name; else return name; } /// /// This returns exclusively the name as seen on the source code /// it is not the fully qualifed type after resolution /// public string GetPartialName () { string connect = is_double_colon ? "::" : "."; if (Left != null) return Left.GetPartialName () + connect + Name; else return Name; } public string GetTypeName () { string connect = is_double_colon ? "::" : "."; if (Left != null) return Left.GetTypeName () + connect + Name; else return Name; } public Expression GetTypeExpression () { if (Left == null) return new SimpleName (Name, Location); if (is_double_colon) { if (Left.Left != null) throw new InternalErrorException ("The left side of a :: should be an identifier"); return new QualifiedAliasMember (Left.Name, Name, Location); } Expression lexpr = Left.GetTypeExpression (); return new MemberAccess (lexpr, Name, Location); } public MemberName Clone () { MemberName left_clone = Left == null ? null : Left.Clone (); return new MemberName (left_clone, Name, is_double_colon, Location); } public string Basename { get { return Name; } } public override string ToString () { string connect = is_double_colon ? "::" : "."; if (Left != null) return Left + connect + Name; else return Name; } public override bool Equals (object other) { return Equals (other as MemberName); } public bool Equals (MemberName other) { if (this == other) return true; if (other == null || Name != other.Name) return false; if (is_double_colon != other.is_double_colon) return false;#if NET_2_0 if (TypeArguments == null) return other.TypeArguments == null; if (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count) return false;#endif if (Left == null) return other.Left == null; return Left.Equals (other.Left); } public override int GetHashCode () { int hash = Name.GetHashCode (); for (MemberName n = Left; n != null; n = n.Left) hash ^= n.Name.GetHashCode (); if (is_double_colon) hash ^= 0xbadc01d;#if NET_2_0 if (TypeArguments != null) hash ^= TypeArguments.Count << 5;#endif return hash & 0x7FFFFFFF; } } /// <summary> /// Base representation for members. This is used to keep track /// of Name, Location and Modifier flags, and handling Attributes. /// </summary> public abstract class MemberCore : Attributable { /// <summary> /// Public name /// </summary> protected string cached_name; public string Name { get { if (cached_name == null) cached_name = MemberName.GetName (false); return cached_name; } } // Is not readonly because of IndexerName attribute private MemberName member_name; public MemberName MemberName { get { return member_name; } } /// <summary> /// Modifier flags that the user specified in the source code /// </summary> public int ModFlags; public /*readonly*/ TypeContainer Parent; /// <summary> /// Location where this declaration happens /// </summary> public Location Location { get { return member_name.Location; } } /// <summary> /// XML documentation comment /// </summary> public string DocComment; /// <summary> /// Represents header string for documentation comment /// for each member types. /// </summary> public abstract string DocCommentHeader { get; } [Flags] public enum Flags { Obsolete_Undetected = 1, // Obsolete attribute has not been detected yet Obsolete = 1 << 1, // Type has obsolete attribute ClsCompliance_Undetected = 1 << 2, // CLS Compliance has not been detected yet ClsCompliant = 1 << 3, // Type is CLS Compliant CloseTypeCreated = 1 << 4, // Tracks whether we have Closed the type HasCompliantAttribute_Undetected = 1 << 5, // Presence of CLSCompliantAttribute has not been detected HasClsCompliantAttribute = 1 << 6, // Type has CLSCompliantAttribute ClsCompliantAttributeTrue = 1 << 7, // Type has CLSCompliant (true) Excluded_Undetected = 1 << 8, // Conditional attribute has not been detected yet Excluded = 1 << 9, // Method is conditional TestMethodDuplication = 1 << 10, // Test for duplication must be performed IsUsed = 1 << 11, IsAssigned = 1 << 12 // Field is assigned } /// <summary> /// MemberCore flags at first detected then cached /// </summary> internal Flags caching_flags; public MemberCore (TypeContainer parent, MemberName name, Attributes attrs) : base (attrs) { if (parent is PartialContainer && !(this is PartialContainer)) throw new InternalErrorException ("A PartialContainer cannot be the direct parent of a member"); Parent = parent; member_name = name; caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected; } protected virtual void SetMemberName (MemberName new_name) { member_name = new_name; cached_name = null; } public abstract bool Define (); // // Returns full member name for error message // public virtual string GetSignatureForError () { if (Parent == null || Parent.Parent == null) return Name; return String.Concat (Parent.GetSignatureForError (), '.', Name); } /// <summary> /// Base Emit method. This is also entry point for CLS-Compliant verification. /// </summary> public virtual void Emit () { if (!RootContext.VerifyClsCompliance) return; VerifyClsCompliance (Parent); } public virtual EmitContext EmitContext { get { return Parent.EmitContext; } } public bool InUnsafe { get { return ((ModFlags & Modifiers.UNSAFE) != 0) || Parent.UnsafeContext; } } public virtual bool IsUsed { get { return (caching_flags & Flags.IsUsed) != 0; } } public void SetMemberIsUsed () { caching_flags |= Flags.IsUsed; } // // Whehter is it ok to use an unsafe pointer in this type container // public bool UnsafeOK (DeclSpace parent) { // // First check if this MemberCore modifier flags has unsafe set // if ((ModFlags & Modifiers.UNSAFE) != 0) return true; if (parent.UnsafeContext) return true; Expression.UnsafeError (Location); return false; } /// <summary> /// Returns instance of ObsoleteAttribute for this MemberCore /// </summary> public virtual ObsoleteAttribute GetObsoleteAttribute () { // ((flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0) is slower, but why ? if ((caching_flags & Flags.Obsolete_Undetected) == 0 && (caching_flags & Flags.Obsolete) == 0) { return null; } caching_flags &= ~Flags.Obsolete_Undetected; if (OptAttributes == null) return null; Attribute obsolete_attr = OptAttributes.Search ( TypeManager.obsolete_attribute_type, EmitContext); if (obsolete_attr == null) return null; ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (EmitContext); if (obsolete == null) return null; caching_flags |= Flags.Obsolete; return obsolete; } /// <summary> /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements /// </summary> public virtual void CheckObsoleteness (Location loc) { if (Parent != null) Parent.CheckObsoleteness (loc); ObsoleteAttribute oa = GetObsoleteAttribute (); if (oa == null) { return; } AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc); } protected void CheckObsoleteType (Expression type) { ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type.Type); if (obsolete_attr == null) return; if (GetObsoleteAttribute () != null || Parent.GetObsoleteAttribute () != null) return; AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (type.Type), type.Location); } /// <summary> /// Analyze whether CLS-Compliant verification must be execute for this MemberCore. /// </summary> public override bool IsClsCompliaceRequired (DeclSpace container) { if ((caching_flags & Flags.ClsCompliance_Undetected) == 0) return (caching_flags & Flags.ClsCompliant) != 0; if (GetClsCompliantAttributeValue (container) && IsExposedFromAssembly (container)) { caching_flags &= ~Flags.ClsCompliance_Undetected; caching_flags |= Flags.ClsCompliant; return true; } caching_flags &= ~Flags.ClsCompliance_Undetected; return false; } /// <summary> /// Returns true when MemberCore is exposed from assembly. /// </summary> public bool IsExposedFromAssembly (DeclSpace ds) { if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0) return false; DeclSpace parentContainer = ds; while (parentContainer != null && parentContainer.ModFlags != 0) { if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0) return false; parentContainer = parentContainer.Parent; } return true; } /// <summary> /// Resolve CLSCompliantAttribute value or gets cached value. /// </summary> bool GetClsCompliantAttributeValue (DeclSpace ds) { if (OptAttributes != null) { Attribute cls_attribute = OptAttributes.Search ( TypeManager.cls_compliant_attribute_type, ds.EmitContext); if (cls_attribute != null) { caching_flags |= Flags.HasClsCompliantAttribute; return cls_attribute.GetClsCompliantAttributeValue (ds.EmitContext); } } return ds.GetClsCompliantAttributeValue (); } /// <summary> /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute /// </summary> protected bool HasClsCompliantAttribute { get { return (caching_flags & Flags.HasClsCompliantAttribute) != 0; } } /// <summary> /// It helps to handle error 102 & 111 detection /// </summary> public virtual bool MarkForDuplicationCheck () { return false; } /// <summary> /// The main virtual method for CLS-Compliant verifications. /// The method returns true if member is CLS-Compliant and false if member is not /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it /// and add their extra verifications. /// </summary> protected virtual bool VerifyClsCompliance (DeclSpace ds) { if (!IsClsCompliaceRequired (ds)) { if (HasClsCompliantAttribute && RootContext.WarningLevel >= 2) { if (!IsExposedFromAssembly (ds)) Report.Warning (3019, Location, "CLS compliance checking will not be performed on `{0}' because it is not visible from outside this assembly", GetSignatureForError ()); if (!CodeGen.Assembly.IsClsCompliant) Report.Warning (3021, Location, "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant", GetSignatureForError ()); } return false; } if (!CodeGen.Assembly.IsClsCompliant) { if (HasClsCompliantAttribute) { Report.Error (3014, Location, "`{0}' cannot be marked as CLS-compliant because the assembly is not marked as CLS-compliant", GetSignatureForError ()); } return false; } if (member_name.Name [0] == '_') { Report.Error (3008, Location, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -