2 // attribute.cs: Attribute Handler
4 // Author: Ravi Pratap (ravi@ximian.com)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
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
: Expression
81 // Wraps owner resolve context, the owner is an attribute
82 // parent and the rest is exactly same
84 struct AttributeResolveContext
: IResolveContext
86 readonly IResolveContext rc
;
88 public AttributeResolveContext (IResolveContext rc
)
93 #region IResolveContext Members
95 public DeclSpace DeclContainer
{
97 DeclSpace ds
= rc
as DeclSpace
;
99 return rc
.DeclContainer
;
105 public bool IsInObsoleteScope
{
106 get { return rc.IsInObsoleteScope; }
109 public bool IsInUnsafeScope
{
110 get { return rc.IsInUnsafeScope; }
113 public DeclSpace GenericDeclContainer
{
114 get { return rc.GenericDeclContainer; }
120 public readonly string ExplicitTarget
;
121 public AttributeTargets Target
;
123 // TODO: remove this member
124 public readonly string Name
;
125 public readonly Expression LeftExpr
;
126 public readonly string Identifier
;
128 ArrayList PosArguments
;
129 ArrayList NamedArguments
;
132 readonly bool nameEscaped
;
134 // It can contain more onwers when the attribute is applied to multiple fiels.
135 protected Attributable
[] owners
;
137 static readonly AttributeUsageAttribute DefaultUsageAttribute
= new AttributeUsageAttribute (AttributeTargets
.All
);
138 static Assembly orig_sec_assembly
;
139 public static readonly object[] EmptyObject
= new object [0];
141 // non-null if named args present after Resolve () is called
142 PropertyInfo
[] prop_info_arr
;
143 FieldInfo
[] field_info_arr
;
144 object [] field_values_arr
;
145 object [] prop_values_arr
;
146 object [] pos_values
;
148 static PtrHashtable usage_attr_cache
;
149 // Cache for parameter-less attributes
150 static PtrHashtable att_cache
;
152 public Attribute (string target
, Expression left_expr
, string identifier
, object[] args
, Location loc
, bool nameEscaped
)
154 LeftExpr
= left_expr
;
155 Identifier
= identifier
;
156 Name
= LeftExpr
== null ? identifier
: LeftExpr
+ "." + identifier
;
158 PosArguments
= (ArrayList
)args
[0];
159 NamedArguments
= (ArrayList
)args
[1];
162 ExplicitTarget
= target
;
163 this.nameEscaped
= nameEscaped
;
166 public Attribute
Clone ()
168 Attribute a
= new Attribute (ExplicitTarget
, LeftExpr
, Identifier
, null, loc
, nameEscaped
);
169 a
.PosArguments
= PosArguments
;
170 a
.NamedArguments
= NamedArguments
;
179 public static void Reset ()
181 usage_attr_cache
= new PtrHashtable ();
182 att_cache
= new PtrHashtable ();
185 public virtual void AttachTo (Attributable owner
)
187 if (this.owners
== null) {
188 this.owners
= new Attributable
[1] { owner }
;
192 // When the same attribute is attached to multiple fiels
193 // we use this extra_owners as a list of owners. The attribute
194 // then can be removed because will be emitted when first owner
196 Attributable
[] new_array
= new Attributable
[this.owners
.Length
+ 1];
197 owners
.CopyTo (new_array
, 0);
198 new_array
[owners
.Length
] = owner
;
199 this.owners
= new_array
;
200 owner
.OptAttributes
= null;
203 void Error_InvalidNamedArgument (string name
)
205 Report
.Error (617, Location
, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
206 "must be fields which are not readonly, static, const or read-write properties which are " +
207 "public and not static",
211 void Error_InvalidNamedAgrumentType (string name
)
213 Report
.Error (655, Location
, "`{0}' is not a valid named attribute argument because it is not a valid " +
214 "attribute parameter type", name
);
217 public static void Error_AttributeArgumentNotValid (Location loc
)
219 Report
.Error (182, loc
,
220 "An attribute argument must be a constant expression, typeof " +
221 "expression or array creation expression");
224 static void Error_TypeParameterInAttribute (Location loc
)
227 -202, loc
, "Can not use a type parameter in an attribute");
230 public void Error_MissingGuidAttribute ()
232 Report
.Error (596, Location
, "The Guid attribute must be specified with the ComImport attribute");
235 public void Error_MisusedExtensionAttribute ()
237 Report
.Error (1112, Location
, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
241 /// This is rather hack. We report many emit attribute error with same error to be compatible with
242 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
244 public void Error_AttributeEmitError (string inner
)
246 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
247 TypeManager
.CSharpName (Type
), inner
);
250 public void Error_InvalidSecurityParent ()
252 Error_AttributeEmitError ("it is attached to invalid parent");
261 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
263 return expr
.ResolveAsTypeTerminal (ec
, silent
);
266 Type
ResolvePossibleAttributeType (string name
, bool silent
, ref bool is_attr
)
268 IResolveContext rc
= new AttributeResolveContext (Owner
.ResolveContext
);
271 if (LeftExpr
== null) {
272 te
= ResolveAsTypeTerminal (new SimpleName (name
, Location
), rc
, silent
);
274 te
= ResolveAsTypeTerminal (new MemberAccess (LeftExpr
, name
), rc
, silent
);
281 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
283 } else if (!silent
) {
284 Report
.SymbolRelatedToPreviousError (t
);
285 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
291 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
293 void ResolveAttributeType ()
295 bool t1_is_attr
= false;
296 Type t1
= ResolvePossibleAttributeType (Identifier
, true, ref t1_is_attr
);
298 bool t2_is_attr
= false;
299 Type t2
= nameEscaped
? null :
300 ResolvePossibleAttributeType (Identifier
+ "Attribute", true, ref t2_is_attr
);
302 if (t1_is_attr
&& t2_is_attr
) {
303 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " +
304 "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
305 resolve_error
= true;
319 if (t1
== null && t2
== null)
320 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
322 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
324 ResolvePossibleAttributeType (Identifier
+ "Attribute", false, ref t2_is_attr
);
326 resolve_error
= true;
329 public virtual Type
ResolveType ()
331 if (Type
== null && !resolve_error
)
332 ResolveAttributeType ();
336 public override string GetSignatureForError ()
339 return TypeManager
.CSharpName (Type
);
341 return LeftExpr
== null ? Identifier
: LeftExpr
.GetSignatureForError () + "." + Identifier
;
344 public bool HasSecurityAttribute
{
346 return TypeManager
.security_attr_type
!= null &&
347 TypeManager
.IsSubclassOf (type
, TypeManager
.security_attr_type
);
351 public bool IsValidSecurityAttribute ()
353 return HasSecurityAttribute
&& IsSecurityActionValid (false);
356 static bool IsValidArgumentType (Type t
)
359 t
= TypeManager
.GetElementType (t
);
361 return t
== TypeManager
.string_type
||
362 TypeManager
.IsPrimitiveType (t
) ||
363 TypeManager
.IsEnumType (t
) ||
364 t
== TypeManager
.object_type
||
365 t
== TypeManager
.type_type
;
368 [Conditional ("GMCS_SOURCE")]
369 void ApplyModuleCharSet ()
371 if (Type
!= TypeManager
.dllimport_type
)
374 if (!CodeGen
.Module
.HasDefaultCharSet
)
377 const string CharSetEnumMember
= "CharSet";
378 if (NamedArguments
== null) {
379 NamedArguments
= new ArrayList (1);
381 foreach (DictionaryEntry de
in NamedArguments
) {
382 if ((string)de
.Key
== CharSetEnumMember
)
387 NamedArguments
.Add (new DictionaryEntry (CharSetEnumMember
,
388 new Argument (Constant
.CreateConstant (typeof (CharSet
), CodeGen
.Module
.DefaultCharSet
, Location
))));
391 public CustomAttributeBuilder
Resolve ()
396 resolve_error
= true;
399 ResolveAttributeType ();
404 if (Type
.IsAbstract
) {
405 Report
.Error (653, Location
, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
409 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (Type
);
410 if (obsolete_attr
!= null) {
411 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, TypeManager
.CSharpName (Type
), Location
);
414 if (PosArguments
== null && NamedArguments
== null) {
415 object o
= att_cache
[Type
];
417 resolve_error
= false;
418 return (CustomAttributeBuilder
)o
;
422 Attributable owner
= Owner
;
423 DeclSpace ds
= owner
.ResolveContext
as DeclSpace
;
425 ds
= owner
.ResolveContext
.DeclContainer
;
427 EmitContext ec
= new EmitContext (owner
.ResolveContext
, ds
, ds
,
428 Location
, null, typeof (Attribute
), ds
.ModFlags
, false);
429 ec
.IsAnonymousMethodAllowed
= false;
431 ConstructorInfo ctor
= ResolveConstructor (ec
);
433 if (Type
is TypeBuilder
&&
434 TypeManager
.LookupDeclSpace (Type
).MemberCache
== null)
435 // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error.
436 // It'll be resolved again when the attached-to entity is emitted.
437 resolve_error
= false;
441 ApplyModuleCharSet ();
443 CustomAttributeBuilder cb
;
445 // SRE does not allow private ctor but we want to report all source code errors
449 if (NamedArguments
== null) {
450 cb
= new CustomAttributeBuilder (ctor
, pos_values
);
452 if (pos_values
.Length
== 0)
453 att_cache
.Add (Type
, cb
);
455 resolve_error
= false;
459 if (!ResolveNamedArguments (ec
)) {
463 cb
= new CustomAttributeBuilder (ctor
, pos_values
,
464 prop_info_arr
, prop_values_arr
,
465 field_info_arr
, field_values_arr
);
467 resolve_error
= false;
471 Error_AttributeArgumentNotValid (Location
);
476 protected virtual ConstructorInfo
ResolveConstructor (EmitContext ec
)
478 if (PosArguments
!= null) {
479 for (int i
= 0; i
< PosArguments
.Count
; i
++) {
480 Argument a
= (Argument
) PosArguments
[i
];
482 if (!a
.Resolve (ec
, Location
))
487 MethodGroupExpr mg
= MemberLookupFinal (ec
, ec
.ContainerType
,
488 Type
, ".ctor", MemberTypes
.Constructor
,
489 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
490 Location
) as MethodGroupExpr
;
495 mg
= mg
.OverloadResolve (ec
, ref PosArguments
, false, Location
);
499 ConstructorInfo constructor
= (ConstructorInfo
)mg
;
500 if (PosArguments
== null) {
501 pos_values
= EmptyObject
;
505 AParametersCollection pd
= TypeManager
.GetParameterData (constructor
);
507 int pos_arg_count
= PosArguments
.Count
;
508 pos_values
= new object [pos_arg_count
];
509 for (int j
= 0; j
< pos_arg_count
; ++j
) {
510 Argument a
= (Argument
) PosArguments
[j
];
512 if (!a
.Expr
.GetAttributableValue (ec
, a
.Type
, out pos_values
[j
]))
516 // Here we do the checks which should be done by corlib or by runtime.
517 // However Zoltan doesn't like it and every Mono compiler has to do it again.
519 if (Type
== TypeManager
.guid_attr_type
) {
521 new Guid ((string)pos_values
[0]);
523 catch (Exception e
) {
524 Error_AttributeEmitError (e
.Message
);
529 if (Type
== TypeManager
.attribute_usage_type
&& (int)pos_values
[0] == 0) {
530 Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
534 if (Type
== TypeManager
.indexer_name_type
|| Type
== TypeManager
.conditional_attribute_type
) {
535 string v
= pos_values
[0] as string;
536 if (!Tokenizer
.IsValidIdentifier (v
) || Tokenizer
.IsKeyword (v
)) {
537 Report
.Error (633, ((Argument
)PosArguments
[0]).Expr
.Location
,
538 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
543 if (Type
== TypeManager
.methodimpl_attr_type
&& pos_values
.Length
== 1 &&
544 pd
.Types
[0] == TypeManager
.short_type
&&
545 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
546 Error_AttributeEmitError ("Incorrect argument value.");
553 protected virtual bool ResolveNamedArguments (EmitContext ec
)
555 int named_arg_count
= NamedArguments
.Count
;
557 ArrayList field_infos
= new ArrayList (named_arg_count
);
558 ArrayList prop_infos
= new ArrayList (named_arg_count
);
559 ArrayList field_values
= new ArrayList (named_arg_count
);
560 ArrayList prop_values
= new ArrayList (named_arg_count
);
562 ArrayList seen_names
= new ArrayList(named_arg_count
);
564 foreach (DictionaryEntry de
in NamedArguments
) {
565 string member_name
= (string) de
.Key
;
567 if (seen_names
.Contains(member_name
)) {
568 Report
.Error(643, Location
, "'{0}' duplicate named attribute argument", member_name
);
571 seen_names
.Add(member_name
);
573 Argument a
= (Argument
) de
.Value
;
574 if (!a
.Resolve (ec
, Location
))
577 Expression member
= Expression
.MemberLookup (
578 ec
.ContainerType
, Type
, member_name
,
579 MemberTypes
.Field
| MemberTypes
.Property
,
580 BindingFlags
.Public
| BindingFlags
.Instance
,
583 if (member
== null) {
584 member
= Expression
.MemberLookup (ec
.ContainerType
, Type
, member_name
,
585 MemberTypes
.Field
| MemberTypes
.Property
, BindingFlags
.NonPublic
| BindingFlags
.Instance
,
588 if (member
!= null) {
589 Report
.SymbolRelatedToPreviousError (member
.Type
);
590 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError ());
596 Expression
.Error_TypeDoesNotContainDefinition (Location
, Type
, member_name
);
600 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
601 Error_InvalidNamedArgument (member_name
);
605 if (a
.Expr
is TypeParameterExpr
){
606 Error_TypeParameterInAttribute (Location
);
610 ObsoleteAttribute obsolete_attr
;
612 if (member
is PropertyExpr
) {
613 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
615 if (!pi
.CanWrite
|| !pi
.CanRead
) {
616 Report
.SymbolRelatedToPreviousError (pi
);
617 Error_InvalidNamedArgument (member_name
);
621 if (!IsValidArgumentType (member
.Type
)) {
622 Report
.SymbolRelatedToPreviousError (pi
);
623 Error_InvalidNamedAgrumentType (member_name
);
628 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
631 PropertyBase pb
= TypeManager
.GetProperty (pi
);
633 obsolete_attr
= pb
.GetObsoleteAttribute ();
635 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
637 prop_values
.Add (value);
641 FieldInfo fi
= ((FieldExpr
) member
).FieldInfo
;
644 Error_InvalidNamedArgument (member_name
);
648 if (!IsValidArgumentType (member
.Type
)) {
649 Report
.SymbolRelatedToPreviousError (fi
);
650 Error_InvalidNamedAgrumentType (member_name
);
655 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
658 FieldBase fb
= TypeManager
.GetField (fi
);
660 obsolete_attr
= fb
.GetObsoleteAttribute ();
662 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
664 field_values
.Add (value);
665 field_infos
.Add (fi
);
668 if (obsolete_attr
!= null && !Owner
.ResolveContext
.IsInObsoleteScope
)
669 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
);
672 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
673 field_info_arr
= new FieldInfo
[field_infos
.Count
];
674 field_values_arr
= new object [field_values
.Count
];
675 prop_values_arr
= new object [prop_values
.Count
];
677 field_infos
.CopyTo (field_info_arr
, 0);
678 field_values
.CopyTo (field_values_arr
, 0);
680 prop_values
.CopyTo (prop_values_arr
, 0);
681 prop_infos
.CopyTo (prop_info_arr
, 0);
687 /// Get a string containing a list of valid targets for the attribute 'attr'
689 public string GetValidTargets ()
691 StringBuilder sb
= new StringBuilder ();
692 AttributeTargets targets
= GetAttributeUsage (Type
).ValidOn
;
694 if ((targets
& AttributeTargets
.Assembly
) != 0)
695 sb
.Append ("assembly, ");
697 if ((targets
& AttributeTargets
.Module
) != 0)
698 sb
.Append ("module, ");
700 if ((targets
& AttributeTargets
.Class
) != 0)
701 sb
.Append ("class, ");
703 if ((targets
& AttributeTargets
.Struct
) != 0)
704 sb
.Append ("struct, ");
706 if ((targets
& AttributeTargets
.Enum
) != 0)
707 sb
.Append ("enum, ");
709 if ((targets
& AttributeTargets
.Constructor
) != 0)
710 sb
.Append ("constructor, ");
712 if ((targets
& AttributeTargets
.Method
) != 0)
713 sb
.Append ("method, ");
715 if ((targets
& AttributeTargets
.Property
) != 0)
716 sb
.Append ("property, indexer, ");
718 if ((targets
& AttributeTargets
.Field
) != 0)
719 sb
.Append ("field, ");
721 if ((targets
& AttributeTargets
.Event
) != 0)
722 sb
.Append ("event, ");
724 if ((targets
& AttributeTargets
.Interface
) != 0)
725 sb
.Append ("interface, ");
727 if ((targets
& AttributeTargets
.Parameter
) != 0)
728 sb
.Append ("parameter, ");
730 if ((targets
& AttributeTargets
.Delegate
) != 0)
731 sb
.Append ("delegate, ");
733 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
734 sb
.Append ("return, ");
737 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
738 sb
.Append ("type parameter, ");
740 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
744 /// Returns AttributeUsage attribute based on types hierarchy
746 static AttributeUsageAttribute
GetAttributeUsage (Type type
)
748 AttributeUsageAttribute ua
= usage_attr_cache
[type
] as AttributeUsageAttribute
;
752 Class attr_class
= TypeManager
.LookupClass (type
);
754 if (attr_class
== null) {
755 object[] usage_attr
= type
.GetCustomAttributes (TypeManager
.attribute_usage_type
, true);
756 ua
= (AttributeUsageAttribute
)usage_attr
[0];
757 usage_attr_cache
.Add (type
, ua
);
762 if (attr_class
.OptAttributes
!= null)
763 a
= attr_class
.OptAttributes
.Search (TypeManager
.attribute_usage_type
);
766 if (attr_class
.TypeBuilder
.BaseType
!= TypeManager
.attribute_type
)
767 ua
= GetAttributeUsage (attr_class
.TypeBuilder
.BaseType
);
769 ua
= DefaultUsageAttribute
;
771 ua
= a
.GetAttributeUsageAttribute ();
774 usage_attr_cache
.Add (type
, ua
);
778 AttributeUsageAttribute
GetAttributeUsageAttribute ()
780 if (pos_values
== null)
781 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
782 // But because a lot of attribute class code must be rewritten will be better to wait...
786 return DefaultUsageAttribute
;
788 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
790 object field
= GetPropertyValue ("AllowMultiple");
792 usage_attribute
.AllowMultiple
= (bool)field
;
794 field
= GetPropertyValue ("Inherited");
796 usage_attribute
.Inherited
= (bool)field
;
798 return usage_attribute
;
802 /// Returns custom name of indexer
804 public string GetIndexerAttributeValue ()
806 if (pos_values
== null)
807 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
808 // But because a lot of attribute class code must be rewritten will be better to wait...
814 return pos_values
[0] as string;
818 /// Returns condition of ConditionalAttribute
820 public string GetConditionalAttributeValue ()
822 if (pos_values
== null)
823 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
824 // But because a lot of attribute class code must be rewritten will be better to wait...
830 return (string)pos_values
[0];
834 /// Creates the instance of ObsoleteAttribute from this attribute instance
836 public ObsoleteAttribute
GetObsoleteAttribute ()
838 if (pos_values
== null)
839 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
840 // But because a lot of attribute class code must be rewritten will be better to wait...
846 if (pos_values
== null || pos_values
.Length
== 0)
847 return new ObsoleteAttribute ();
849 if (pos_values
.Length
== 1)
850 return new ObsoleteAttribute ((string)pos_values
[0]);
852 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
856 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
857 /// before ApplyAttribute. We need to resolve the arguments.
858 /// This situation occurs when class deps is differs from Emit order.
860 public bool GetClsCompliantAttributeValue ()
862 if (pos_values
== null)
863 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
864 // But because a lot of attribute class code must be rewritten will be better to wait...
870 return (bool)pos_values
[0];
873 public Type
GetCoClassAttributeValue ()
875 if (pos_values
== null)
881 return (Type
)pos_values
[0];
884 public bool CheckTarget ()
886 string[] valid_targets
= Owner
.ValidAttributeTargets
;
887 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
888 Target
= Owner
.AttributeTargets
;
892 // TODO: we can skip the first item
893 if (((IList
) valid_targets
).Contains (ExplicitTarget
)) {
894 switch (ExplicitTarget
) {
895 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
896 case "param": Target
= AttributeTargets
.Parameter
; return true;
897 case "field": Target
= AttributeTargets
.Field
; return true;
898 case "method": Target
= AttributeTargets
.Method
; return true;
899 case "property": Target
= AttributeTargets
.Property
; return true;
901 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
904 StringBuilder sb
= new StringBuilder ();
905 foreach (string s
in valid_targets
) {
909 sb
.Remove (sb
.Length
- 2, 2);
910 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
911 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
916 /// Tests permitted SecurityAction for assembly or other types
918 protected virtual bool IsSecurityActionValid (bool for_assembly
)
920 SecurityAction action
= GetSecurityActionValue ();
923 case SecurityAction
.Demand
:
924 case SecurityAction
.Assert
:
925 case SecurityAction
.Deny
:
926 case SecurityAction
.PermitOnly
:
927 case SecurityAction
.LinkDemand
:
928 case SecurityAction
.InheritanceDemand
:
933 case SecurityAction
.RequestMinimum
:
934 case SecurityAction
.RequestOptional
:
935 case SecurityAction
.RequestRefuse
:
941 Error_AttributeEmitError ("SecurityAction is out of range");
945 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
949 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
951 return (SecurityAction
)pos_values
[0];
955 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
957 /// <returns></returns>
958 public void ExtractSecurityPermissionSet (ListDictionary permissions
)
960 Type orig_assembly_type
= null;
962 if (TypeManager
.LookupDeclSpace (Type
) != null) {
963 if (!RootContext
.StdLib
) {
964 orig_assembly_type
= Type
.GetType (Type
.FullName
);
966 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
967 if (orig_version_path
== null) {
968 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
972 if (orig_sec_assembly
== null) {
973 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
974 orig_sec_assembly
= Assembly
.LoadFile (file
);
977 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
978 if (orig_assembly_type
== null) {
979 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
980 "was not found in previous version of assembly");
986 SecurityAttribute sa
;
987 // For all non-selfreferencing security attributes we can avoid all hacks
988 if (orig_assembly_type
== null) {
989 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
991 if (prop_info_arr
!= null) {
992 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
993 PropertyInfo pi
= prop_info_arr
[i
];
994 pi
.SetValue (sa
, prop_values_arr
[i
], null);
998 // HACK: All security attributes have same ctor syntax
999 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
1001 // All types are from newly created assembly but for invocation with old one we need to convert them
1002 if (prop_info_arr
!= null) {
1003 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1004 PropertyInfo emited_pi
= prop_info_arr
[i
];
1005 // FIXME: We are missing return type filter
1006 // TODO: pi can be null
1007 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
);
1009 object old_instance
= TypeManager
.IsEnumType (pi
.PropertyType
) ?
1010 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
1011 prop_values_arr
[i
];
1013 pi
.SetValue (sa
, old_instance
, null);
1019 perm
= sa
.CreatePermission ();
1020 SecurityAction action
= GetSecurityActionValue ();
1022 // IS is correct because for corlib we are using an instance from old corlib
1023 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
1025 case SecurityAction
.Demand
:
1026 action
= (SecurityAction
)13;
1028 case SecurityAction
.LinkDemand
:
1029 action
= (SecurityAction
)14;
1031 case SecurityAction
.InheritanceDemand
:
1032 action
= (SecurityAction
)15;
1037 PermissionSet ps
= (PermissionSet
)permissions
[action
];
1039 if (sa
is PermissionSetAttribute
)
1040 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
1042 ps
= new PermissionSet (PermissionState
.None
);
1044 permissions
.Add (action
, ps
);
1045 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
1046 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
1047 permissions
[action
] = ps
;
1049 ps
.AddPermission (perm
);
1052 public object GetPropertyValue (string name
)
1054 if (prop_info_arr
== null)
1057 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1058 if (prop_info_arr
[i
].Name
== name
)
1059 return prop_values_arr
[i
];
1066 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1067 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1068 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1071 public UnmanagedMarshal
GetMarshal (Attributable attr
)
1073 UnmanagedType UnmanagedType
;
1074 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (UnmanagedType
))
1075 UnmanagedType
= (UnmanagedType
) System
.Enum
.ToObject (typeof (UnmanagedType
), pos_values
[0]);
1077 UnmanagedType
= (UnmanagedType
) pos_values
[0];
1079 object value = GetFieldValue ("SizeParamIndex");
1080 if (value != null && UnmanagedType
!= UnmanagedType
.LPArray
) {
1081 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1085 object o
= GetFieldValue ("ArraySubType");
1086 UnmanagedType array_sub_type
= o
== null ? (UnmanagedType
) 0x50 /* NATIVE_MAX */ : (UnmanagedType
) o
;
1088 switch (UnmanagedType
) {
1089 case UnmanagedType
.CustomMarshaler
: {
1090 MethodInfo define_custom
= typeof (UnmanagedMarshal
).GetMethod ("DefineCustom",
1091 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1092 if (define_custom
== null) {
1093 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1097 object [] args
= new object [4];
1098 args
[0] = GetFieldValue ("MarshalTypeRef");
1099 args
[1] = GetFieldValue ("MarshalCookie");
1100 args
[2] = GetFieldValue ("MarshalType");
1101 args
[3] = Guid
.Empty
;
1102 return (UnmanagedMarshal
) define_custom
.Invoke (null, args
);
1104 case UnmanagedType
.LPArray
: {
1105 object size_const
= GetFieldValue ("SizeConst");
1106 object size_param_index
= GetFieldValue ("SizeParamIndex");
1108 if ((size_const
!= null) || (size_param_index
!= null)) {
1109 MethodInfo define_array
= typeof (UnmanagedMarshal
).GetMethod ("DefineLPArrayInternal",
1110 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1111 if (define_array
== null) {
1112 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1116 object [] args
= new object [3];
1117 args
[0] = array_sub_type
;
1118 args
[1] = size_const
== null ? -1 : size_const
;
1119 args
[2] = size_param_index
== null ? -1 : size_param_index
;
1120 return (UnmanagedMarshal
) define_array
.Invoke (null, args
);
1123 return UnmanagedMarshal
.DefineLPArray (array_sub_type
);
1125 case UnmanagedType
.SafeArray
:
1126 return UnmanagedMarshal
.DefineSafeArray (array_sub_type
);
1128 case UnmanagedType
.ByValArray
:
1129 FieldBase fm
= attr
as FieldBase
;
1131 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1134 return UnmanagedMarshal
.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1136 case UnmanagedType
.ByValTStr
:
1137 return UnmanagedMarshal
.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1140 return UnmanagedMarshal
.DefineUnmanagedMarshal (UnmanagedType
);
1144 object GetFieldValue (string name
)
1147 if (field_info_arr
== null)
1150 foreach (FieldInfo fi
in field_info_arr
) {
1151 if (fi
.Name
== name
)
1152 return GetValue (field_values_arr
[i
]);
1158 static object GetValue (object value)
1160 if (value is EnumConstant
)
1161 return ((EnumConstant
) value).GetValue ();
1168 public CharSet
GetCharSetValue ()
1170 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1173 public bool HasField (string fieldName
)
1175 if (field_info_arr
== null)
1178 foreach (FieldInfo fi
in field_info_arr
) {
1179 if (fi
.Name
== fieldName
)
1186 public bool IsInternalMethodImplAttribute
{
1188 if (Type
!= TypeManager
.methodimpl_attr_type
)
1191 MethodImplOptions options
;
1192 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1193 options
= (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1195 options
= (MethodImplOptions
)pos_values
[0];
1197 return (options
& MethodImplOptions
.InternalCall
) != 0;
1201 public LayoutKind
GetLayoutKindValue ()
1203 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1204 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1206 return (LayoutKind
)pos_values
[0];
1209 public object GetParameterDefaultValue ()
1211 return pos_values
[0];
1214 public override bool Equals (object obj
)
1216 Attribute a
= obj
as Attribute
;
1220 return Type
== a
.Type
&& Target
== a
.Target
;
1223 public override int GetHashCode ()
1225 return base.GetHashCode ();
1229 /// Emit attribute for Attributable symbol
1231 public void Emit (ListDictionary allEmitted
)
1233 CustomAttributeBuilder cb
= Resolve ();
1237 AttributeUsageAttribute usage_attr
= GetAttributeUsage (Type
);
1238 if ((usage_attr
.ValidOn
& Target
) == 0) {
1239 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1240 "It is valid on `{1}' declarations only",
1241 GetSignatureForError (), GetValidTargets ());
1246 foreach (Attributable owner
in owners
)
1247 owner
.ApplyAttributeBuilder (this, cb
);
1249 catch (Exception e
) {
1250 Error_AttributeEmitError (e
.Message
);
1254 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1255 if (allEmitted
.Contains (this)) {
1256 ArrayList a
= allEmitted
[this] as ArrayList
;
1258 a
= new ArrayList (2);
1259 allEmitted
[this] = a
;
1263 allEmitted
.Add (this, null);
1267 if (!RootContext
.VerifyClsCompliance
)
1270 // Here we are testing attribute arguments for array usage (error 3016)
1271 if (Owner
.IsClsComplianceRequired ()) {
1272 if (PosArguments
!= null) {
1273 foreach (Argument arg
in PosArguments
) {
1274 // Type is undefined (was error 246)
1275 if (arg
.Type
== null)
1278 if (arg
.Type
.IsArray
) {
1279 Report
.Warning (3016, 1, Location
, "Arrays as attribute arguments are not CLS-compliant");
1285 if (NamedArguments
== null)
1288 foreach (DictionaryEntry de
in NamedArguments
) {
1289 Argument arg
= (Argument
) de
.Value
;
1291 // Type is undefined (was error 246)
1292 if (arg
.Type
== null)
1295 if (arg
.Type
.IsArray
) {
1296 Report
.Warning (3016, 1, Location
, "Arrays as attribute arguments are not CLS-compliant");
1303 private Expression
GetValue ()
1305 if (PosArguments
== null || PosArguments
.Count
< 1)
1308 return ((Argument
) PosArguments
[0]).Expr
;
1311 public string GetString ()
1313 Expression e
= GetValue ();
1314 if (e
is StringConstant
)
1315 return ((StringConstant
)e
).Value
;
1319 public bool GetBoolean ()
1321 Expression e
= GetValue ();
1322 if (e
is BoolConstant
)
1323 return ((BoolConstant
)e
).Value
;
1327 public Type
GetArgumentType ()
1329 TypeOf e
= GetValue () as TypeOf
;
1332 return e
.TypeArgument
;
1335 public override Expression
CreateExpressionTree (EmitContext ec
)
1337 throw new NotSupportedException ("ET");
1340 public override Expression
DoResolve (EmitContext ec
)
1342 throw new NotImplementedException ();
1345 public override void Emit (EmitContext ec
)
1347 throw new NotImplementedException ();
1353 /// For global attributes (assembly, module) we need special handling.
1354 /// Attributes can be located in the several files
1356 public class GlobalAttribute
: Attribute
1358 public readonly NamespaceEntry ns
;
1360 public GlobalAttribute (NamespaceEntry ns
, string target
,
1361 Expression left_expr
, string identifier
, object[] args
, Location loc
, bool nameEscaped
):
1362 base (target
, left_expr
, identifier
, args
, loc
, nameEscaped
)
1365 this.owners
= new Attributable
[1];
1368 public override void AttachTo (Attributable owner
)
1370 if (ExplicitTarget
== "assembly") {
1371 owners
[0] = CodeGen
.Assembly
;
1374 if (ExplicitTarget
== "module") {
1375 owners
[0] = CodeGen
.Module
;
1378 throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget
);
1383 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1384 // each time a new file is parsed. However, we need to use the NamespaceEntry
1385 // in effect where the attribute was used. Since code elsewhere cannot assume
1386 // that the NamespaceEntry is right, just overwrite it.
1388 // Precondition: RootContext.ToplevelTypes == null
1390 if (RootContext
.ToplevelTypes
.NamespaceEntry
!= null)
1391 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1393 RootContext
.ToplevelTypes
.NamespaceEntry
= ns
;
1396 protected override bool IsSecurityActionValid (bool for_assembly
)
1398 return base.IsSecurityActionValid (true);
1403 RootContext
.ToplevelTypes
.NamespaceEntry
= null;
1406 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
1410 return base.ResolveAsTypeTerminal (expr
, ec
, silent
);
1417 protected override ConstructorInfo
ResolveConstructor (EmitContext ec
)
1421 return base.ResolveConstructor (ec
);
1428 protected override bool ResolveNamedArguments (EmitContext ec
)
1432 return base.ResolveNamedArguments (ec
);
1440 public class Attributes
{
1441 public readonly ArrayList Attrs
;
1443 public Attributes (Attribute a
)
1445 Attrs
= new ArrayList ();
1449 public Attributes (ArrayList attrs
)
1454 public void AddAttributes (ArrayList attrs
)
1456 Attrs
.AddRange (attrs
);
1459 public void AttachTo (Attributable attributable
)
1461 foreach (Attribute a
in Attrs
)
1462 a
.AttachTo (attributable
);
1465 public Attributes
Clone ()
1467 ArrayList al
= new ArrayList (Attrs
.Count
);
1468 foreach (Attribute a
in Attrs
)
1469 al
.Add (a
.Clone ());
1471 return new Attributes (al
);
1475 /// Checks whether attribute target is valid for the current element
1477 public bool CheckTargets ()
1479 foreach (Attribute a
in Attrs
) {
1480 if (!a
.CheckTarget ())
1486 public Attribute
Search (Type t
)
1488 foreach (Attribute a
in Attrs
) {
1489 if (a
.ResolveType () == t
)
1496 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1498 public Attribute
[] SearchMulti (Type t
)
1500 ArrayList ar
= null;
1502 foreach (Attribute a
in Attrs
) {
1503 if (a
.ResolveType () == t
) {
1505 ar
= new ArrayList ();
1510 return ar
== null ? null : ar
.ToArray (typeof (Attribute
)) as Attribute
[];
1517 ListDictionary ld
= Attrs
.Count
> 1 ? new ListDictionary () : null;
1519 foreach (Attribute a
in Attrs
)
1522 if (ld
== null || ld
.Count
== 0)
1525 foreach (DictionaryEntry d
in ld
) {
1526 if (d
.Value
== null)
1529 foreach (Attribute collision
in (ArrayList
)d
.Value
)
1530 Report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1532 Attribute a
= (Attribute
)d
.Key
;
1533 Report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times",
1534 a
.GetSignatureForError ());
1538 public bool Contains (Type t
)
1540 return Search (t
) != null;
1545 /// Helper class for attribute verification routine.
1547 sealed class AttributeTester
1549 static PtrHashtable analyzed_types
;
1550 static PtrHashtable analyzed_types_obsolete
;
1551 static PtrHashtable analyzed_member_obsolete
;
1552 static PtrHashtable analyzed_method_excluded
;
1553 static PtrHashtable fixed_buffer_cache
;
1555 static object TRUE
= new object ();
1556 static object FALSE
= new object ();
1558 static AttributeTester ()
1563 private AttributeTester ()
1567 public static void Reset ()
1569 analyzed_types
= new PtrHashtable ();
1570 analyzed_types_obsolete
= new PtrHashtable ();
1571 analyzed_member_obsolete
= new PtrHashtable ();
1572 analyzed_method_excluded
= new PtrHashtable ();
1573 fixed_buffer_cache
= new PtrHashtable ();
1576 public enum Result
{
1583 /// Returns true if parameters of two compared methods are CLS-Compliant.
1584 /// It tests differing only in ref or out, or in array rank.
1586 public static Result
AreOverloadedMethodParamsClsCompliant (AParametersCollection pa
, AParametersCollection pb
)
1588 Type
[] types_a
= pa
.Types
;
1589 Type
[] types_b
= pb
.Types
;
1590 if (types_a
== null || types_b
== null)
1593 if (types_a
.Length
!= types_b
.Length
)
1596 Result result
= Result
.Ok
;
1597 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1598 Type aType
= types_a
[i
];
1599 Type bType
= types_b
[i
];
1601 if (aType
.IsArray
&& bType
.IsArray
) {
1602 Type a_el_type
= TypeManager
.GetElementType (aType
);
1603 Type b_el_type
= TypeManager
.GetElementType (bType
);
1604 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1605 result
= Result
.RefOutArrayError
;
1609 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1610 result
= Result
.ArrayArrayError
;
1618 const Parameter
.Modifier out_ref_mod
= (Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
1619 if ((pa
.FixedParameters
[i
].ModFlags
& out_ref_mod
) != (pb
.FixedParameters
[i
].ModFlags
& out_ref_mod
))
1620 result
= Result
.RefOutArrayError
;
1626 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1628 public static bool IsClsCompliant (Type type
)
1633 object type_compliance
= analyzed_types
[type
];
1634 if (type_compliance
!= null)
1635 return type_compliance
== TRUE
;
1637 if (type
.IsPointer
) {
1638 analyzed_types
.Add (type
, FALSE
);
1644 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1645 } else if (TypeManager
.IsNullableType (type
)) {
1646 result
= IsClsCompliant (TypeManager
.GetTypeArguments (type
) [0]);
1648 result
= AnalyzeTypeCompliance (type
);
1650 analyzed_types
.Add (type
, result
? TRUE
: FALSE
);
1655 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1657 public static IFixedBuffer
GetFixedBuffer (FieldInfo fi
)
1659 // Fixed buffer helper type is generated as value type
1660 if (TypeManager
.IsReferenceType (fi
.FieldType
))
1663 FieldBase fb
= TypeManager
.GetField (fi
);
1665 return fb
as IFixedBuffer
;
1668 if (TypeManager
.GetConstant (fi
) != null)
1671 object o
= fixed_buffer_cache
[fi
];
1673 if (TypeManager
.fixed_buffer_attr_type
== null)
1676 if (!fi
.IsDefined (TypeManager
.fixed_buffer_attr_type
, false)) {
1677 fixed_buffer_cache
.Add (fi
, FALSE
);
1681 IFixedBuffer iff
= new FixedFieldExternal (fi
);
1682 fixed_buffer_cache
.Add (fi
, iff
);
1689 return (IFixedBuffer
)o
;
1692 public static void VerifyModulesClsCompliance ()
1694 Module
[] modules
= RootNamespace
.Global
.Modules
;
1695 if (modules
== null)
1698 // The first module is generated assembly
1699 for (int i
= 1; i
< modules
.Length
; ++i
) {
1700 Module module
= modules
[i
];
1701 if (!GetClsCompliantAttributeValue (module
, null)) {
1702 Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1703 "to match the assembly", module
.Name
);
1709 public static Type
GetImportedIgnoreCaseClsType (string name
)
1711 foreach (Assembly a
in RootNamespace
.Global
.Assemblies
) {
1712 Type t
= a
.GetType (name
, false, true);
1716 if (IsClsCompliant (t
))
1722 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider
, Assembly a
)
1724 if (TypeManager
.cls_compliant_attribute_type
== null)
1727 object[] cls_attr
= attribute_provider
.GetCustomAttributes (TypeManager
.cls_compliant_attribute_type
, false);
1728 if (cls_attr
.Length
== 0) {
1732 return GetClsCompliantAttributeValue (a
, null);
1735 return ((CLSCompliantAttribute
)cls_attr
[0]).IsCompliant
;
1738 static bool AnalyzeTypeCompliance (Type type
)
1740 type
= TypeManager
.DropGenericTypeArguments (type
);
1741 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1743 return ds
.IsClsComplianceRequired ();
1746 if (TypeManager
.IsGenericParameter (type
))
1749 return GetClsCompliantAttributeValue (type
, type
.Assembly
);
1753 /// Returns instance of ObsoleteAttribute when type is obsolete
1755 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1757 object type_obsolete
= analyzed_types_obsolete
[type
];
1758 if (type_obsolete
== FALSE
)
1761 if (type_obsolete
!= null)
1762 return (ObsoleteAttribute
)type_obsolete
;
1764 ObsoleteAttribute result
= null;
1765 if (TypeManager
.HasElementType (type
)) {
1766 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1767 } else if (TypeManager
.IsGenericParameter (type
))
1768 result
= null; // TODO: throw new NotSupportedException ()
1769 else if (TypeManager
.IsGenericType (type
) && !TypeManager
.IsGenericTypeDefinition (type
)) {
1770 return GetObsoleteAttribute (TypeManager
.DropGenericTypeArguments (type
));
1772 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1774 // Type is external, we can get attribute directly
1775 if (type_ds
== null) {
1776 if (TypeManager
.obsolete_attribute_type
!= null) {
1777 object[] attribute
= type
.GetCustomAttributes (TypeManager
.obsolete_attribute_type
, false);
1778 if (attribute
.Length
== 1)
1779 result
= (ObsoleteAttribute
) attribute
[0];
1782 result
= type_ds
.GetObsoleteAttribute ();
1786 // Cannot use .Add because of corlib bootstrap
1787 analyzed_types_obsolete
[type
] = result
== null ? FALSE
: result
;
1792 /// Returns instance of ObsoleteAttribute when method is obsolete
1794 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1796 IMethodData mc
= TypeManager
.GetMethod (mb
);
1798 return mc
.GetObsoleteAttribute ();
1800 // compiler generated methods are not registered by AddMethod
1801 if (mb
.DeclaringType
is TypeBuilder
)
1804 MemberInfo mi
= TypeManager
.GetPropertyFromAccessor (mb
);
1806 return GetMemberObsoleteAttribute (mi
);
1808 mi
= TypeManager
.GetEventFromAccessor (mb
);
1810 return GetMemberObsoleteAttribute (mi
);
1812 return GetMemberObsoleteAttribute (mb
);
1816 /// Returns instance of ObsoleteAttribute when member is obsolete
1818 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1820 object type_obsolete
= analyzed_member_obsolete
[mi
];
1821 if (type_obsolete
== FALSE
)
1824 if (type_obsolete
!= null)
1825 return (ObsoleteAttribute
)type_obsolete
;
1827 if ((mi
.DeclaringType
is TypeBuilder
) || TypeManager
.IsGenericType (mi
.DeclaringType
))
1830 if (TypeManager
.obsolete_attribute_type
== null)
1833 ObsoleteAttribute oa
= System
.Attribute
.GetCustomAttribute (mi
, TypeManager
.obsolete_attribute_type
, false)
1834 as ObsoleteAttribute
;
1835 analyzed_member_obsolete
.Add (mi
, oa
== null ? FALSE
: oa
);
1840 /// Common method for Obsolete error/warning reporting.
1842 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
)
1845 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1849 if (oa
.Message
== null || oa
.Message
.Length
== 0) {
1850 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1853 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1856 public static bool IsConditionalMethodExcluded (MethodBase mb
, Location loc
)
1858 object excluded
= analyzed_method_excluded
[mb
];
1859 if (excluded
!= null)
1860 return excluded
== TRUE
? true : false;
1862 if (TypeManager
.conditional_attribute_type
== null)
1865 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (TypeManager
.conditional_attribute_type
, true)
1866 as ConditionalAttribute
[];
1867 if (attrs
.Length
== 0) {
1868 analyzed_method_excluded
.Add (mb
, FALSE
);
1872 foreach (ConditionalAttribute a
in attrs
) {
1873 if (loc
.CompilationUnit
.IsConditionalDefined (a
.ConditionString
)) {
1874 analyzed_method_excluded
.Add (mb
, FALSE
);
1879 analyzed_method_excluded
.Add (mb
, TRUE
);
1884 /// Analyzes class whether it has attribute which has ConditionalAttribute
1885 /// and its condition is not defined.
1887 public static bool IsAttributeExcluded (Type type
, Location loc
)
1892 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1894 // TODO: add caching
1895 // TODO: merge all Type bases attribute caching to one cache to save memory
1896 if (class_decl
== null && TypeManager
.conditional_attribute_type
!= null) {
1897 object[] attributes
= type
.GetCustomAttributes (TypeManager
.conditional_attribute_type
, false);
1898 foreach (ConditionalAttribute ca
in attributes
) {
1899 if (loc
.CompilationUnit
.IsConditionalDefined (ca
.ConditionString
))
1902 return attributes
.Length
> 0;
1905 return class_decl
.IsExcluded ();
1908 public static Type
GetCoClassAttribute (Type type
)
1910 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1912 if (TypeManager
.coclass_attr_type
== null)
1915 object[] o
= type
.GetCustomAttributes (TypeManager
.coclass_attr_type
, false);
1918 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1921 if (tc
.OptAttributes
== null || TypeManager
.coclass_attr_type
== null)
1924 Attribute a
= tc
.OptAttributes
.Search (TypeManager
.coclass_attr_type
);
1928 return a
.GetCoClassAttributeValue ();