2 // attribute.cs: Attribute Handler
4 // Author: Ravi Pratap (ravi@ximian.com)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System.Diagnostics;
15 using System.Collections;
16 using System.Collections.Specialized;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Runtime.InteropServices;
20 using System.Runtime.CompilerServices;
21 using System.Security;
22 using System.Security.Permissions;
26 namespace Mono.CSharp {
29 /// Base class for objects that can have Attributes applied to them.
31 public abstract class Attributable {
33 /// Attributes for this type
35 Attributes attributes;
37 public Attributable (Attributes attrs)
39 OptAttributes = attrs;
42 public Attributes OptAttributes
50 if (attributes != null) {
51 attributes.AttachTo (this);
57 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
59 public abstract void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb);
62 /// Returns one AttributeTarget for this element.
64 public abstract AttributeTargets AttributeTargets { get; }
66 public abstract IResolveContext ResolveContext { get; }
68 public abstract bool IsClsComplianceRequired ();
71 /// Gets list of valid attribute targets for explicit target declaration.
72 /// The first array item is default target. Don't break this rule.
74 public abstract string[] ValidAttributeTargets { get; }
77 public class Attribute {
78 public readonly string ExplicitTarget;
79 public AttributeTargets Target;
81 // TODO: remove this member
82 public readonly string Name;
83 public readonly Expression LeftExpr;
84 public readonly string Identifier;
86 public readonly ArrayList Arguments;
88 public readonly Location Location;
93 readonly bool nameEscaped;
96 static AttributeUsageAttribute DefaultUsageAttribute = new AttributeUsageAttribute (AttributeTargets.All);
97 static Assembly orig_sec_assembly;
99 // non-null if named args present after Resolve () is called
100 PropertyInfo [] prop_info_arr;
101 FieldInfo [] field_info_arr;
102 object [] field_values_arr;
103 object [] prop_values_arr;
104 object [] pos_values;
106 static PtrHashtable usage_attr_cache = new PtrHashtable ();
108 public Attribute (string target, Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped)
110 LeftExpr = left_expr;
111 Identifier = identifier;
112 Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier;
115 ExplicitTarget = target;
116 this.nameEscaped = nameEscaped;
119 public void AttachTo (Attributable owner)
124 void Error_InvalidNamedArgument (string name)
126 Report.Error (617, Location, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
127 "must be fields which are not readonly, static, const or read-write properties which are " +
128 "public and not static",
132 void Error_InvalidNamedAgrumentType (string name)
134 Report.Error (655, Location, "`{0}' is not a valid named attribute argument because it is not a valid " +
135 "attribute parameter type", name);
138 static void Error_AttributeArgumentNotValid (string extra, Location loc)
140 Report.Error (182, loc,
141 "An attribute argument must be a constant expression, typeof " +
142 "expression or array creation expression" + extra);
145 static void Error_AttributeArgumentNotValid (Location loc)
147 Error_AttributeArgumentNotValid ("", loc);
152 /// This is rather hack. We report many emit attribute error with same error to be compatible with
153 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
155 public void Error_AttributeEmitError (string inner)
157 Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
158 TypeManager.CSharpName (Type), inner);
161 public void Error_InvalidSecurityParent ()
163 Error_AttributeEmitError ("it is attached to invalid parent");
166 protected virtual FullNamedExpression ResolveAsTypeTerminal (Expression expr, IResolveContext ec, bool silent)
168 return expr.ResolveAsTypeTerminal (ec, silent);
171 protected virtual FullNamedExpression ResolveAsTypeStep (Expression expr, IResolveContext ec, bool silent)
173 return expr.ResolveAsTypeStep (ec, silent);
176 Type ResolvePossibleAttributeType (string name, bool silent, ref bool is_attr)
178 IResolveContext rc = owner.ResolveContext;
180 FullNamedExpression fn;
181 if (LeftExpr == null) {
182 fn = ResolveAsTypeTerminal (new SimpleName (name, Location), rc, silent);
184 fn = ResolveAsTypeStep (LeftExpr, rc, silent);
187 fn = new MemberAccess (fn, name, Location).ResolveAsTypeTerminal (rc, silent);
190 TypeExpr te = fn as TypeExpr;
195 if (TypeManager.IsSubclassOf (t, TypeManager.attribute_type)) {
197 } else if (!silent) {
198 Report.SymbolRelatedToPreviousError (t);
199 Report.Error (616, Location, "`{0}': is not an attribute class", TypeManager.CSharpName (t));
205 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
207 void ResolveAttributeType ()
209 bool t1_is_attr = false;
210 Type t1 = ResolvePossibleAttributeType (Identifier, true, ref t1_is_attr);
212 bool t2_is_attr = false;
213 Type t2 = nameEscaped ? null :
214 ResolvePossibleAttributeType (Identifier + "Attribute", true, ref t2_is_attr);
216 if (t1_is_attr && t2_is_attr) {
217 Report.Error (1614, Location, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " +
218 "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
219 resolve_error = true;
233 if (t1 == null && t2 == null)
234 ResolvePossibleAttributeType (Identifier, false, ref t1_is_attr);
236 ResolvePossibleAttributeType (Identifier, false, ref t1_is_attr);
238 ResolvePossibleAttributeType (Identifier + "Attribute", false, ref t2_is_attr);
240 resolve_error = true;
243 public virtual Type ResolveType ()
245 if (Type == null && !resolve_error)
246 ResolveAttributeType ();
250 public string GetSignatureForError ()
253 return TypeManager.CSharpName (Type);
255 return LeftExpr == null ? Identifier : LeftExpr.GetSignatureForError () + "." + Identifier;
259 // Given an expression, if the expression is a valid attribute-argument-expression
260 // returns an object that can be used to encode it, or null on failure.
262 public static bool GetAttributeArgumentExpression (Expression e, Location loc, Type arg_type, out object result)
264 Constant constant = e as Constant;
265 if (constant != null) {
266 constant = constant.ToType (arg_type, loc);
267 if (constant == null) {
271 result = constant.GetTypedValue ();
273 } else if (e is TypeOf) {
274 result = ((TypeOf) e).TypeArg;
276 } else if (e is ArrayCreation){
277 result = ((ArrayCreation) e).EncodeAsAttribute ();
280 } else if (e is EmptyCast) {
281 Expression child = ((EmptyCast)e).Child;
282 return GetAttributeArgumentExpression (child, loc, child.Type, out result);
283 } else if (e is As) {
285 return GetAttributeArgumentExpression (as_e.Expr, loc, as_e.ProbeType.Type, out result);
289 Error_AttributeArgumentNotValid (loc);
293 bool IsValidArgumentType (Type t)
296 t = t.GetElementType ();
298 return TypeManager.IsPrimitiveType (t) ||
299 TypeManager.IsEnumType (t) ||
300 t == TypeManager.string_type ||
301 t == TypeManager.object_type ||
302 t == TypeManager.type_type;
305 // Cache for parameter-less attributes
306 static PtrHashtable att_cache = new PtrHashtable ();
308 public CustomAttributeBuilder Resolve ()
313 resolve_error = true;
316 ResolveAttributeType ();
321 if (Type.IsAbstract) {
322 Report.Error (653, Location, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
326 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (Type);
327 if (obsolete_attr != null) {
328 AttributeTester.Report_ObsoleteMessage (obsolete_attr, TypeManager.CSharpName (Type), Location);
331 if (Arguments == null) {
332 object o = att_cache [Type];
334 resolve_error = false;
335 return (CustomAttributeBuilder)o;
339 ConstructorInfo ctor = ResolveArguments ();
343 CustomAttributeBuilder cb;
346 if (prop_info_arr != null || field_info_arr != null) {
347 cb = new CustomAttributeBuilder (
349 prop_info_arr, prop_values_arr,
350 field_info_arr, field_values_arr);
352 cb = new CustomAttributeBuilder (
355 if (pos_values.Length == 0)
356 att_cache.Add (Type, cb);
360 Error_AttributeArgumentNotValid (Location);
364 resolve_error = false;
368 protected virtual ConstructorInfo ResolveArguments ()
370 // Now we extract the positional and named arguments
372 ArrayList pos_args = null;
373 ArrayList named_args = null;
374 int pos_arg_count = 0;
375 int named_arg_count = 0;
377 if (Arguments != null) {
378 pos_args = (ArrayList) Arguments [0];
379 if (pos_args != null)
380 pos_arg_count = pos_args.Count;
381 if (Arguments.Count > 1) {
382 named_args = (ArrayList) Arguments [1];
383 named_arg_count = named_args.Count;
387 pos_values = new object [pos_arg_count];
390 // First process positional arguments
393 EmitContext ec = new EmitContext (owner.ResolveContext, owner.ResolveContext.DeclContainer, owner.ResolveContext.DeclContainer,
394 Location, null, null, owner.ResolveContext.DeclContainer.ModFlags, false);
397 for (i = 0; i < pos_arg_count; i++) {
398 Argument a = (Argument) pos_args [i];
401 if (!a.Resolve (ec, Location))
407 if (!GetAttributeArgumentExpression (e, Location, a.Type, out val))
410 pos_values [i] = val;
412 if (i == 0 && Type == TypeManager.attribute_usage_type && (int)val == 0) {
413 Report.Error (591, Location, "Invalid value for argument to 'System.AttributeUsage' attribute");
419 // Now process named arguments
422 ArrayList field_infos = null;
423 ArrayList prop_infos = null;
424 ArrayList field_values = null;
425 ArrayList prop_values = null;
426 Hashtable seen_names = null;
428 if (named_arg_count > 0) {
429 field_infos = new ArrayList (4);
430 prop_infos = new ArrayList (4);
431 field_values = new ArrayList (4);
432 prop_values = new ArrayList (4);
434 seen_names = new Hashtable(4);
437 for (i = 0; i < named_arg_count; i++) {
438 DictionaryEntry de = (DictionaryEntry) named_args [i];
439 string member_name = (string) de.Key;
440 Argument a = (Argument) de.Value;
443 if (seen_names.Contains(member_name)) {
444 Report.Error(643, Location, "'" + member_name + "' duplicate named attribute argument");
447 seen_names.Add(member_name, 1);
449 if (!a.Resolve (ec, Location))
452 Expression member = Expression.MemberLookup (
453 ec.ContainerType, Type, member_name,
454 MemberTypes.Field | MemberTypes.Property,
455 BindingFlags.Public | BindingFlags.Instance,
458 if (member == null) {
459 member = Expression.MemberLookup (ec.ContainerType, Type, member_name,
460 MemberTypes.Field | MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance,
463 if (member != null) {
464 Expression.ErrorIsInaccesible (Location, member.GetSignatureForError ());
470 Report.Error (117, Location, "`{0}' does not contain a definition for `{1}'",
471 TypeManager.CSharpName (Type), member_name);
475 if (!(member is PropertyExpr || member is FieldExpr)) {
476 Error_InvalidNamedArgument (member_name);
481 if (member is PropertyExpr) {
482 PropertyExpr pe = (PropertyExpr) member;
483 PropertyInfo pi = pe.PropertyInfo;
485 if (!pi.CanWrite || !pi.CanRead) {
486 Report.SymbolRelatedToPreviousError (pi);
487 Error_InvalidNamedArgument (member_name);
491 if (!IsValidArgumentType (pi.PropertyType)) {
492 Report.SymbolRelatedToPreviousError (pi);
493 Error_InvalidNamedAgrumentType (member_name);
498 if (!GetAttributeArgumentExpression (e, Location, pi.PropertyType, out value))
501 prop_values.Add (value);
504 } else if (member is FieldExpr) {
505 FieldExpr fe = (FieldExpr) member;
506 FieldInfo fi = fe.FieldInfo;
509 Error_InvalidNamedArgument (member_name);
513 if (!IsValidArgumentType (fi.FieldType)) {
514 Report.SymbolRelatedToPreviousError (fi);
515 Error_InvalidNamedAgrumentType (member_name);
520 if (!GetAttributeArgumentExpression (e, Location, fi.FieldType, out value))
523 field_values.Add (value);
524 field_infos.Add (fi);
528 Expression mg = Expression.MemberLookup (ec.ContainerType,
529 Type, ".ctor", MemberTypes.Constructor,
530 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
533 MethodBase constructor = Invocation.OverloadResolve (
534 ec, (MethodGroupExpr) mg, pos_args, false, Location);
536 if (constructor == null) {
541 // Here we do the checks which should be done by corlib or by runtime.
542 // However Zoltan doesn't like it and every Mono compiler has to do it again.
544 if (Type == TypeManager.guid_attr_type) {
546 new Guid ((string)pos_values [0]);
548 catch (Exception e) {
549 Error_AttributeEmitError (e.Message);
554 if (Type == TypeManager.methodimpl_attr_type &&
555 pos_values.Length == 1 && ((Argument)pos_args [0]).Type == TypeManager.short_type &&
556 !System.Enum.IsDefined (typeof (MethodImplOptions), pos_values [0])) {
557 Error_AttributeEmitError ("Incorrect argument value.");
562 // Now we perform some checks on the positional args as they
563 // cannot be null for a constructor which expects a parameter
567 ParameterData pd = TypeManager.GetParameterData (constructor);
569 int last_real_param = pd.Count;
571 // When the params is not filled we need to put one
572 if (last_real_param > pos_arg_count) {
573 object [] new_pos_values = new object [pos_arg_count + 1];
574 pos_values.CopyTo (new_pos_values, 0);
575 new_pos_values [pos_arg_count] = new object [] {} ;
576 pos_values = new_pos_values;
581 for (int j = 0; j < pos_arg_count; ++j) {
582 Argument a = (Argument) pos_args [j];
584 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
585 Error_AttributeArgumentNotValid (Location);
589 object value = pos_values [j];
590 if (value != null && a.Type != value.GetType () && TypeManager.IsPrimitiveType (a.Type)) {
592 pos_values [j] = TypeManager.ChangeType (value, a.Type, out fail);
594 // TODO: Can failed ?
595 throw new NotImplementedException ();
599 if (j < last_real_param)
602 if (j == last_real_param) {
603 object [] array = new object [pos_arg_count - last_real_param];
604 array [0] = pos_values [j];
605 pos_values [j] = array;
609 object [] params_array = (object []) pos_values [last_real_param];
610 params_array [j - last_real_param] = pos_values [j];
613 // Adjust the size of the pos_values if it had params
614 if (last_real_param != pos_arg_count) {
615 object [] new_pos_values = new object [last_real_param + 1];
616 Array.Copy (pos_values, new_pos_values, last_real_param + 1);
617 pos_values = new_pos_values;
620 if (named_arg_count > 0) {
621 prop_info_arr = new PropertyInfo [prop_infos.Count];
622 field_info_arr = new FieldInfo [field_infos.Count];
623 field_values_arr = new object [field_values.Count];
624 prop_values_arr = new object [prop_values.Count];
626 field_infos.CopyTo (field_info_arr, 0);
627 field_values.CopyTo (field_values_arr, 0);
629 prop_values.CopyTo (prop_values_arr, 0);
630 prop_infos.CopyTo (prop_info_arr, 0);
633 return (ConstructorInfo) constructor;
637 /// Get a string containing a list of valid targets for the attribute 'attr'
639 public string GetValidTargets ()
641 StringBuilder sb = new StringBuilder ();
642 AttributeTargets targets = GetAttributeUsage ().ValidOn;
644 if ((targets & AttributeTargets.Assembly) != 0)
645 sb.Append ("assembly, ");
647 if ((targets & AttributeTargets.Module) != 0)
648 sb.Append ("module, ");
650 if ((targets & AttributeTargets.Class) != 0)
651 sb.Append ("class, ");
653 if ((targets & AttributeTargets.Struct) != 0)
654 sb.Append ("struct, ");
656 if ((targets & AttributeTargets.Enum) != 0)
657 sb.Append ("enum, ");
659 if ((targets & AttributeTargets.Constructor) != 0)
660 sb.Append ("constructor, ");
662 if ((targets & AttributeTargets.Method) != 0)
663 sb.Append ("method, ");
665 if ((targets & AttributeTargets.Property) != 0)
666 sb.Append ("property, indexer, ");
668 if ((targets & AttributeTargets.Field) != 0)
669 sb.Append ("field, ");
671 if ((targets & AttributeTargets.Event) != 0)
672 sb.Append ("event, ");
674 if ((targets & AttributeTargets.Interface) != 0)
675 sb.Append ("interface, ");
677 if ((targets & AttributeTargets.Parameter) != 0)
678 sb.Append ("parameter, ");
680 if ((targets & AttributeTargets.Delegate) != 0)
681 sb.Append ("delegate, ");
683 if ((targets & AttributeTargets.ReturnValue) != 0)
684 sb.Append ("return, ");
687 if ((targets & AttributeTargets.GenericParameter) != 0)
688 sb.Append ("type parameter, ");
690 return sb.Remove (sb.Length - 2, 2).ToString ();
694 /// Returns AttributeUsage attribute for this type
696 AttributeUsageAttribute GetAttributeUsage ()
698 AttributeUsageAttribute ua = usage_attr_cache [Type] as AttributeUsageAttribute;
702 Class attr_class = TypeManager.LookupClass (Type);
704 if (attr_class == null) {
705 object[] usage_attr = Type.GetCustomAttributes (TypeManager.attribute_usage_type, true);
706 ua = (AttributeUsageAttribute)usage_attr [0];
707 usage_attr_cache.Add (Type, ua);
711 Attribute a = attr_class.OptAttributes == null
713 : attr_class.OptAttributes.Search (TypeManager.attribute_usage_type);
716 ? DefaultUsageAttribute
717 : a.GetAttributeUsageAttribute ();
719 usage_attr_cache.Add (Type, ua);
723 AttributeUsageAttribute GetAttributeUsageAttribute ()
725 if (pos_values == null)
726 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
727 // But because a lot of attribute class code must be rewritten will be better to wait...
731 return DefaultUsageAttribute;
733 AttributeUsageAttribute usage_attribute = new AttributeUsageAttribute ((AttributeTargets)pos_values [0]);
735 object field = GetPropertyValue ("AllowMultiple");
737 usage_attribute.AllowMultiple = (bool)field;
739 field = GetPropertyValue ("Inherited");
741 usage_attribute.Inherited = (bool)field;
743 return usage_attribute;
747 /// Returns custom name of indexer
749 public string GetIndexerAttributeValue ()
751 if (pos_values == null)
752 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
753 // But because a lot of attribute class code must be rewritten will be better to wait...
759 return pos_values [0] as string;
763 /// Returns condition of ConditionalAttribute
765 public string GetConditionalAttributeValue ()
767 if (pos_values == null)
768 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
769 // But because a lot of attribute class code must be rewritten will be better to wait...
775 return (string)pos_values [0];
779 /// Creates the instance of ObsoleteAttribute from this attribute instance
781 public ObsoleteAttribute GetObsoleteAttribute ()
783 if (pos_values == null)
784 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
785 // But because a lot of attribute class code must be rewritten will be better to wait...
791 if (pos_values == null || pos_values.Length == 0)
792 return new ObsoleteAttribute ();
794 if (pos_values.Length == 1)
795 return new ObsoleteAttribute ((string)pos_values [0]);
797 return new ObsoleteAttribute ((string)pos_values [0], (bool)pos_values [1]);
801 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
802 /// before ApplyAttribute. We need to resolve the arguments.
803 /// This situation occurs when class deps is differs from Emit order.
805 public bool GetClsCompliantAttributeValue ()
807 if (pos_values == null)
808 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
809 // But because a lot of attribute class code must be rewritten will be better to wait...
815 return (bool)pos_values [0];
818 public Type GetCoClassAttributeValue ()
820 if (pos_values == null)
826 return (Type)pos_values [0];
829 public bool CheckTarget ()
831 string[] valid_targets = owner.ValidAttributeTargets;
832 if (ExplicitTarget == null || ExplicitTarget == valid_targets [0]) {
833 Target = owner.AttributeTargets;
837 // TODO: we can skip the first item
838 if (((IList) valid_targets).Contains (ExplicitTarget)) {
839 switch (ExplicitTarget) {
840 case "return": Target = AttributeTargets.ReturnValue; return true;
841 case "param": Target = AttributeTargets.Parameter; return true;
842 case "field": Target = AttributeTargets.Field; return true;
843 case "method": Target = AttributeTargets.Method; return true;
844 case "property": Target = AttributeTargets.Property; return true;
846 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget);
849 StringBuilder sb = new StringBuilder ();
850 foreach (string s in valid_targets) {
854 sb.Remove (sb.Length - 2, 2);
855 Report.Error (657, Location, "`{0}' is not a valid attribute location for this declaration. " +
856 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget, sb.ToString ());
861 /// Tests permitted SecurityAction for assembly or other types
863 public bool CheckSecurityActionValidity (bool for_assembly)
865 SecurityAction action = GetSecurityActionValue ();
867 if ((action == SecurityAction.RequestMinimum || action == SecurityAction.RequestOptional ||
868 action == SecurityAction.RequestRefuse) && for_assembly)
872 if (action < SecurityAction.Demand || action > SecurityAction.InheritanceDemand) {
873 Error_AttributeEmitError ("SecurityAction is out of range");
877 if ((action != SecurityAction.RequestMinimum && action != SecurityAction.RequestOptional &&
878 action != SecurityAction.RequestRefuse) && !for_assembly)
882 Error_AttributeEmitError (String.Concat ("SecurityAction `", action, "' is not valid for this declaration"));
886 System.Security.Permissions.SecurityAction GetSecurityActionValue ()
888 return (SecurityAction)pos_values [0];
892 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
894 /// <returns></returns>
895 public void ExtractSecurityPermissionSet (ListDictionary permissions)
897 Type orig_assembly_type = null;
899 if (TypeManager.LookupDeclSpace (Type) != null) {
900 if (!RootContext.StdLib) {
901 orig_assembly_type = Type.GetType (Type.FullName);
903 string orig_version_path = Environment.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
904 if (orig_version_path == null) {
905 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
909 if (orig_sec_assembly == null) {
910 string file = Path.Combine (orig_version_path, Driver.OutputFile);
911 orig_sec_assembly = Assembly.LoadFile (file);
914 orig_assembly_type = orig_sec_assembly.GetType (Type.FullName, true);
915 if (orig_assembly_type == null) {
916 Report.Warning (-112, 1, Location, "Self-referenced security attribute `{0}' " +
917 "was not found in previous version of assembly");
923 SecurityAttribute sa;
924 // For all non-selfreferencing security attributes we can avoid all hacks
925 if (orig_assembly_type == null) {
926 sa = (SecurityAttribute) Activator.CreateInstance (Type, pos_values);
928 if (prop_info_arr != null) {
929 for (int i = 0; i < prop_info_arr.Length; ++i) {
930 PropertyInfo pi = prop_info_arr [i];
931 pi.SetValue (sa, prop_values_arr [i], null);
935 // HACK: All security attributes have same ctor syntax
936 sa = (SecurityAttribute) Activator.CreateInstance (orig_assembly_type, new object[] { GetSecurityActionValue () } );
938 // All types are from newly created assembly but for invocation with old one we need to convert them
939 if (prop_info_arr != null) {
940 for (int i = 0; i < prop_info_arr.Length; ++i) {
941 PropertyInfo emited_pi = prop_info_arr [i];
942 PropertyInfo pi = orig_assembly_type.GetProperty (emited_pi.Name, emited_pi.PropertyType);
944 object old_instance = pi.PropertyType.IsEnum ?
945 System.Enum.ToObject (pi.PropertyType, prop_values_arr [i]) :
948 pi.SetValue (sa, old_instance, null);
954 perm = sa.CreatePermission ();
955 SecurityAction action = GetSecurityActionValue ();
957 // IS is correct because for corlib we are using an instance from old corlib
958 if (!(perm is System.Security.CodeAccessPermission)) {
960 case SecurityAction.Demand:
961 action = (SecurityAction)13;
963 case SecurityAction.LinkDemand:
964 action = (SecurityAction)14;
966 case SecurityAction.InheritanceDemand:
967 action = (SecurityAction)15;
972 PermissionSet ps = (PermissionSet)permissions [action];
974 if (sa is PermissionSetAttribute)
975 ps = new PermissionSet (sa.Unrestricted ? PermissionState.Unrestricted : PermissionState.None);
977 ps = new PermissionSet (PermissionState.None);
979 permissions.Add (action, ps);
980 } else if (!ps.IsUnrestricted () && (sa is PermissionSetAttribute) && sa.Unrestricted) {
981 ps = ps.Union (new PermissionSet (PermissionState.Unrestricted));
982 permissions [action] = ps;
984 ps.AddPermission (perm);
987 object GetValue (object value)
989 if (value is EnumConstant)
990 return ((EnumConstant) value).GetValue ();
995 public object GetPropertyValue (string name)
997 if (prop_info_arr == null)
1000 for (int i = 0; i < prop_info_arr.Length; ++i) {
1001 if (prop_info_arr [i].Name == name)
1002 return prop_values_arr [i];
1008 object GetFieldValue (string name)
1011 if (field_info_arr == null)
1014 foreach (FieldInfo fi in field_info_arr) {
1015 if (fi.Name == name)
1016 return GetValue (field_values_arr [i]);
1023 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1024 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1025 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1027 public UnmanagedMarshal GetMarshal (Attributable attr)
1029 UnmanagedType UnmanagedType;
1030 if (!RootContext.StdLib || pos_values [0].GetType () != typeof (UnmanagedType))
1031 UnmanagedType = (UnmanagedType) System.Enum.ToObject (typeof (UnmanagedType), pos_values [0]);
1033 UnmanagedType = (UnmanagedType) pos_values [0];
1035 object value = GetFieldValue ("SizeParamIndex");
1036 if (value != null && UnmanagedType != UnmanagedType.LPArray) {
1037 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1041 object o = GetFieldValue ("ArraySubType");
1042 UnmanagedType array_sub_type = o == null ? (UnmanagedType) 0x50 /* NATIVE_MAX */ : (UnmanagedType) o;
1044 switch (UnmanagedType) {
1045 case UnmanagedType.CustomMarshaler: {
1046 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
1047 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1048 if (define_custom == null) {
1049 Report.RuntimeMissingSupport (Location, "set marshal info");
1053 object [] args = new object [4];
1054 args [0] = GetFieldValue ("MarshalTypeRef");
1055 args [1] = GetFieldValue ("MarshalCookie");
1056 args [2] = GetFieldValue ("MarshalType");
1057 args [3] = Guid.Empty;
1058 return (UnmanagedMarshal) define_custom.Invoke (null, args);
1060 case UnmanagedType.LPArray: {
1061 object size_const = GetFieldValue ("SizeConst");
1062 object size_param_index = GetFieldValue ("SizeParamIndex");
1064 if ((size_const != null) || (size_param_index != null)) {
1065 MethodInfo define_array = typeof (UnmanagedMarshal).GetMethod ("DefineLPArrayInternal",
1066 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
1067 if (define_array == null) {
1068 Report.RuntimeMissingSupport (Location, "set marshal info");
1072 object [] args = new object [3];
1073 args [0] = array_sub_type;
1074 args [1] = size_const == null ? -1 : size_const;
1075 args [2] = size_param_index == null ? -1 : size_param_index;
1076 return (UnmanagedMarshal) define_array.Invoke (null, args);
1079 return UnmanagedMarshal.DefineLPArray (array_sub_type);
1081 case UnmanagedType.SafeArray:
1082 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
1084 case UnmanagedType.ByValArray:
1085 FieldMember fm = attr as FieldMember;
1087 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1090 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1092 case UnmanagedType.ByValTStr:
1093 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1096 return UnmanagedMarshal.DefineUnmanagedMarshal (UnmanagedType);
1100 public CharSet GetCharSetValue ()
1102 return (CharSet)System.Enum.Parse (typeof (CharSet), pos_values [0].ToString ());
1105 public MethodImplOptions GetMethodImplOptions ()
1107 if (pos_values [0].GetType () != typeof (MethodImplOptions))
1108 return (MethodImplOptions)System.Enum.ToObject (typeof (MethodImplOptions), pos_values [0]);
1109 return (MethodImplOptions)pos_values [0];
1112 public LayoutKind GetLayoutKindValue ()
1114 if (!RootContext.StdLib || pos_values [0].GetType () != typeof (LayoutKind))
1115 return (LayoutKind)System.Enum.ToObject (typeof (LayoutKind), pos_values [0]);
1117 return (LayoutKind)pos_values [0];
1120 public override bool Equals (object obj)
1122 Attribute a = obj as Attribute;
1126 return Type == a.Type && Target == a.Target;
1129 public override int GetHashCode ()
1131 return base.GetHashCode ();
1135 /// Emit attribute for Attributable symbol
1137 public void Emit (ListDictionary allEmitted)
1139 CustomAttributeBuilder cb = Resolve ();
1143 AttributeUsageAttribute usage_attr = GetAttributeUsage ();
1144 if ((usage_attr.ValidOn & Target) == 0) {
1145 Report.Error (592, Location, "The attribute `{0}' is not valid on this declaration type. " +
1146 "It is valid on `{1}' declarations only",
1147 GetSignatureForError (), GetValidTargets ());
1152 owner.ApplyAttributeBuilder (this, cb);
1154 catch (Exception e) {
1155 Error_AttributeEmitError (e.Message);
1159 if (!usage_attr.AllowMultiple && allEmitted != null) {
1160 if (allEmitted.Contains (this)) {
1161 ArrayList a = allEmitted [this] as ArrayList;
1163 a = new ArrayList (2);
1164 allEmitted [this] = a;
1168 allEmitted.Add (this, null);
1172 if (!RootContext.VerifyClsCompliance)
1175 // Here we are testing attribute arguments for array usage (error 3016)
1176 if (owner.IsClsComplianceRequired ()) {
1177 if (Arguments == null)
1180 ArrayList pos_args = (ArrayList) Arguments [0];
1181 if (pos_args != null) {
1182 foreach (Argument arg in pos_args) {
1183 // Type is undefined (was error 246)
1184 if (arg.Type == null)
1187 if (arg.Type.IsArray) {
1188 Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
1194 if (Arguments.Count < 2)
1197 ArrayList named_args = (ArrayList) Arguments [1];
1198 foreach (DictionaryEntry de in named_args) {
1199 Argument arg = (Argument) de.Value;
1201 // Type is undefined (was error 246)
1202 if (arg.Type == null)
1205 if (arg.Type.IsArray) {
1206 Report.Error (3016, Location, "Arrays as attribute arguments are not CLS-compliant");
1213 public MethodBuilder DefinePInvokeMethod (TypeBuilder builder, string name,
1214 MethodAttributes flags, Type ret_type, Type [] param_types)
1216 if (pos_values == null)
1217 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
1218 // But because a lot of attribute class code must be rewritten will be better to wait...
1224 string dll_name = (string)pos_values [0];
1227 CallingConvention cc = CallingConvention.Winapi;
1228 CharSet charset = CodeGen.Module.DefaultCharSet;
1229 bool preserve_sig = true;
1230 string entry_point = name;
1231 bool best_fit_mapping = false;
1232 bool throw_on_unmappable = false;
1233 bool exact_spelling = false;
1234 bool set_last_error = false;
1236 bool best_fit_mapping_set = false;
1237 bool throw_on_unmappable_set = false;
1238 bool exact_spelling_set = false;
1239 bool set_last_error_set = false;
1241 MethodInfo set_best_fit = null;
1242 MethodInfo set_throw_on = null;
1243 MethodInfo set_exact_spelling = null;
1244 MethodInfo set_set_last_error = null;
1246 if (field_info_arr != null) {
1248 for (int i = 0; i < field_info_arr.Length; i++) {
1249 switch (field_info_arr [i].Name) {
1250 case "BestFitMapping":
1251 best_fit_mapping = (bool) field_values_arr [i];
1252 best_fit_mapping_set = true;
1254 case "CallingConvention":
1255 cc = (CallingConvention) field_values_arr [i];
1258 charset = (CharSet) field_values_arr [i];
1261 entry_point = (string) field_values_arr [i];
1263 case "ExactSpelling":
1264 exact_spelling = (bool) field_values_arr [i];
1265 exact_spelling_set = true;
1268 preserve_sig = (bool) field_values_arr [i];
1270 case "SetLastError":
1271 set_last_error = (bool) field_values_arr [i];
1272 set_last_error_set = true;
1274 case "ThrowOnUnmappableChar":
1275 throw_on_unmappable = (bool) field_values_arr [i];
1276 throw_on_unmappable_set = true;
1279 throw new InternalErrorException (field_info_arr [i].ToString ());
1284 if (throw_on_unmappable_set || best_fit_mapping_set || exact_spelling_set || set_last_error_set) {
1285 set_best_fit = typeof (MethodBuilder).
1286 GetMethod ("set_BestFitMapping", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1287 set_throw_on = typeof (MethodBuilder).
1288 GetMethod ("set_ThrowOnUnmappableChar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1289 set_exact_spelling = typeof (MethodBuilder).
1290 GetMethod ("set_ExactSpelling", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1291 set_set_last_error = typeof (MethodBuilder).
1292 GetMethod ("set_SetLastError", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1294 if ((set_best_fit == null) || (set_throw_on == null) ||
1295 (set_exact_spelling == null) || (set_set_last_error == null)) {
1296 Report.Error (-1, Location,
1297 "The ThrowOnUnmappableChar, BestFitMapping, SetLastError, " +
1298 "and ExactSpelling attributes can only be emitted when running on the mono runtime.");
1304 MethodBuilder mb = builder.DefinePInvokeMethod (
1305 name, dll_name, entry_point, flags | MethodAttributes.HideBySig | MethodAttributes.PinvokeImpl,
1306 CallingConventions.Standard, ret_type, param_types, cc, charset);
1309 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
1311 if (throw_on_unmappable_set)
1312 set_throw_on.Invoke (mb, 0, null, new object [] { throw_on_unmappable }, null);
1313 if (best_fit_mapping_set)
1314 set_best_fit.Invoke (mb, 0, null, new object [] { best_fit_mapping }, null);
1315 if (exact_spelling_set)
1316 set_exact_spelling.Invoke (mb, 0, null, new object [] { exact_spelling }, null);
1317 if (set_last_error_set)
1318 set_set_last_error.Invoke (mb, 0, null, new object [] { set_last_error }, null);
1322 catch (ArgumentException e) {
1323 Error_AttributeEmitError (e.Message);
1328 private Expression GetValue ()
1330 if ((Arguments == null) || (Arguments.Count < 1))
1332 ArrayList al = (ArrayList) Arguments [0];
1333 if ((al == null) || (al.Count < 1))
1335 Argument arg = (Argument) al [0];
1336 if ((arg == null) || (arg.Expr == null))
1341 public string GetString ()
1343 Expression e = GetValue ();
1344 if (e is StringLiteral)
1345 return (e as StringLiteral).Value;
1349 public bool GetBoolean ()
1351 Expression e = GetValue ();
1352 if (e is BoolLiteral)
1353 return (e as BoolLiteral).Value;
1360 /// For global attributes (assembly, module) we need special handling.
1361 /// Attributes can be located in the several files
1363 public class GlobalAttribute : Attribute
1365 public readonly NamespaceEntry ns;
1367 public GlobalAttribute (NamespaceEntry ns, string target,
1368 Expression left_expr, string identifier, ArrayList args, Location loc, bool nameEscaped):
1369 base (target, left_expr, identifier, args, loc, nameEscaped)
1376 // RootContext.Tree.Types has a single NamespaceEntry which gets overwritten
1377 // each time a new file is parsed. However, we need to use the NamespaceEntry
1378 // in effect where the attribute was used. Since code elsewhere cannot assume
1379 // that the NamespaceEntry is right, just overwrite it.
1381 // Precondition: RootContext.Tree.Types == null
1383 if (RootContext.Tree.Types.NamespaceEntry != null)
1384 throw new InternalErrorException (Location + " non-null NamespaceEntry");
1386 RootContext.Tree.Types.NamespaceEntry = ns;
1391 RootContext.Tree.Types.NamespaceEntry = null;
1394 protected override FullNamedExpression ResolveAsTypeStep (Expression expr, IResolveContext ec, bool silent)
1398 return base.ResolveAsTypeStep (expr, ec, silent);
1406 protected override FullNamedExpression ResolveAsTypeTerminal (Expression expr, IResolveContext ec, bool silent)
1410 return base.ResolveAsTypeTerminal (expr, ec, silent);
1417 protected override ConstructorInfo ResolveArguments ()
1421 return base.ResolveArguments ();
1429 public class Attributes {
1430 public readonly ArrayList Attrs;
1432 public Attributes (Attribute a)
1434 Attrs = new ArrayList ();
1438 public Attributes (ArrayList attrs)
1443 public void AddAttributes (ArrayList attrs)
1445 Attrs.AddRange (attrs);
1448 public void AttachTo (Attributable attributable)
1450 foreach (Attribute a in Attrs)
1451 a.AttachTo (attributable);
1455 /// Checks whether attribute target is valid for the current element
1457 public bool CheckTargets ()
1459 foreach (Attribute a in Attrs) {
1460 if (!a.CheckTarget ())
1466 public Attribute Search (Type t)
1468 foreach (Attribute a in Attrs) {
1469 if (a.ResolveType () == t)
1476 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1478 public Attribute[] SearchMulti (Type t)
1480 ArrayList ar = null;
1482 foreach (Attribute a in Attrs) {
1483 if (a.ResolveType () == t) {
1485 ar = new ArrayList ();
1490 return ar == null ? null : ar.ToArray (typeof (Attribute)) as Attribute[];
1497 ListDictionary ld = Attrs.Count > 1 ? new ListDictionary () : null;
1499 foreach (Attribute a in Attrs)
1502 if (ld == null || ld.Count == 0)
1505 foreach (DictionaryEntry d in ld) {
1506 if (d.Value == null)
1509 foreach (Attribute collision in (ArrayList)d.Value)
1510 Report.SymbolRelatedToPreviousError (collision.Location, "");
1512 Attribute a = (Attribute)d.Key;
1513 Report.Error (579, a.Location, "The attribute `{0}' cannot be applied multiple times", a.GetSignatureForError ());
1517 public bool Contains (Type t)
1519 return Search (t) != null;
1524 /// Helper class for attribute verification routine.
1526 sealed class AttributeTester
1528 static PtrHashtable analyzed_types = new PtrHashtable ();
1529 static PtrHashtable analyzed_types_obsolete = new PtrHashtable ();
1530 static PtrHashtable analyzed_member_obsolete = new PtrHashtable ();
1531 static PtrHashtable analyzed_method_excluded = new PtrHashtable ();
1534 static PtrHashtable fixed_buffer_cache = new PtrHashtable ();
1537 static object TRUE = new object ();
1538 static object FALSE = new object ();
1540 private AttributeTester ()
1544 public enum Result {
1551 /// Returns true if parameters of two compared methods are CLS-Compliant.
1552 /// It tests differing only in ref or out, or in array rank.
1554 public static Result AreOverloadedMethodParamsClsCompliant (Type[] types_a, Type[] types_b)
1556 if (types_a == null || types_b == null)
1559 if (types_a.Length != types_b.Length)
1562 Result result = Result.Ok;
1563 for (int i = 0; i < types_b.Length; ++i) {
1564 Type aType = types_a [i];
1565 Type bType = types_b [i];
1567 if (aType.IsArray && bType.IsArray) {
1568 Type a_el_type = aType.GetElementType ();
1569 Type b_el_type = bType.GetElementType ();
1570 if (aType.GetArrayRank () != bType.GetArrayRank () && a_el_type == b_el_type) {
1571 result = Result.RefOutArrayError;
1575 if (a_el_type.IsArray || b_el_type.IsArray) {
1576 result = Result.ArrayArrayError;
1581 Type aBaseType = aType;
1582 bool is_either_ref_or_out = false;
1584 if (aType.IsByRef || aType.IsPointer) {
1585 aBaseType = aType.GetElementType ();
1586 is_either_ref_or_out = true;
1589 Type bBaseType = bType;
1590 if (bType.IsByRef || bType.IsPointer)
1592 bBaseType = bType.GetElementType ();
1593 is_either_ref_or_out = !is_either_ref_or_out;
1596 if (aBaseType != bBaseType)
1599 if (is_either_ref_or_out)
1600 result = Result.RefOutArrayError;
1606 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1608 public static bool IsClsCompliant (Type type)
1613 object type_compliance = analyzed_types[type];
1614 if (type_compliance != null)
1615 return type_compliance == TRUE;
1617 if (type.IsPointer) {
1618 analyzed_types.Add (type, null);
1623 if (type.IsArray || type.IsByRef) {
1624 result = IsClsCompliant (TypeManager.GetElementType (type));
1626 result = AnalyzeTypeCompliance (type);
1628 analyzed_types.Add (type, result ? TRUE : FALSE);
1633 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1635 public static IFixedBuffer GetFixedBuffer (FieldInfo fi)
1637 FieldBase fb = TypeManager.GetField (fi);
1639 return fb as IFixedBuffer;
1643 object o = fixed_buffer_cache [fi];
1645 if (System.Attribute.GetCustomAttribute (fi, TypeManager.fixed_buffer_attr_type) == null) {
1646 fixed_buffer_cache.Add (fi, FALSE);
1650 IFixedBuffer iff = new FixedFieldExternal (fi);
1651 fixed_buffer_cache.Add (fi, iff);
1658 return (IFixedBuffer)o;
1664 public static void VerifyModulesClsCompliance ()
1666 Module[] modules = RootNamespace.Global.Modules;
1667 if (modules == null)
1670 // The first module is generated assembly
1671 for (int i = 1; i < modules.Length; ++i) {
1672 Module module = modules [i];
1673 if (!IsClsCompliant (module)) {
1674 Report.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1675 "to match the assembly", module.Name);
1681 public static Type GetImportedIgnoreCaseClsType (string name)
1683 foreach (Assembly a in RootNamespace.Global.Assemblies) {
1684 Type t = a.GetType (name, false, true);
1688 if (IsClsCompliant (t))
1694 static bool IsClsCompliant (ICustomAttributeProvider attribute_provider)
1696 object[] CompliantAttribute = attribute_provider.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1697 if (CompliantAttribute.Length == 0)
1700 return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
1703 static bool AnalyzeTypeCompliance (Type type)
1705 DeclSpace ds = TypeManager.LookupDeclSpace (type);
1707 return ds.IsClsComplianceRequired ();
1710 object[] CompliantAttribute = type.GetCustomAttributes (TypeManager.cls_compliant_attribute_type, false);
1711 if (CompliantAttribute.Length == 0)
1712 return IsClsCompliant (type.Assembly);
1714 return ((CLSCompliantAttribute)CompliantAttribute[0]).IsCompliant;
1718 /// Returns instance of ObsoleteAttribute when type is obsolete
1720 public static ObsoleteAttribute GetObsoleteAttribute (Type type)
1722 object type_obsolete = analyzed_types_obsolete [type];
1723 if (type_obsolete == FALSE)
1726 if (type_obsolete != null)
1727 return (ObsoleteAttribute)type_obsolete;
1729 ObsoleteAttribute result = null;
1730 if (type.IsByRef || type.IsArray || type.IsPointer) {
1731 result = GetObsoleteAttribute (TypeManager.GetElementType (type));
1733 DeclSpace type_ds = TypeManager.LookupDeclSpace (type);
1735 // Type is external, we can get attribute directly
1736 if (type_ds == null) {
1737 object[] attribute = type.GetCustomAttributes (TypeManager.obsolete_attribute_type, false);
1738 if (attribute.Length == 1)
1739 result = (ObsoleteAttribute)attribute [0];
1741 // Is null during corlib bootstrap
1742 if (TypeManager.obsolete_attribute_type != null)
1743 result = type_ds.GetObsoleteAttribute ();
1747 // Cannot use .Add because of corlib bootstrap
1748 analyzed_types_obsolete [type] = result == null ? FALSE : result;
1753 /// Returns instance of ObsoleteAttribute when method is obsolete
1755 public static ObsoleteAttribute GetMethodObsoleteAttribute (MethodBase mb)
1757 IMethodData mc = TypeManager.GetMethod (mb);
1759 return mc.GetObsoleteAttribute ();
1761 // compiler generated methods are not registered by AddMethod
1762 if (mb.DeclaringType is TypeBuilder)
1765 if (mb.IsSpecialName) {
1766 PropertyInfo pi = PropertyExpr.AccessorTable [mb] as PropertyInfo;
1768 // FIXME: This is buggy as properties from this assembly are included as well
1770 //return GetMemberObsoleteAttribute (pi);
1774 return GetMemberObsoleteAttribute (mb);
1778 /// Returns instance of ObsoleteAttribute when member is obsolete
1780 public static ObsoleteAttribute GetMemberObsoleteAttribute (MemberInfo mi)
1782 object type_obsolete = analyzed_member_obsolete [mi];
1783 if (type_obsolete == FALSE)
1786 if (type_obsolete != null)
1787 return (ObsoleteAttribute)type_obsolete;
1789 ObsoleteAttribute oa = System.Attribute.GetCustomAttribute (mi, TypeManager.obsolete_attribute_type, false)
1790 as ObsoleteAttribute;
1791 analyzed_member_obsolete.Add (mi, oa == null ? FALSE : oa);
1796 /// Common method for Obsolete error/warning reporting.
1798 public static void Report_ObsoleteMessage (ObsoleteAttribute oa, string member, Location loc)
1801 Report.Error (619, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1805 if (oa.Message == null) {
1806 Report.Warning (612, 1, loc, "`{0}' is obsolete", member);
1809 Report.Warning (618, 2, loc, "`{0}' is obsolete: `{1}'", member, oa.Message);
1812 public static bool IsConditionalMethodExcluded (MethodBase mb)
1814 object excluded = analyzed_method_excluded [mb];
1815 if (excluded != null)
1816 return excluded == TRUE ? true : false;
1818 ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true)
1819 as ConditionalAttribute[];
1820 if (attrs.Length == 0) {
1821 analyzed_method_excluded.Add (mb, FALSE);
1825 foreach (ConditionalAttribute a in attrs) {
1826 if (RootContext.AllDefines.Contains (a.ConditionString)) {
1827 analyzed_method_excluded.Add (mb, FALSE);
1831 analyzed_method_excluded.Add (mb, TRUE);
1836 /// Analyzes class whether it has attribute which has ConditionalAttribute
1837 /// and its condition is not defined.
1839 public static bool IsAttributeExcluded (Type type)
1844 Class class_decl = TypeManager.LookupDeclSpace (type) as Class;
1846 // TODO: add caching
1847 // TODO: merge all Type bases attribute caching to one cache to save memory
1848 if (class_decl == null) {
1849 object[] attributes = type.GetCustomAttributes (TypeManager.conditional_attribute_type, false);
1850 foreach (ConditionalAttribute ca in attributes) {
1851 if (RootContext.AllDefines.Contains (ca.ConditionString))
1854 return attributes.Length > 0;
1857 return class_decl.IsExcluded ();
1860 public static Type GetCoClassAttribute (Type type)
1862 TypeContainer tc = TypeManager.LookupInterface (type);
1864 object[] o = type.GetCustomAttributes (TypeManager.coclass_attr_type, false);
1867 return ((System.Runtime.InteropServices.CoClassAttribute)o[0]).CoClass;
1870 if (tc.OptAttributes == null)
1873 Attribute a = tc.OptAttributes.Search (TypeManager.coclass_attr_type);
1877 return a.GetCoClassAttributeValue ();