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 protected Attributes attributes
;
37 public Attributable (Attributes attrs
)
40 OptAttributes
= attrs
;
43 public Attributes OptAttributes
51 if (attributes
!= null) {
52 attributes
.AttachTo (this);
58 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
60 public abstract void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
);
63 /// Returns one AttributeTarget for this element.
65 public abstract AttributeTargets AttributeTargets { get; }
67 public abstract IResolveContext ResolveContext { get; }
69 public abstract bool IsClsComplianceRequired ();
72 /// Gets list of valid attribute targets for explicit target declaration.
73 /// The first array item is default target. Don't break this rule.
75 public abstract string[] ValidAttributeTargets { get; }
78 public class Attribute
{
79 public readonly string ExplicitTarget
;
80 public AttributeTargets Target
;
82 // TODO: remove this member
83 public readonly string Name
;
84 public readonly Expression LeftExpr
;
85 public readonly string Identifier
;
87 readonly ArrayList PosArguments
;
88 ArrayList NamedArguments
;
90 public readonly Location Location
;
95 readonly bool nameEscaped
;
97 // It can contain more onwers when the attribute is applied to multiple fiels.
98 Attributable
[] owners
;
100 static readonly AttributeUsageAttribute DefaultUsageAttribute
= new AttributeUsageAttribute (AttributeTargets
.All
);
101 static Assembly orig_sec_assembly
;
102 public static readonly object[] EmptyObject
= new object [0];
104 // non-null if named args present after Resolve () is called
105 PropertyInfo
[] prop_info_arr
;
106 FieldInfo
[] field_info_arr
;
107 object [] field_values_arr
;
108 object [] prop_values_arr
;
109 object [] pos_values
;
111 static PtrHashtable usage_attr_cache
;
112 // Cache for parameter-less attributes
113 static PtrHashtable att_cache
;
115 public Attribute (string target
, Expression left_expr
, string identifier
, object[] args
, Location loc
, bool nameEscaped
)
117 LeftExpr
= left_expr
;
118 Identifier
= identifier
;
119 Name
= LeftExpr
== null ? identifier
: LeftExpr
+ "." + identifier
;
121 PosArguments
= (ArrayList
)args
[0];
122 NamedArguments
= (ArrayList
)args
[1];
125 ExplicitTarget
= target
;
126 this.nameEscaped
= nameEscaped
;
134 public static void Reset ()
136 usage_attr_cache
= new PtrHashtable ();
137 att_cache
= new PtrHashtable ();
140 public void AttachTo (Attributable owner
)
142 if (this.owners
== null) {
143 this.owners
= new Attributable
[1] { owner }
;
147 // When the same attribute is attached to multiple fiels
148 // we use this extra_owners as a list of owners. The attribute
149 // then can be removed because will be emitted when first owner
151 Attributable
[] new_array
= new Attributable
[this.owners
.Length
+ 1];
152 owners
.CopyTo (new_array
, 0);
153 new_array
[owners
.Length
] = owner
;
154 this.owners
= new_array
;
155 owner
.OptAttributes
= null;
158 void Error_InvalidNamedArgument (string name
)
160 Report
.Error (617, Location
, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
161 "must be fields which are not readonly, static, const or read-write properties which are " +
162 "public and not static",
166 void Error_InvalidNamedAgrumentType (string name
)
168 Report
.Error (655, Location
, "`{0}' is not a valid named attribute argument because it is not a valid " +
169 "attribute parameter type", name
);
172 public static void Error_AttributeArgumentNotValid (Location loc
)
174 Report
.Error (182, loc
,
175 "An attribute argument must be a constant expression, typeof " +
176 "expression or array creation expression");
179 static void Error_TypeParameterInAttribute (Location loc
)
182 -202, loc
, "Can not use a type parameter in an attribute");
185 public void Error_MissingGuidAttribute ()
187 Report
.Error (596, Location
, "The Guid attribute must be specified with the ComImport attribute");
190 public void Error_MisusedExtensionAttribute ()
192 Report
.Error (1112, Location
, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
196 /// This is rather hack. We report many emit attribute error with same error to be compatible with
197 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
199 public void Error_AttributeEmitError (string inner
)
201 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
202 TypeManager
.CSharpName (Type
), inner
);
205 public void Error_InvalidSecurityParent ()
207 Error_AttributeEmitError ("it is attached to invalid parent");
216 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
218 return expr
.ResolveAsTypeTerminal (ec
, silent
);
221 Type
ResolvePossibleAttributeType (string name
, bool silent
, ref bool is_attr
)
223 IResolveContext rc
= Owner
.ResolveContext
;
226 if (LeftExpr
== null) {
227 te
= ResolveAsTypeTerminal (new SimpleName (name
, Location
), rc
, silent
);
229 te
= ResolveAsTypeTerminal (new MemberAccess (LeftExpr
, name
), rc
, silent
);
236 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
238 } else if (!silent
) {
239 Report
.SymbolRelatedToPreviousError (t
);
240 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
246 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
248 void ResolveAttributeType ()
250 bool t1_is_attr
= false;
251 Type t1
= ResolvePossibleAttributeType (Identifier
, true, ref t1_is_attr
);
253 bool t2_is_attr
= false;
254 Type t2
= nameEscaped
? null :
255 ResolvePossibleAttributeType (Identifier
+ "Attribute", true, ref t2_is_attr
);
257 if (t1_is_attr
&& t2_is_attr
) {
258 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " +
259 "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
260 resolve_error
= true;
274 if (t1
== null && t2
== null)
275 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
277 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
279 ResolvePossibleAttributeType (Identifier
+ "Attribute", false, ref t2_is_attr
);
281 resolve_error
= true;
284 public virtual Type
ResolveType ()
286 if (Type
== null && !resolve_error
)
287 ResolveAttributeType ();
291 public string GetSignatureForError ()
294 return TypeManager
.CSharpName (Type
);
296 return LeftExpr
== null ? Identifier
: LeftExpr
.GetSignatureForError () + "." + Identifier
;
299 bool IsValidArgumentType (Type t
)
302 t
= t
.GetElementType ();
304 return TypeManager
.IsPrimitiveType (t
) ||
305 TypeManager
.IsEnumType (t
) ||
306 t
== TypeManager
.string_type
||
307 t
== TypeManager
.object_type
||
308 t
== TypeManager
.type_type
;
311 [Conditional ("GMCS_SOURCE")]
312 void ApplyModuleCharSet ()
314 if (Type
!= TypeManager
.dllimport_type
)
317 if (!CodeGen
.Module
.HasDefaultCharSet
)
320 const string CharSetEnumMember
= "CharSet";
321 if (NamedArguments
== null) {
322 NamedArguments
= new ArrayList (1);
324 foreach (DictionaryEntry de
in NamedArguments
) {
325 if ((string)de
.Key
== CharSetEnumMember
)
330 NamedArguments
.Add (new DictionaryEntry (CharSetEnumMember
,
331 new Argument (Constant
.CreateConstant (typeof (CharSet
), CodeGen
.Module
.DefaultCharSet
, Location
))));
334 public CustomAttributeBuilder
Resolve ()
339 resolve_error
= true;
342 ResolveAttributeType ();
347 if (Type
.IsAbstract
) {
348 Report
.Error (653, Location
, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
352 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (Type
);
353 if (obsolete_attr
!= null) {
354 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, TypeManager
.CSharpName (Type
), Location
);
357 if (PosArguments
== null && NamedArguments
== null) {
358 object o
= att_cache
[Type
];
360 resolve_error
= false;
361 return (CustomAttributeBuilder
)o
;
365 Attributable owner
= Owner
;
366 EmitContext ec
= new EmitContext (owner
.ResolveContext
, owner
.ResolveContext
.DeclContainer
, owner
.ResolveContext
.DeclContainer
,
367 Location
, null, null, owner
.ResolveContext
.DeclContainer
.ModFlags
, false);
368 ec
.IsAnonymousMethodAllowed
= false;
370 ConstructorInfo ctor
= ResolveConstructor (ec
);
372 if (Type
is TypeBuilder
&&
373 TypeManager
.LookupDeclSpace (Type
).MemberCache
== null)
374 // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error.
375 // It'll be resolved again when the attached-to entity is emitted.
376 resolve_error
= false;
380 ApplyModuleCharSet ();
382 CustomAttributeBuilder cb
;
384 if (NamedArguments
== null) {
385 cb
= new CustomAttributeBuilder (ctor
, pos_values
);
387 if (pos_values
.Length
== 0)
388 att_cache
.Add (Type
, cb
);
390 resolve_error
= false;
394 if (!ResolveNamedArguments (ec
)) {
398 cb
= new CustomAttributeBuilder (ctor
, pos_values
,
399 prop_info_arr
, prop_values_arr
,
400 field_info_arr
, field_values_arr
);
402 resolve_error
= false;
406 Error_AttributeArgumentNotValid (Location
);
411 protected virtual ConstructorInfo
ResolveConstructor (EmitContext ec
)
413 if (PosArguments
!= null) {
414 for (int i
= 0; i
< PosArguments
.Count
; i
++) {
415 Argument a
= (Argument
) PosArguments
[i
];
417 if (!a
.Resolve (ec
, Location
))
422 Expression mg
= Expression
.MemberLookup (ec
.ContainerType
,
423 Type
, ".ctor", MemberTypes
.Constructor
,
424 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
430 MethodBase constructor
= ((MethodGroupExpr
)mg
).OverloadResolve (
431 ec
, PosArguments
, false, Location
);
433 if (constructor
== null)
436 ObsoleteAttribute oa
= AttributeTester
.GetMethodObsoleteAttribute (constructor
);
437 if (oa
!= null && !Owner
.ResolveContext
.IsInObsoleteScope
) {
438 AttributeTester
.Report_ObsoleteMessage (oa
, mg
.GetSignatureForError (), mg
.Location
);
441 if (PosArguments
== null) {
442 pos_values
= EmptyObject
;
443 return (ConstructorInfo
)constructor
;
446 ParameterData pd
= TypeManager
.GetParameterData (constructor
);
448 int pos_arg_count
= PosArguments
.Count
;
449 int last_real_param
= pd
.Count
;
451 pos_values
= new object [pos_arg_count
];
454 // When the params is not filled we need to put one
455 if (last_real_param
> pos_arg_count
) {
456 object [] new_pos_values
= new object [pos_arg_count
+ 1];
457 pos_values
.CopyTo (new_pos_values
, 0);
458 new_pos_values
[pos_arg_count
] = new object [] {} ;
459 pos_values
= new_pos_values
;
464 for (int j
= 0; j
< pos_arg_count
; ++j
) {
465 Argument a
= (Argument
) PosArguments
[j
];
467 if (!a
.Expr
.GetAttributableValue (a
.Type
, out pos_values
[j
]))
470 if (j
< last_real_param
)
473 if (j
== last_real_param
) {
474 object [] array
= new object [pos_arg_count
- last_real_param
];
475 array
[0] = pos_values
[j
];
476 pos_values
[j
] = array
;
480 object [] params_array
= (object []) pos_values
[last_real_param
];
481 params_array
[j
- last_real_param
] = pos_values
[j
];
484 // Adjust the size of the pos_values if it had params
485 if (last_real_param
!= pos_arg_count
) {
486 object [] new_pos_values
= new object [last_real_param
+ 1];
487 Array
.Copy (pos_values
, new_pos_values
, last_real_param
+ 1);
488 pos_values
= new_pos_values
;
491 // Here we do the checks which should be done by corlib or by runtime.
492 // However Zoltan doesn't like it and every Mono compiler has to do it again.
494 if (Type
== TypeManager
.guid_attr_type
) {
496 new Guid ((string)pos_values
[0]);
498 catch (Exception e
) {
499 Error_AttributeEmitError (e
.Message
);
504 if (Type
== TypeManager
.attribute_usage_type
&& (int)pos_values
[0] == 0) {
505 Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
509 if (Type
== TypeManager
.indexer_name_type
|| Type
== TypeManager
.conditional_attribute_type
) {
510 if (!Tokenizer
.IsValidIdentifier ((string)pos_values
[0])) {
511 Report
.Error (633, ((Argument
)PosArguments
[0]).Expr
.Location
,
512 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
517 if (Type
== TypeManager
.methodimpl_attr_type
&& pos_values
.Length
== 1 &&
518 pd
.ParameterType (0) == TypeManager
.short_type
&&
519 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
520 Error_AttributeEmitError ("Incorrect argument value.");
524 return (ConstructorInfo
)constructor
;
527 protected virtual bool ResolveNamedArguments (EmitContext ec
)
529 int named_arg_count
= NamedArguments
.Count
;
531 ArrayList field_infos
= new ArrayList (named_arg_count
);
532 ArrayList prop_infos
= new ArrayList (named_arg_count
);
533 ArrayList field_values
= new ArrayList (named_arg_count
);
534 ArrayList prop_values
= new ArrayList (named_arg_count
);
536 ArrayList seen_names
= new ArrayList(named_arg_count
);
538 foreach (DictionaryEntry de
in NamedArguments
) {
539 string member_name
= (string) de
.Key
;
541 if (seen_names
.Contains(member_name
)) {
542 Report
.Error(643, Location
, "'" + member_name
+ "' duplicate named attribute argument");
545 seen_names
.Add(member_name
);
547 Argument a
= (Argument
) de
.Value
;
548 if (!a
.Resolve (ec
, Location
))
551 Expression member
= Expression
.MemberLookup (
552 ec
.ContainerType
, Type
, member_name
,
553 MemberTypes
.Field
| MemberTypes
.Property
,
554 BindingFlags
.Public
| BindingFlags
.Instance
,
557 if (member
== null) {
558 member
= Expression
.MemberLookup (ec
.ContainerType
, Type
, member_name
,
559 MemberTypes
.Field
| MemberTypes
.Property
, BindingFlags
.NonPublic
| BindingFlags
.Instance
,
562 if (member
!= null) {
563 Report
.SymbolRelatedToPreviousError (member
.Type
);
564 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError ());
570 Expression
.Error_TypeDoesNotContainDefinition (Location
, Type
, member_name
);
574 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
575 Error_InvalidNamedArgument (member_name
);
579 if (a
.Expr
is TypeParameterExpr
){
580 Error_TypeParameterInAttribute (Location
);
584 ObsoleteAttribute obsolete_attr
;
586 if (member
is PropertyExpr
) {
587 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
589 if (!pi
.CanWrite
|| !pi
.CanRead
) {
590 Report
.SymbolRelatedToPreviousError (pi
);
591 Error_InvalidNamedArgument (member_name
);
595 if (!IsValidArgumentType (pi
.PropertyType
)) {
596 Report
.SymbolRelatedToPreviousError (pi
);
597 Error_InvalidNamedAgrumentType (member_name
);
602 if (!a
.Expr
.GetAttributableValue (pi
.PropertyType
, out value))
605 PropertyBase pb
= TypeManager
.GetProperty (pi
);
607 obsolete_attr
= pb
.GetObsoleteAttribute ();
609 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
611 prop_values
.Add (value);
615 FieldInfo fi
= ((FieldExpr
) member
).FieldInfo
;
618 Error_InvalidNamedArgument (member_name
);
622 if (!IsValidArgumentType (fi
.FieldType
)) {
623 Report
.SymbolRelatedToPreviousError (fi
);
624 Error_InvalidNamedAgrumentType (member_name
);
629 if (!a
.Expr
.GetAttributableValue (fi
.FieldType
, out value))
632 FieldBase fb
= TypeManager
.GetField (fi
);
634 obsolete_attr
= fb
.GetObsoleteAttribute ();
636 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
638 field_values
.Add (value);
639 field_infos
.Add (fi
);
642 if (obsolete_attr
!= null && !Owner
.ResolveContext
.IsInObsoleteScope
)
643 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
);
646 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
647 field_info_arr
= new FieldInfo
[field_infos
.Count
];
648 field_values_arr
= new object [field_values
.Count
];
649 prop_values_arr
= new object [prop_values
.Count
];
651 field_infos
.CopyTo (field_info_arr
, 0);
652 field_values
.CopyTo (field_values_arr
, 0);
654 prop_values
.CopyTo (prop_values_arr
, 0);
655 prop_infos
.CopyTo (prop_info_arr
, 0);
661 /// Get a string containing a list of valid targets for the attribute 'attr'
663 public string GetValidTargets ()
665 StringBuilder sb
= new StringBuilder ();
666 AttributeTargets targets
= GetAttributeUsage ().ValidOn
;
668 if ((targets
& AttributeTargets
.Assembly
) != 0)
669 sb
.Append ("assembly, ");
671 if ((targets
& AttributeTargets
.Module
) != 0)
672 sb
.Append ("module, ");
674 if ((targets
& AttributeTargets
.Class
) != 0)
675 sb
.Append ("class, ");
677 if ((targets
& AttributeTargets
.Struct
) != 0)
678 sb
.Append ("struct, ");
680 if ((targets
& AttributeTargets
.Enum
) != 0)
681 sb
.Append ("enum, ");
683 if ((targets
& AttributeTargets
.Constructor
) != 0)
684 sb
.Append ("constructor, ");
686 if ((targets
& AttributeTargets
.Method
) != 0)
687 sb
.Append ("method, ");
689 if ((targets
& AttributeTargets
.Property
) != 0)
690 sb
.Append ("property, indexer, ");
692 if ((targets
& AttributeTargets
.Field
) != 0)
693 sb
.Append ("field, ");
695 if ((targets
& AttributeTargets
.Event
) != 0)
696 sb
.Append ("event, ");
698 if ((targets
& AttributeTargets
.Interface
) != 0)
699 sb
.Append ("interface, ");
701 if ((targets
& AttributeTargets
.Parameter
) != 0)
702 sb
.Append ("parameter, ");
704 if ((targets
& AttributeTargets
.Delegate
) != 0)
705 sb
.Append ("delegate, ");
707 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
708 sb
.Append ("return, ");
711 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
712 sb
.Append ("type parameter, ");
714 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
718 /// Returns AttributeUsage attribute for this type
720 AttributeUsageAttribute
GetAttributeUsage ()
722 AttributeUsageAttribute ua
= usage_attr_cache
[Type
] as AttributeUsageAttribute
;
726 Class attr_class
= TypeManager
.LookupClass (Type
);
728 if (attr_class
== null) {
729 object[] usage_attr
= Type
.GetCustomAttributes (TypeManager
.attribute_usage_type
, true);
730 ua
= (AttributeUsageAttribute
)usage_attr
[0];
731 usage_attr_cache
.Add (Type
, ua
);
735 Attribute a
= attr_class
.OptAttributes
== null
737 : attr_class
.OptAttributes
.Search (TypeManager
.attribute_usage_type
);
740 ? DefaultUsageAttribute
741 : a
.GetAttributeUsageAttribute ();
743 usage_attr_cache
.Add (Type
, ua
);
747 AttributeUsageAttribute
GetAttributeUsageAttribute ()
749 if (pos_values
== null)
750 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
751 // But because a lot of attribute class code must be rewritten will be better to wait...
755 return DefaultUsageAttribute
;
757 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
759 object field
= GetPropertyValue ("AllowMultiple");
761 usage_attribute
.AllowMultiple
= (bool)field
;
763 field
= GetPropertyValue ("Inherited");
765 usage_attribute
.Inherited
= (bool)field
;
767 return usage_attribute
;
771 /// Returns custom name of indexer
773 public string GetIndexerAttributeValue ()
775 if (pos_values
== null)
776 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
777 // But because a lot of attribute class code must be rewritten will be better to wait...
783 return pos_values
[0] as string;
787 /// Returns condition of ConditionalAttribute
789 public string GetConditionalAttributeValue ()
791 if (pos_values
== null)
792 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
793 // But because a lot of attribute class code must be rewritten will be better to wait...
799 return (string)pos_values
[0];
803 /// Creates the instance of ObsoleteAttribute from this attribute instance
805 public ObsoleteAttribute
GetObsoleteAttribute ()
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 if (pos_values
== null || pos_values
.Length
== 0)
816 return new ObsoleteAttribute ();
818 if (pos_values
.Length
== 1)
819 return new ObsoleteAttribute ((string)pos_values
[0]);
821 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
825 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
826 /// before ApplyAttribute. We need to resolve the arguments.
827 /// This situation occurs when class deps is differs from Emit order.
829 public bool GetClsCompliantAttributeValue ()
831 if (pos_values
== null)
832 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
833 // But because a lot of attribute class code must be rewritten will be better to wait...
839 return (bool)pos_values
[0];
842 public Type
GetCoClassAttributeValue ()
844 if (pos_values
== null)
850 return (Type
)pos_values
[0];
853 public bool CheckTarget ()
855 string[] valid_targets
= Owner
.ValidAttributeTargets
;
856 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
857 Target
= Owner
.AttributeTargets
;
861 // TODO: we can skip the first item
862 if (((IList
) valid_targets
).Contains (ExplicitTarget
)) {
863 switch (ExplicitTarget
) {
864 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
865 case "param": Target
= AttributeTargets
.Parameter
; return true;
866 case "field": Target
= AttributeTargets
.Field
; return true;
867 case "method": Target
= AttributeTargets
.Method
; return true;
868 case "property": Target
= AttributeTargets
.Property
; return true;
870 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
873 StringBuilder sb
= new StringBuilder ();
874 foreach (string s
in valid_targets
) {
878 sb
.Remove (sb
.Length
- 2, 2);
879 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
880 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
885 /// Tests permitted SecurityAction for assembly or other types
887 public bool CheckSecurityActionValidity (bool for_assembly
)
889 SecurityAction action
= GetSecurityActionValue ();
892 case SecurityAction
.Demand
:
893 case SecurityAction
.Assert
:
894 case SecurityAction
.Deny
:
895 case SecurityAction
.PermitOnly
:
896 case SecurityAction
.LinkDemand
:
897 case SecurityAction
.InheritanceDemand
:
902 case SecurityAction
.RequestMinimum
:
903 case SecurityAction
.RequestOptional
:
904 case SecurityAction
.RequestRefuse
:
910 Error_AttributeEmitError ("SecurityAction is out of range");
914 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
918 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
920 return (SecurityAction
)pos_values
[0];
924 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
926 /// <returns></returns>
927 public void ExtractSecurityPermissionSet (ListDictionary permissions
)
929 Type orig_assembly_type
= null;
931 if (TypeManager
.LookupDeclSpace (Type
) != null) {
932 if (!RootContext
.StdLib
) {
933 orig_assembly_type
= Type
.GetType (Type
.FullName
);
935 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
936 if (orig_version_path
== null) {
937 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
941 if (orig_sec_assembly
== null) {
942 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
943 orig_sec_assembly
= Assembly
.LoadFile (file
);
946 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
947 if (orig_assembly_type
== null) {
948 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
949 "was not found in previous version of assembly");
955 SecurityAttribute sa
;
956 // For all non-selfreferencing security attributes we can avoid all hacks
957 if (orig_assembly_type
== null) {
958 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
960 if (prop_info_arr
!= null) {
961 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
962 PropertyInfo pi
= prop_info_arr
[i
];
963 pi
.SetValue (sa
, prop_values_arr
[i
], null);
967 // HACK: All security attributes have same ctor syntax
968 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
970 // All types are from newly created assembly but for invocation with old one we need to convert them
971 if (prop_info_arr
!= null) {
972 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
973 PropertyInfo emited_pi
= prop_info_arr
[i
];
974 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
, emited_pi
.PropertyType
);
976 object old_instance
= pi
.PropertyType
.IsEnum
?
977 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
980 pi
.SetValue (sa
, old_instance
, null);
986 perm
= sa
.CreatePermission ();
987 SecurityAction action
= GetSecurityActionValue ();
989 // IS is correct because for corlib we are using an instance from old corlib
990 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
992 case SecurityAction
.Demand
:
993 action
= (SecurityAction
)13;
995 case SecurityAction
.LinkDemand
:
996 action
= (SecurityAction
)14;
998 case SecurityAction
.InheritanceDemand
:
999 action
= (SecurityAction
)15;
1004 PermissionSet ps
= (PermissionSet
)permissions
[action
];
1006 if (sa
is PermissionSetAttribute
)
1007 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
1009 ps
= new PermissionSet (PermissionState
.None
);
1011 permissions
.Add (action
, ps
);
1012 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
1013 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
1014 permissions
[action
] = ps
;
1016 ps
.AddPermission (perm
);
1019 static object GetValue (object value)
1021 if (value is EnumConstant
)
1022 return ((EnumConstant
) value).GetValue ();
1027 public object GetPropertyValue (string name
)
1029 if (prop_info_arr
== null)
1032 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1033 if (prop_info_arr
[i
].Name
== name
)
1034 return prop_values_arr
[i
];
1040 object GetFieldValue (string name
)
1043 if (field_info_arr
== null)
1046 foreach (FieldInfo fi
in field_info_arr
) {
1047 if (fi
.Name
== name
)
1048 return GetValue (field_values_arr
[i
]);
1055 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1056 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1057 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1059 public UnmanagedMarshal
GetMarshal (Attributable attr
)
1061 UnmanagedType UnmanagedType
;
1062 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (UnmanagedType
))
1063 UnmanagedType
= (UnmanagedType
) System
.Enum
.ToObject (typeof (UnmanagedType
), pos_values
[0]);
1065 UnmanagedType
= (UnmanagedType
) pos_values
[0];
1067 object value = GetFieldValue ("SizeParamIndex");
1068 if (value != null && UnmanagedType
!= UnmanagedType
.LPArray
) {
1069 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1073 object o
= GetFieldValue ("ArraySubType");
1074 UnmanagedType array_sub_type
= o
== null ? (UnmanagedType
) 0x50 /* NATIVE_MAX */ : (UnmanagedType
) o
;
1076 switch (UnmanagedType
) {
1077 case UnmanagedType
.CustomMarshaler
: {
1078 MethodInfo define_custom
= typeof (UnmanagedMarshal
).GetMethod ("DefineCustom",
1079 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1080 if (define_custom
== null) {
1081 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1085 object [] args
= new object [4];
1086 args
[0] = GetFieldValue ("MarshalTypeRef");
1087 args
[1] = GetFieldValue ("MarshalCookie");
1088 args
[2] = GetFieldValue ("MarshalType");
1089 args
[3] = Guid
.Empty
;
1090 return (UnmanagedMarshal
) define_custom
.Invoke (null, args
);
1092 case UnmanagedType
.LPArray
: {
1093 object size_const
= GetFieldValue ("SizeConst");
1094 object size_param_index
= GetFieldValue ("SizeParamIndex");
1096 if ((size_const
!= null) || (size_param_index
!= null)) {
1097 MethodInfo define_array
= typeof (UnmanagedMarshal
).GetMethod ("DefineLPArrayInternal",
1098 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1099 if (define_array
== null) {
1100 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1104 object [] args
= new object [3];
1105 args
[0] = array_sub_type
;
1106 args
[1] = size_const
== null ? -1 : size_const
;
1107 args
[2] = size_param_index
== null ? -1 : size_param_index
;
1108 return (UnmanagedMarshal
) define_array
.Invoke (null, args
);
1111 return UnmanagedMarshal
.DefineLPArray (array_sub_type
);
1113 case UnmanagedType
.SafeArray
:
1114 return UnmanagedMarshal
.DefineSafeArray (array_sub_type
);
1116 case UnmanagedType
.ByValArray
:
1117 FieldBase fm
= attr
as FieldBase
;
1119 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1122 return UnmanagedMarshal
.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1124 case UnmanagedType
.ByValTStr
:
1125 return UnmanagedMarshal
.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1128 return UnmanagedMarshal
.DefineUnmanagedMarshal (UnmanagedType
);
1132 public CharSet
GetCharSetValue ()
1134 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1137 public bool IsInternalMethodImplAttribute
{
1139 if (Type
!= TypeManager
.methodimpl_attr_type
)
1142 MethodImplOptions options
;
1143 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1144 options
= (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1146 options
= (MethodImplOptions
)pos_values
[0];
1148 return (options
& MethodImplOptions
.InternalCall
) != 0;
1152 public LayoutKind
GetLayoutKindValue ()
1154 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1155 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1157 return (LayoutKind
)pos_values
[0];
1160 public object GetParameterDefaultValue ()
1162 return pos_values
[0];
1165 public override bool Equals (object obj
)
1167 Attribute a
= obj
as Attribute
;
1171 return Type
== a
.Type
&& Target
== a
.Target
;
1174 public override int GetHashCode ()
1176 return base.GetHashCode ();
1180 /// Emit attribute for Attributable symbol
1182 public void Emit (ListDictionary allEmitted
)
1184 CustomAttributeBuilder cb
= Resolve ();
1188 AttributeUsageAttribute usage_attr
= GetAttributeUsage ();
1189 if ((usage_attr
.ValidOn
& Target
) == 0) {
1190 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1191 "It is valid on `{1}' declarations only",
1192 GetSignatureForError (), GetValidTargets ());
1197 foreach (Attributable owner
in owners
)
1198 owner
.ApplyAttributeBuilder (this, cb
);
1200 catch (Exception e
) {
1201 Error_AttributeEmitError (e
.Message
);
1205 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1206 if (allEmitted
.Contains (this)) {
1207 ArrayList a
= allEmitted
[this] as ArrayList
;
1209 a
= new ArrayList (2);
1210 allEmitted
[this] = a
;
1214 allEmitted
.Add (this, null);
1218 if (!RootContext
.VerifyClsCompliance
)
1221 // Here we are testing attribute arguments for array usage (error 3016)
1222 if (Owner
.IsClsComplianceRequired ()) {
1223 if (PosArguments
!= null) {
1224 foreach (Argument arg
in PosArguments
) {
1225 // Type is undefined (was error 246)
1226 if (arg
.Type
== null)
1229 if (arg
.Type
.IsArray
) {
1230 Report
.Error (3016, Location
, "Arrays as attribute arguments are not CLS-compliant");
1236 if (NamedArguments
== null)
1239 foreach (DictionaryEntry de
in NamedArguments
) {
1240 Argument arg
= (Argument
) de
.Value
;
1242 // Type is undefined (was error 246)
1243 if (arg
.Type
== null)
1246 if (arg
.Type
.IsArray
) {
1247 Report
.Error (3016, Location
, "Arrays as attribute arguments are not CLS-compliant");
1254 private Expression
GetValue ()
1256 if (PosArguments
== null || PosArguments
.Count
< 1)
1259 return ((Argument
) PosArguments
[0]).Expr
;
1262 public string GetString ()
1264 Expression e
= GetValue ();
1265 if (e
is StringLiteral
)
1266 return (e
as StringLiteral
).Value
;
1270 public bool GetBoolean ()
1272 Expression e
= GetValue ();
1273 if (e
is BoolLiteral
)
1274 return (e
as BoolLiteral
).Value
;
1278 public Type
GetArgumentType ()
1280 TypeOf e
= GetValue () as TypeOf
;
1283 return e
.TypeArgument
;
1289 /// For global attributes (assembly, module) we need special handling.
1290 /// Attributes can be located in the several files
1292 public class GlobalAttribute
: Attribute
1294 public readonly NamespaceEntry ns
;
1296 public GlobalAttribute (NamespaceEntry ns
, string target
,
1297 Expression left_expr
, string identifier
, object[] args
, Location loc
, bool nameEscaped
):
1298 base (target
, left_expr
, identifier
, args
, loc
, nameEscaped
)
1305 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1306 // each time a new file is parsed. However, we need to use the NamespaceEntry
1307 // in effect where the attribute was used. Since code elsewhere cannot assume
1308 // that the NamespaceEntry is right, just overwrite it.
1310 // Precondition: RootContext.ToplevelTypes == null
1312 if (RootContext
.ToplevelTypes
.NamespaceEntry
!= null)
1313 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1315 RootContext
.ToplevelTypes
.NamespaceEntry
= ns
;
1320 RootContext
.ToplevelTypes
.NamespaceEntry
= null;
1323 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
1327 return base.ResolveAsTypeTerminal (expr
, ec
, silent
);
1334 protected override ConstructorInfo
ResolveConstructor (EmitContext ec
)
1338 return base.ResolveConstructor (ec
);
1345 protected override bool ResolveNamedArguments (EmitContext ec
)
1349 return base.ResolveNamedArguments (ec
);
1357 public class Attributes
{
1358 public readonly ArrayList Attrs
;
1360 public Attributes (Attribute a
)
1362 Attrs
= new ArrayList ();
1366 public Attributes (ArrayList attrs
)
1371 public void AddAttributes (ArrayList attrs
)
1373 Attrs
.AddRange (attrs
);
1376 public void AttachTo (Attributable attributable
)
1378 foreach (Attribute a
in Attrs
)
1379 a
.AttachTo (attributable
);
1383 /// Checks whether attribute target is valid for the current element
1385 public bool CheckTargets ()
1387 foreach (Attribute a
in Attrs
) {
1388 if (!a
.CheckTarget ())
1394 public Attribute
Search (Type t
)
1396 foreach (Attribute a
in Attrs
) {
1397 if (a
.ResolveType () == t
)
1404 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1406 public Attribute
[] SearchMulti (Type t
)
1408 ArrayList ar
= null;
1410 foreach (Attribute a
in Attrs
) {
1411 if (a
.ResolveType () == t
) {
1413 ar
= new ArrayList ();
1418 return ar
== null ? null : ar
.ToArray (typeof (Attribute
)) as Attribute
[];
1425 ListDictionary ld
= Attrs
.Count
> 1 ? new ListDictionary () : null;
1427 foreach (Attribute a
in Attrs
)
1430 if (ld
== null || ld
.Count
== 0)
1433 foreach (DictionaryEntry d
in ld
) {
1434 if (d
.Value
== null)
1437 foreach (Attribute collision
in (ArrayList
)d
.Value
)
1438 Report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1440 Attribute a
= (Attribute
)d
.Key
;
1441 Report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times", a
.GetSignatureForError ());
1445 public bool Contains (Type t
)
1447 return Search (t
) != null;
1452 /// Helper class for attribute verification routine.
1454 sealed class AttributeTester
1456 static PtrHashtable analyzed_types
;
1457 static PtrHashtable analyzed_types_obsolete
;
1458 static PtrHashtable analyzed_member_obsolete
;
1459 static PtrHashtable analyzed_method_excluded
;
1462 static PtrHashtable fixed_buffer_cache
;
1465 static object TRUE
= new object ();
1466 static object FALSE
= new object ();
1468 static AttributeTester ()
1473 private AttributeTester ()
1477 public static void Reset ()
1479 analyzed_types
= new PtrHashtable ();
1480 analyzed_types_obsolete
= new PtrHashtable ();
1481 analyzed_member_obsolete
= new PtrHashtable ();
1482 analyzed_method_excluded
= new PtrHashtable ();
1484 fixed_buffer_cache
= new PtrHashtable ();
1488 public enum Result
{
1495 /// Returns true if parameters of two compared methods are CLS-Compliant.
1496 /// It tests differing only in ref or out, or in array rank.
1498 public static Result
AreOverloadedMethodParamsClsCompliant (Type
[] types_a
, Type
[] types_b
)
1500 if (types_a
== null || types_b
== null)
1503 if (types_a
.Length
!= types_b
.Length
)
1506 Result result
= Result
.Ok
;
1507 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1508 Type aType
= types_a
[i
];
1509 Type bType
= types_b
[i
];
1511 if (aType
.IsArray
&& bType
.IsArray
) {
1512 Type a_el_type
= aType
.GetElementType ();
1513 Type b_el_type
= bType
.GetElementType ();
1514 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1515 result
= Result
.RefOutArrayError
;
1519 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1520 result
= Result
.ArrayArrayError
;
1525 Type aBaseType
= aType
;
1526 bool is_either_ref_or_out
= false;
1528 if (aType
.IsByRef
|| aType
.IsPointer
) {
1529 aBaseType
= aType
.GetElementType ();
1530 is_either_ref_or_out
= true;
1533 Type bBaseType
= bType
;
1534 if (bType
.IsByRef
|| bType
.IsPointer
)
1536 bBaseType
= bType
.GetElementType ();
1537 is_either_ref_or_out
= !is_either_ref_or_out
;
1540 if (aBaseType
!= bBaseType
)
1543 if (is_either_ref_or_out
)
1544 result
= Result
.RefOutArrayError
;
1550 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1552 public static bool IsClsCompliant (Type type
)
1557 object type_compliance
= analyzed_types
[type
];
1558 if (type_compliance
!= null)
1559 return type_compliance
== TRUE
;
1561 if (type
.IsPointer
) {
1562 analyzed_types
.Add (type
, null);
1567 if (type
.IsArray
|| type
.IsByRef
) {
1568 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1570 result
= AnalyzeTypeCompliance (type
);
1572 analyzed_types
.Add (type
, result
? TRUE
: FALSE
);
1577 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1579 public static IFixedBuffer
GetFixedBuffer (FieldInfo fi
)
1581 // Fixed buffer helper type is generated as value type
1582 if (!fi
.FieldType
.IsValueType
)
1585 FieldBase fb
= TypeManager
.GetField (fi
);
1587 return fb
as IFixedBuffer
;
1591 object o
= fixed_buffer_cache
[fi
];
1593 if (System
.Attribute
.GetCustomAttribute (fi
, TypeManager
.fixed_buffer_attr_type
) == null) {
1594 fixed_buffer_cache
.Add (fi
, FALSE
);
1598 IFixedBuffer iff
= new FixedFieldExternal (fi
);
1599 fixed_buffer_cache
.Add (fi
, iff
);
1606 return (IFixedBuffer
)o
;
1612 public static void VerifyModulesClsCompliance ()
1614 Module
[] modules
= RootNamespace
.Global
.Modules
;
1615 if (modules
== null)
1618 // The first module is generated assembly
1619 for (int i
= 1; i
< modules
.Length
; ++i
) {
1620 Module module
= modules
[i
];
1621 if (!IsClsCompliant (module
)) {
1622 Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1623 "to match the assembly", module
.Name
);
1629 public static Type
GetImportedIgnoreCaseClsType (string name
)
1631 foreach (Assembly a
in RootNamespace
.Global
.Assemblies
) {
1632 Type t
= a
.GetType (name
, false, true);
1636 if (IsClsCompliant (t
))
1642 static bool IsClsCompliant (ICustomAttributeProvider attribute_provider
)
1644 object[] CompliantAttribute
= attribute_provider
.GetCustomAttributes (TypeManager
.cls_compliant_attribute_type
, false);
1645 if (CompliantAttribute
.Length
== 0)
1648 return ((CLSCompliantAttribute
)CompliantAttribute
[0]).IsCompliant
;
1651 static bool AnalyzeTypeCompliance (Type type
)
1653 type
= TypeManager
.DropGenericTypeArguments (type
);
1654 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1656 return ds
.IsClsComplianceRequired ();
1659 if (TypeManager
.IsGenericParameter (type
))
1662 object[] CompliantAttribute
= type
.GetCustomAttributes (TypeManager
.cls_compliant_attribute_type
, false);
1663 if (CompliantAttribute
.Length
== 0)
1664 return IsClsCompliant (type
.Assembly
);
1666 return ((CLSCompliantAttribute
)CompliantAttribute
[0]).IsCompliant
;
1669 // Registers the core type as we assume that they will never be obsolete which
1670 // makes things easier for bootstrap and faster (we don't need to query Obsolete attribute).
1671 public static void RegisterNonObsoleteType (Type type
)
1673 analyzed_types_obsolete
[type
] = FALSE
;
1677 /// Returns instance of ObsoleteAttribute when type is obsolete
1679 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1681 object type_obsolete
= analyzed_types_obsolete
[type
];
1682 if (type_obsolete
== FALSE
)
1685 if (type_obsolete
!= null)
1686 return (ObsoleteAttribute
)type_obsolete
;
1688 ObsoleteAttribute result
= null;
1689 if (TypeManager
.HasElementType (type
)) {
1690 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1691 } else if (TypeManager
.IsGenericParameter (type
) || TypeManager
.IsGenericType (type
))
1694 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1696 // Type is external, we can get attribute directly
1697 if (type_ds
== null) {
1698 object[] attribute
= type
.GetCustomAttributes (TypeManager
.obsolete_attribute_type
, false);
1699 if (attribute
.Length
== 1)
1700 result
= (ObsoleteAttribute
)attribute
[0];
1702 result
= type_ds
.GetObsoleteAttribute ();
1706 // Cannot use .Add because of corlib bootstrap
1707 analyzed_types_obsolete
[type
] = result
== null ? FALSE
: result
;
1712 /// Returns instance of ObsoleteAttribute when method is obsolete
1714 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1716 IMethodData mc
= TypeManager
.GetMethod (mb
);
1718 return mc
.GetObsoleteAttribute ();
1720 // compiler generated methods are not registered by AddMethod
1721 if (mb
.DeclaringType
is TypeBuilder
)
1724 MemberInfo mi
= TypeManager
.GetPropertyFromAccessor (mb
);
1726 return GetMemberObsoleteAttribute (mi
);
1728 mi
= TypeManager
.GetEventFromAccessor (mb
);
1730 return GetMemberObsoleteAttribute (mi
);
1732 return GetMemberObsoleteAttribute (mb
);
1736 /// Returns instance of ObsoleteAttribute when member is obsolete
1738 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1740 object type_obsolete
= analyzed_member_obsolete
[mi
];
1741 if (type_obsolete
== FALSE
)
1744 if (type_obsolete
!= null)
1745 return (ObsoleteAttribute
)type_obsolete
;
1747 if ((mi
.DeclaringType
is TypeBuilder
) || TypeManager
.IsGenericType (mi
.DeclaringType
))
1750 ObsoleteAttribute oa
= System
.Attribute
.GetCustomAttribute (mi
, TypeManager
.obsolete_attribute_type
, false)
1751 as ObsoleteAttribute
;
1752 analyzed_member_obsolete
.Add (mi
, oa
== null ? FALSE
: oa
);
1757 /// Common method for Obsolete error/warning reporting.
1759 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
)
1762 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1766 if (oa
.Message
== null) {
1767 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1770 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1773 public static bool IsConditionalMethodExcluded (MethodBase mb
)
1775 mb
= TypeManager
.DropGenericMethodArguments (mb
);
1776 if ((mb
is MethodBuilder
) || (mb
is ConstructorBuilder
))
1779 object excluded
= analyzed_method_excluded
[mb
];
1780 if (excluded
!= null)
1781 return excluded
== TRUE
? true : false;
1783 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (TypeManager
.conditional_attribute_type
, true)
1784 as ConditionalAttribute
[];
1785 if (attrs
.Length
== 0) {
1786 analyzed_method_excluded
.Add (mb
, FALSE
);
1790 foreach (ConditionalAttribute a
in attrs
) {
1791 if (RootContext
.AllDefines
.Contains (a
.ConditionString
)) {
1792 analyzed_method_excluded
.Add (mb
, FALSE
);
1796 analyzed_method_excluded
.Add (mb
, TRUE
);
1801 /// Analyzes class whether it has attribute which has ConditionalAttribute
1802 /// and its condition is not defined.
1804 public static bool IsAttributeExcluded (Type type
)
1809 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1811 // TODO: add caching
1812 // TODO: merge all Type bases attribute caching to one cache to save memory
1813 if (class_decl
== null) {
1814 object[] attributes
= type
.GetCustomAttributes (TypeManager
.conditional_attribute_type
, false);
1815 foreach (ConditionalAttribute ca
in attributes
) {
1816 if (RootContext
.AllDefines
.Contains (ca
.ConditionString
))
1819 return attributes
.Length
> 0;
1822 return class_decl
.IsExcluded ();
1825 public static Type
GetCoClassAttribute (Type type
)
1827 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1829 object[] o
= type
.GetCustomAttributes (TypeManager
.coclass_attr_type
, false);
1832 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1835 if (tc
.OptAttributes
== null)
1838 Attribute a
= tc
.OptAttributes
.Search (TypeManager
.coclass_attr_type
);
1842 return a
.GetCoClassAttributeValue ();