📄 attribute.cs
字号:
//// attribute.cs: Attribute Handler//// Author: Ravi Pratap (ravi@ximian.com)// Marek Safar (marek.safar@seznam.cz)//// Licensed under the terms of the GNU GPL//// (C) 2001 Ximian, Inc (http://www.ximian.com)////using System;using System.Diagnostics;using System.Collections;using System.Collections.Specialized;using System.Reflection;using System.Reflection.Emit;using System.Runtime.InteropServices;using System.Runtime.CompilerServices;using System.Security; using System.Security.Permissions;using System.Text;using System.IO;namespace Mono.CSharp { /// <summary> /// Base class for objects that can have Attributes applied to them. /// </summary> public abstract class Attributable { /// <summary> /// Attributes for this type /// </summary> Attributes attributes; public Attributable (Attributes attrs) { attributes = attrs; } public Attributes OptAttributes { get { return attributes; } set { attributes = value; } } /// <summary> /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder /// </summary> public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb); /// <summary> /// Returns one AttributeTarget for this element. /// </summary> public abstract AttributeTargets AttributeTargets { get; } public abstract bool IsClsCompliaceRequired (DeclSpace ds); /// <summary> /// Gets list of valid attribute targets for explicit target declaration. /// The first array item is default target. Don't break this rule. /// </summary> public abstract string[] ValidAttributeTargets { get; } }; public class Attribute { public readonly string ExplicitTarget; public AttributeTargets Target; // TODO: remove this member public readonly string Name; public readonly Expression LeftExpr; public readonly string Identifier; public readonly ArrayList Arguments; public readonly Location Location; public Type Type; bool resolve_error; readonly bool nameEscaped; static AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All); static Assembly orig_sec_assembly; // non-null if named args present after Resolve () is called PropertyInfo [] prop_info_arr; FieldInfo [] field_info_arr; object [] field_values_arr; object [] prop_values_arr; object [] pos_values; static PtrHashtable usage_attr_cache = new PtrHashtable (); public Attribute (string target, Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped) { LeftExpr = left_expr; Identifier = identifier; Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier; Arguments = args; Location = loc; ExplicitTarget = target; this.nameEscaped = nameEscaped; } void Error_InvalidNamedArgument (string name) { Report.Error (617, Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " + "must be fields which are not readonly, static, const or read-write properties which are " + "public and not static", name); } void Error_InvalidNamedAgrumentType (string name) { Report.Error (655, Location, "`{0}' is not a valid named attribute argument because it is not a valid " + "attribute parameter type", name); } static void Error_AttributeArgumentNotValid (string extra, Location loc) { Report.Error (182, loc, "An attribute argument must be a constant expression, typeof " + "expression or array creation expression" + extra); } static void Error_AttributeArgumentNotValid (Location loc) { Error_AttributeArgumentNotValid ("", loc); } /// <summary> /// This is rather hack. We report many emit attribute error with same error to be compatible with /// csc. But because csc has to report them this way because error came from ilasm we needn't. /// </summary> public void Error_AttributeEmitError (string inner) { Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'", TypeManager.CSharpName (Type), inner); } public void Error_InvalidSecurityParent () { Error_AttributeEmitError ("it is attached to invalid parent"); } protected virtual FullNamedExpression ResolveAsTypeTerminal (Expression expr, EmitContext ec, bool silent) { return expr.ResolveAsTypeTerminal (ec, silent); } protected virtual FullNamedExpression ResolveAsTypeStep (Expression expr, EmitContext ec, bool silent) { return expr.ResolveAsTypeStep (ec, silent); } Type ResolvePossibleAttributeType (EmitContext ec, string name, bool silent, ref bool is_attr) { FullNamedExpression fn; if (LeftExpr == null) { fn = ResolveAsTypeTerminal (new SimpleName (name, Location), ec, silent); } else { fn = ResolveAsTypeStep (LeftExpr, ec, silent); if (fn == null) return null; fn = new MemberAccess (fn, name, Location).ResolveAsTypeTerminal (ec, silent); } TypeExpr te = fn as TypeExpr; if (te == null) return null; Type t = te.Type; if (t.IsSubclassOf (TypeManager.attribute_type)) { is_attr = true; } else if (!silent) { Report.SymbolRelatedToPreviousError (t); Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t)); } return t; } /// <summary> /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true. /// </summary> void ResolveAttributeType (EmitContext ec) { bool t1_is_attr = false; Type t1 = ResolvePossibleAttributeType (ec, Identifier, true, ref t1_is_attr); bool t2_is_attr = false; Type t2 = nameEscaped ? null : ResolvePossibleAttributeType (ec, Identifier + "Attribute", true, ref t2_is_attr); if (t1_is_attr && t2_is_attr) { Report.Error (1614, Location, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " + "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ()); resolve_error = true; return; } if (t1_is_attr) { Type = t1; return; } if (t2_is_attr) { Type = t2; return; } if (t1 == null && t2 == null) ResolvePossibleAttributeType (ec, Identifier, false, ref t1_is_attr); if (t1 != null) ResolvePossibleAttributeType (ec, Identifier, false, ref t1_is_attr); if (t2 != null) ResolvePossibleAttributeType (ec, Identifier + "Attribute", false, ref t2_is_attr); resolve_error = true; } public virtual Type ResolveType (EmitContext ec) { if (Type == null && !resolve_error) ResolveAttributeType (ec); return Type; } public string GetSignatureForError () { return LeftExpr == null ? Identifier : LeftExpr.GetSignatureForError () + "." + Identifier; } // // Given an expression, if the expression is a valid attribute-argument-expression // returns an object that can be used to encode it, or null on failure. // public static bool GetAttributeArgumentExpression (Expression e, Location loc, Type arg_type, out object result) { Constant constant = e as Constant; if (constant != null) { constant = constant.ToType (arg_type, loc); if (constant == null) { result = null; return false; } result = constant.GetTypedValue (); return true; } else if (e is TypeOf) { result = ((TypeOf) e).TypeArg; return true; } else if (e is ArrayCreation){ result = ((ArrayCreation) e).EncodeAsAttribute (); if (result != null) return true; } else if (e is EmptyCast) { Expression child = ((EmptyCast)e).Child; return GetAttributeArgumentExpression (child, loc, child.Type, out result); } else if (e is As) { As as_e = (As) e; return GetAttributeArgumentExpression (as_e.Expr, loc, as_e.ProbeType.Type, out result); } result = null; Error_AttributeArgumentNotValid (loc); return false; } bool IsValidArgumentType (Type t) { if (t.IsArray) t = t.GetElementType (); return TypeManager.IsPrimitiveType (t) || TypeManager.IsEnumType (t) || t == TypeManager.string_type || t == TypeManager.object_type || t == TypeManager.type_type; } // Cache for parameter-less attributes static PtrHashtable att_cache = new PtrHashtable (); public CustomAttributeBuilder Resolve (EmitContext ec) { if (resolve_error) return null; resolve_error = true; if (Type == null) { ResolveAttributeType (ec); if (Type == null) return null; } if (Type.IsAbstract) { Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ()); return null; } ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (Type); if (obsolete_attr != null) { AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location); } if (Arguments == null) { object o = att_cache [Type]; if (o != null) { resolve_error = false; return (CustomAttributeBuilder)o; } } ConstructorInfo ctor = ResolveArguments (ec); if (ctor == null) return null; CustomAttributeBuilder cb; try { if (prop_info_arr != null || field_info_arr != null) { cb = new CustomAttributeBuilder ( ctor, pos_values, prop_info_arr, prop_values_arr, field_info_arr, field_values_arr); } else { cb = new CustomAttributeBuilder ( ctor, pos_values); if (pos_values.Length == 0) att_cache.Add (Type, cb); } } catch (Exception) { Error_AttributeArgumentNotValid (Location); return null; } resolve_error = false; return cb; } protected virtual ConstructorInfo ResolveArguments (EmitContext ec) { // Now we extract the positional and named arguments ArrayList pos_args = null; ArrayList named_args = null; int pos_arg_count = 0; int named_arg_count = 0; if (Arguments != null) { pos_args = (ArrayList) Arguments [0]; if (pos_args != null) pos_arg_count = pos_args.Count; if (Arguments.Count > 1) { named_args = (ArrayList) Arguments [1]; named_arg_count = named_args.Count; } } pos_values = new object [pos_arg_count]; // // First process positional arguments // int i; for (i = 0; i < pos_arg_count; i++) { Argument a = (Argument) pos_args [i]; Expression e; if (!a.Resolve (ec, Location)) return null; e = a.Expr; object val; if (!GetAttributeArgumentExpression (e, Location, a.Type, out val)) return null; pos_values [i] = val; if (i == 0 && Type == TypeManager.attribute_usage_type && (int)val == 0) { Report.Error (591, Location, "Invalid value for argument to 'System.AttributeUsage' attribute"); return null; } } // // Now process named arguments // ArrayList field_infos = null; ArrayList prop_infos = null; ArrayList field_values = null; ArrayList prop_values = null; Hashtable seen_names = null; if (named_arg_count > 0) { field_infos = new ArrayList (); prop_infos = new ArrayList (); field_values = new ArrayList (); prop_values = new ArrayList (); seen_names = new Hashtable(); } for (i = 0; i < named_arg_count; i++) { DictionaryEntry de = (DictionaryEntry) named_args [i]; string member_name = (string) de.Key; Argument a = (Argument) de.Value; Expression e; if (seen_names.Contains(member_name)) { Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument"); return null; } seen_names.Add(member_name, 1); if (!a.Resolve (ec, Location)) return null; Expression member = Expression.MemberLookup ( ec, Type, member_name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, Location); if (member == null) { member = Expression.MemberLookup (ec, Type, member_name, MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance, Location); if (member != null) { Expression.ErrorIsInaccesible (Location, member.GetSignatureForError ()); return null; } } if (member == null){ Report.Error (117, Location, "`{0}' does not contain a definition for `{1}'", Type, member_name); return null; } if (!(member is PropertyExpr || member is FieldExpr)) { Error_InvalidNamedArgument (member_name); return null; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -