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
, PredefinedAttributes pa
);
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 Arguments PosArguments
;
129 Arguments 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
, Arguments
[] args
, Location loc
, bool nameEscaped
)
154 LeftExpr
= left_expr
;
155 Identifier
= identifier
;
156 Name
= LeftExpr
== null ? identifier
: LeftExpr
+ "." + identifier
;
158 PosArguments
= args
[0];
159 NamedArguments
= 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 (NamedArgument name
)
205 Report
.Error (617, name
.Name
.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_InvalidNamedArgumentType (NamedArgument name
)
213 Report
.Error (655, name
.Name
.Location
,
214 "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
218 public static void Error_AttributeArgumentNotValid (Location loc
)
220 Report
.Error (182, loc
,
221 "An attribute argument must be a constant expression, typeof " +
222 "expression or array creation expression");
225 static void Error_TypeParameterInAttribute (Location loc
)
228 -202, loc
, "Can not use a type parameter in an attribute");
231 public void Error_MissingGuidAttribute ()
233 Report
.Error (596, Location
, "The Guid attribute must be specified with the ComImport attribute");
236 public void Error_MisusedExtensionAttribute ()
238 Report
.Error (1112, Location
, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
242 /// This is rather hack. We report many emit attribute error with same error to be compatible with
243 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
245 public void Error_AttributeEmitError (string inner
)
247 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
248 TypeManager
.CSharpName (Type
), inner
);
251 public void Error_InvalidSecurityParent ()
253 Error_AttributeEmitError ("it is attached to invalid parent");
262 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
264 return expr
.ResolveAsTypeTerminal (ec
, silent
);
267 Type
ResolvePossibleAttributeType (string name
, bool silent
, ref bool is_attr
)
269 IResolveContext rc
= new AttributeResolveContext (Owner
.ResolveContext
);
272 if (LeftExpr
== null) {
273 te
= ResolveAsTypeTerminal (new SimpleName (name
, Location
), rc
, silent
);
275 te
= ResolveAsTypeTerminal (new MemberAccess (LeftExpr
, name
), rc
, silent
);
282 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
284 } else if (!silent
) {
285 Report
.SymbolRelatedToPreviousError (t
);
286 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
292 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
294 void ResolveAttributeType ()
296 bool t1_is_attr
= false;
297 Type t1
= ResolvePossibleAttributeType (Identifier
, true, ref t1_is_attr
);
299 bool t2_is_attr
= false;
300 Type t2
= nameEscaped
? null :
301 ResolvePossibleAttributeType (Identifier
+ "Attribute", true, ref t2_is_attr
);
303 if (t1_is_attr
&& t2_is_attr
) {
304 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " +
305 "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
306 resolve_error
= true;
320 if (t1
== null && t2
== null)
321 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
323 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
325 ResolvePossibleAttributeType (Identifier
+ "Attribute", false, ref t2_is_attr
);
327 resolve_error
= true;
330 public virtual Type
ResolveType ()
332 if (Type
== null && !resolve_error
)
333 ResolveAttributeType ();
337 public override string GetSignatureForError ()
340 return TypeManager
.CSharpName (Type
);
342 return LeftExpr
== null ? Identifier
: LeftExpr
.GetSignatureForError () + "." + Identifier
;
345 public bool HasSecurityAttribute
{
347 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Security
;
348 return pa
.IsDefined
&& TypeManager
.IsSubclassOf (type
, pa
.Type
);
352 public bool IsValidSecurityAttribute ()
354 return HasSecurityAttribute
&& IsSecurityActionValid (false);
357 static bool IsValidArgumentType (Type t
)
360 t
= TypeManager
.GetElementType (t
);
362 return t
== TypeManager
.string_type
||
363 TypeManager
.IsPrimitiveType (t
) ||
364 TypeManager
.IsEnumType (t
) ||
365 t
== TypeManager
.object_type
||
366 t
== TypeManager
.type_type
;
369 void ApplyModuleCharSet ()
371 if (Type
!= PredefinedAttributes
.Get
.DllImport
)
374 if (!RootContext
.ToplevelTypes
.HasDefaultCharSet
)
377 const string CharSetEnumMember
= "CharSet";
378 if (NamedArguments
== null) {
379 NamedArguments
= new Arguments (1);
381 foreach (NamedArgument a
in NamedArguments
) {
382 if (a
.Name
.Value
== CharSetEnumMember
)
387 NamedArguments
.Add (new NamedArgument (new LocatedToken (loc
, CharSetEnumMember
),
388 Constant
.CreateConstant (typeof (CharSet
), RootContext
.ToplevelTypes
.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 PosArguments
.Resolve (ec
);
481 MethodGroupExpr mg
= MemberLookupFinal (ec
, ec
.ContainerType
,
482 Type
, ConstructorInfo
.ConstructorName
, MemberTypes
.Constructor
,
483 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
484 Location
) as MethodGroupExpr
;
487 throw new NotImplementedException ();
489 mg
= mg
.OverloadResolve (ec
, ref PosArguments
, false, Location
);
493 ConstructorInfo constructor
= (ConstructorInfo
)mg
;
494 if (PosArguments
== null) {
495 pos_values
= EmptyObject
;
499 AParametersCollection pd
= TypeManager
.GetParameterData (constructor
);
501 if (!PosArguments
.GetAttributableValue (ec
, out pos_values
))
504 // Here we do the checks which should be done by corlib or by runtime.
505 // However Zoltan doesn't like it and every Mono compiler has to do it again.
506 PredefinedAttributes pa
= PredefinedAttributes
.Get
;
507 if (Type
== pa
.Guid
) {
509 new Guid ((string)pos_values
[0]);
511 catch (Exception e
) {
512 Error_AttributeEmitError (e
.Message
);
517 if (Type
== pa
.AttributeUsage
&& (int)pos_values
[0] == 0) {
518 Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
522 if (Type
== pa
.IndexerName
|| Type
== pa
.Conditional
) {
523 string v
= pos_values
[0] as string;
524 if (!Tokenizer
.IsValidIdentifier (v
) || Tokenizer
.IsKeyword (v
)) {
525 Report
.Error (633, PosArguments
[0].Expr
.Location
,
526 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
531 if (Type
== pa
.MethodImpl
&& pos_values
.Length
== 1 &&
532 pd
.Types
[0] == TypeManager
.short_type
&&
533 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
534 Error_AttributeEmitError ("Incorrect argument value.");
541 protected virtual bool ResolveNamedArguments (EmitContext ec
)
543 int named_arg_count
= NamedArguments
.Count
;
545 ArrayList field_infos
= new ArrayList (named_arg_count
);
546 ArrayList prop_infos
= new ArrayList (named_arg_count
);
547 ArrayList field_values
= new ArrayList (named_arg_count
);
548 ArrayList prop_values
= new ArrayList (named_arg_count
);
550 ArrayList seen_names
= new ArrayList (named_arg_count
);
552 foreach (NamedArgument a
in NamedArguments
) {
553 string name
= a
.Name
.Value
;
554 if (seen_names
.Contains (name
)) {
555 Report
.Error (643, a
.Name
.Location
, "Duplicate named attribute `{0}' argument", name
);
559 seen_names
.Add (name
);
563 Expression member
= Expression
.MemberLookup (
564 ec
.ContainerType
, Type
, name
,
566 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.Static
,
569 if (member
== null) {
570 member
= Expression
.MemberLookup (ec
.ContainerType
, Type
, name
,
571 MemberTypes
.All
, BindingFlags
.NonPublic
| BindingFlags
.Instance
| BindingFlags
.Static
,
574 if (member
!= null) {
575 Report
.SymbolRelatedToPreviousError (member
.Type
);
576 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError ());
582 Expression
.Error_TypeDoesNotContainDefinition (Location
, Type
, name
);
586 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
587 Error_InvalidNamedArgument (a
);
591 if (a
.Expr
is TypeParameterExpr
){
592 Error_TypeParameterInAttribute (Location
);
596 ObsoleteAttribute obsolete_attr
;
598 if (member
is PropertyExpr
) {
599 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
601 if (!pi
.CanWrite
|| !pi
.CanRead
|| pi
.GetGetMethod ().IsStatic
) {
602 Report
.SymbolRelatedToPreviousError (pi
);
603 Error_InvalidNamedArgument (a
);
607 if (!IsValidArgumentType (member
.Type
)) {
608 Report
.SymbolRelatedToPreviousError (pi
);
609 Error_InvalidNamedArgumentType (a
);
614 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
617 PropertyBase pb
= TypeManager
.GetProperty (pi
);
619 obsolete_attr
= pb
.GetObsoleteAttribute ();
621 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
623 prop_values
.Add (value);
627 FieldInfo fi
= ((FieldExpr
) member
).FieldInfo
;
629 if (fi
.IsInitOnly
|| fi
.IsStatic
) {
630 Error_InvalidNamedArgument (a
);
634 if (!IsValidArgumentType (member
.Type
)) {
635 Report
.SymbolRelatedToPreviousError (fi
);
636 Error_InvalidNamedArgumentType (a
);
641 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
644 FieldBase fb
= TypeManager
.GetField (fi
);
646 obsolete_attr
= fb
.GetObsoleteAttribute ();
648 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
650 field_values
.Add (value);
651 field_infos
.Add (fi
);
654 if (obsolete_attr
!= null && !Owner
.ResolveContext
.IsInObsoleteScope
)
655 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
);
658 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
659 field_info_arr
= new FieldInfo
[field_infos
.Count
];
660 field_values_arr
= new object [field_values
.Count
];
661 prop_values_arr
= new object [prop_values
.Count
];
663 field_infos
.CopyTo (field_info_arr
, 0);
664 field_values
.CopyTo (field_values_arr
, 0);
666 prop_values
.CopyTo (prop_values_arr
, 0);
667 prop_infos
.CopyTo (prop_info_arr
, 0);
673 /// Get a string containing a list of valid targets for the attribute 'attr'
675 public string GetValidTargets ()
677 StringBuilder sb
= new StringBuilder ();
678 AttributeTargets targets
= GetAttributeUsage (Type
).ValidOn
;
680 if ((targets
& AttributeTargets
.Assembly
) != 0)
681 sb
.Append ("assembly, ");
683 if ((targets
& AttributeTargets
.Module
) != 0)
684 sb
.Append ("module, ");
686 if ((targets
& AttributeTargets
.Class
) != 0)
687 sb
.Append ("class, ");
689 if ((targets
& AttributeTargets
.Struct
) != 0)
690 sb
.Append ("struct, ");
692 if ((targets
& AttributeTargets
.Enum
) != 0)
693 sb
.Append ("enum, ");
695 if ((targets
& AttributeTargets
.Constructor
) != 0)
696 sb
.Append ("constructor, ");
698 if ((targets
& AttributeTargets
.Method
) != 0)
699 sb
.Append ("method, ");
701 if ((targets
& AttributeTargets
.Property
) != 0)
702 sb
.Append ("property, indexer, ");
704 if ((targets
& AttributeTargets
.Field
) != 0)
705 sb
.Append ("field, ");
707 if ((targets
& AttributeTargets
.Event
) != 0)
708 sb
.Append ("event, ");
710 if ((targets
& AttributeTargets
.Interface
) != 0)
711 sb
.Append ("interface, ");
713 if ((targets
& AttributeTargets
.Parameter
) != 0)
714 sb
.Append ("parameter, ");
716 if ((targets
& AttributeTargets
.Delegate
) != 0)
717 sb
.Append ("delegate, ");
719 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
720 sb
.Append ("return, ");
723 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
724 sb
.Append ("type parameter, ");
726 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
730 /// Returns AttributeUsage attribute based on types hierarchy
732 static AttributeUsageAttribute
GetAttributeUsage (Type type
)
734 AttributeUsageAttribute ua
= usage_attr_cache
[type
] as AttributeUsageAttribute
;
738 Class attr_class
= TypeManager
.LookupClass (type
);
739 PredefinedAttribute pa
= PredefinedAttributes
.Get
.AttributeUsage
;
741 if (attr_class
== null) {
743 return new AttributeUsageAttribute (0);
745 object[] usage_attr
= type
.GetCustomAttributes (pa
.Type
, true);
746 ua
= (AttributeUsageAttribute
)usage_attr
[0];
747 usage_attr_cache
.Add (type
, ua
);
752 if (attr_class
.OptAttributes
!= null)
753 a
= attr_class
.OptAttributes
.Search (pa
);
756 if (attr_class
.TypeBuilder
.BaseType
!= TypeManager
.attribute_type
)
757 ua
= GetAttributeUsage (attr_class
.TypeBuilder
.BaseType
);
759 ua
= DefaultUsageAttribute
;
761 ua
= a
.GetAttributeUsageAttribute ();
764 usage_attr_cache
.Add (type
, ua
);
768 AttributeUsageAttribute
GetAttributeUsageAttribute ()
770 if (pos_values
== null)
771 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
772 // But because a lot of attribute class code must be rewritten will be better to wait...
776 return DefaultUsageAttribute
;
778 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
780 object field
= GetPropertyValue ("AllowMultiple");
782 usage_attribute
.AllowMultiple
= (bool)field
;
784 field
= GetPropertyValue ("Inherited");
786 usage_attribute
.Inherited
= (bool)field
;
788 return usage_attribute
;
792 /// Returns custom name of indexer
794 public string GetIndexerAttributeValue ()
796 if (pos_values
== null)
797 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
798 // But because a lot of attribute class code must be rewritten will be better to wait...
804 return pos_values
[0] as string;
808 /// Returns condition of ConditionalAttribute
810 public string GetConditionalAttributeValue ()
812 if (pos_values
== null)
813 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
814 // But because a lot of attribute class code must be rewritten will be better to wait...
820 return (string)pos_values
[0];
824 /// Creates the instance of ObsoleteAttribute from this attribute instance
826 public ObsoleteAttribute
GetObsoleteAttribute ()
828 if (pos_values
== null)
829 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
830 // But because a lot of attribute class code must be rewritten will be better to wait...
836 if (pos_values
== null || pos_values
.Length
== 0)
837 return new ObsoleteAttribute ();
839 if (pos_values
.Length
== 1)
840 return new ObsoleteAttribute ((string)pos_values
[0]);
842 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
846 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
847 /// before ApplyAttribute. We need to resolve the arguments.
848 /// This situation occurs when class deps is differs from Emit order.
850 public bool GetClsCompliantAttributeValue ()
852 if (pos_values
== null)
853 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
854 // But because a lot of attribute class code must be rewritten will be better to wait...
860 return (bool)pos_values
[0];
863 public Type
GetCoClassAttributeValue ()
865 if (pos_values
== null)
871 return (Type
)pos_values
[0];
874 public bool CheckTarget ()
876 string[] valid_targets
= Owner
.ValidAttributeTargets
;
877 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
878 Target
= Owner
.AttributeTargets
;
882 // TODO: we can skip the first item
883 if (((IList
) valid_targets
).Contains (ExplicitTarget
)) {
884 switch (ExplicitTarget
) {
885 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
886 case "param": Target
= AttributeTargets
.Parameter
; return true;
887 case "field": Target
= AttributeTargets
.Field
; return true;
888 case "method": Target
= AttributeTargets
.Method
; return true;
889 case "property": Target
= AttributeTargets
.Property
; return true;
891 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
894 StringBuilder sb
= new StringBuilder ();
895 foreach (string s
in valid_targets
) {
899 sb
.Remove (sb
.Length
- 2, 2);
900 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
901 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
906 /// Tests permitted SecurityAction for assembly or other types
908 protected virtual bool IsSecurityActionValid (bool for_assembly
)
910 SecurityAction action
= GetSecurityActionValue ();
913 case SecurityAction
.Demand
:
914 case SecurityAction
.Assert
:
915 case SecurityAction
.Deny
:
916 case SecurityAction
.PermitOnly
:
917 case SecurityAction
.LinkDemand
:
918 case SecurityAction
.InheritanceDemand
:
923 case SecurityAction
.RequestMinimum
:
924 case SecurityAction
.RequestOptional
:
925 case SecurityAction
.RequestRefuse
:
931 Error_AttributeEmitError ("SecurityAction is out of range");
935 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
939 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
941 return (SecurityAction
)pos_values
[0];
945 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
947 /// <returns></returns>
948 public void ExtractSecurityPermissionSet (ListDictionary permissions
)
950 Type orig_assembly_type
= null;
952 if (TypeManager
.LookupDeclSpace (Type
) != null) {
953 if (!RootContext
.StdLib
) {
954 orig_assembly_type
= Type
.GetType (Type
.FullName
);
956 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
957 if (orig_version_path
== null) {
958 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
962 if (orig_sec_assembly
== null) {
963 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
964 orig_sec_assembly
= Assembly
.LoadFile (file
);
967 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
968 if (orig_assembly_type
== null) {
969 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
970 "was not found in previous version of assembly");
976 SecurityAttribute sa
;
977 // For all non-selfreferencing security attributes we can avoid all hacks
978 if (orig_assembly_type
== null) {
979 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
981 if (prop_info_arr
!= null) {
982 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
983 PropertyInfo pi
= prop_info_arr
[i
];
984 pi
.SetValue (sa
, prop_values_arr
[i
], null);
988 // HACK: All security attributes have same ctor syntax
989 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
991 // All types are from newly created assembly but for invocation with old one we need to convert them
992 if (prop_info_arr
!= null) {
993 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
994 PropertyInfo emited_pi
= prop_info_arr
[i
];
995 // FIXME: We are missing return type filter
996 // TODO: pi can be null
997 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
);
999 object old_instance
= TypeManager
.IsEnumType (pi
.PropertyType
) ?
1000 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
1001 prop_values_arr
[i
];
1003 pi
.SetValue (sa
, old_instance
, null);
1009 perm
= sa
.CreatePermission ();
1010 SecurityAction action
= GetSecurityActionValue ();
1012 // IS is correct because for corlib we are using an instance from old corlib
1013 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
1015 case SecurityAction
.Demand
:
1016 action
= (SecurityAction
)13;
1018 case SecurityAction
.LinkDemand
:
1019 action
= (SecurityAction
)14;
1021 case SecurityAction
.InheritanceDemand
:
1022 action
= (SecurityAction
)15;
1027 PermissionSet ps
= (PermissionSet
)permissions
[action
];
1029 if (sa
is PermissionSetAttribute
)
1030 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
1032 ps
= new PermissionSet (PermissionState
.None
);
1034 permissions
.Add (action
, ps
);
1035 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
1036 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
1037 permissions
[action
] = ps
;
1039 ps
.AddPermission (perm
);
1042 public object GetPropertyValue (string name
)
1044 if (prop_info_arr
== null)
1047 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1048 if (prop_info_arr
[i
].Name
== name
)
1049 return prop_values_arr
[i
];
1056 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1057 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1058 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1061 public UnmanagedMarshal
GetMarshal (Attributable attr
)
1063 UnmanagedType UnmanagedType
;
1064 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (UnmanagedType
))
1065 UnmanagedType
= (UnmanagedType
) System
.Enum
.ToObject (typeof (UnmanagedType
), pos_values
[0]);
1067 UnmanagedType
= (UnmanagedType
) pos_values
[0];
1069 object value = GetFieldValue ("SizeParamIndex");
1070 if (value != null && UnmanagedType
!= UnmanagedType
.LPArray
) {
1071 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1075 object o
= GetFieldValue ("ArraySubType");
1076 UnmanagedType array_sub_type
= o
== null ? (UnmanagedType
) 0x50 /* NATIVE_MAX */ : (UnmanagedType
) o
;
1078 switch (UnmanagedType
) {
1079 case UnmanagedType
.CustomMarshaler
: {
1080 MethodInfo define_custom
= typeof (UnmanagedMarshal
).GetMethod ("DefineCustom",
1081 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1082 if (define_custom
== null) {
1083 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1087 object [] args
= new object [4];
1088 args
[0] = GetFieldValue ("MarshalTypeRef");
1089 args
[1] = GetFieldValue ("MarshalCookie");
1090 args
[2] = GetFieldValue ("MarshalType");
1091 args
[3] = Guid
.Empty
;
1092 return (UnmanagedMarshal
) define_custom
.Invoke (null, args
);
1094 case UnmanagedType
.LPArray
: {
1095 object size_const
= GetFieldValue ("SizeConst");
1096 object size_param_index
= GetFieldValue ("SizeParamIndex");
1098 if ((size_const
!= null) || (size_param_index
!= null)) {
1099 MethodInfo define_array
= typeof (UnmanagedMarshal
).GetMethod ("DefineLPArrayInternal",
1100 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1101 if (define_array
== null) {
1102 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1106 object [] args
= new object [3];
1107 args
[0] = array_sub_type
;
1108 args
[1] = size_const
== null ? -1 : size_const
;
1109 args
[2] = size_param_index
== null ? -1 : size_param_index
;
1110 return (UnmanagedMarshal
) define_array
.Invoke (null, args
);
1113 return UnmanagedMarshal
.DefineLPArray (array_sub_type
);
1115 case UnmanagedType
.SafeArray
:
1116 return UnmanagedMarshal
.DefineSafeArray (array_sub_type
);
1118 case UnmanagedType
.ByValArray
:
1119 FieldBase fm
= attr
as FieldBase
;
1121 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1124 return UnmanagedMarshal
.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1126 case UnmanagedType
.ByValTStr
:
1127 return UnmanagedMarshal
.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1130 return UnmanagedMarshal
.DefineUnmanagedMarshal (UnmanagedType
);
1134 object GetFieldValue (string name
)
1137 if (field_info_arr
== null)
1140 foreach (FieldInfo fi
in field_info_arr
) {
1141 if (fi
.Name
== name
)
1142 return GetValue (field_values_arr
[i
]);
1148 static object GetValue (object value)
1150 if (value is EnumConstant
)
1151 return ((EnumConstant
) value).GetValue ();
1158 public CharSet
GetCharSetValue ()
1160 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1163 public bool HasField (string fieldName
)
1165 if (field_info_arr
== null)
1168 foreach (FieldInfo fi
in field_info_arr
) {
1169 if (fi
.Name
== fieldName
)
1176 public bool IsInternalMethodImplAttribute
{
1178 if (Type
!= PredefinedAttributes
.Get
.MethodImpl
)
1181 MethodImplOptions options
;
1182 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1183 options
= (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1185 options
= (MethodImplOptions
)pos_values
[0];
1187 return (options
& MethodImplOptions
.InternalCall
) != 0;
1191 public LayoutKind
GetLayoutKindValue ()
1193 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1194 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1196 return (LayoutKind
)pos_values
[0];
1199 public object GetParameterDefaultValue ()
1201 return pos_values
[0];
1204 public override bool Equals (object obj
)
1206 Attribute a
= obj
as Attribute
;
1210 return Type
== a
.Type
&& Target
== a
.Target
;
1213 public override int GetHashCode ()
1215 return base.GetHashCode ();
1219 /// Emit attribute for Attributable symbol
1221 public void Emit (ListDictionary allEmitted
)
1223 CustomAttributeBuilder cb
= Resolve ();
1227 AttributeUsageAttribute usage_attr
= GetAttributeUsage (Type
);
1228 if ((usage_attr
.ValidOn
& Target
) == 0) {
1229 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1230 "It is valid on `{1}' declarations only",
1231 GetSignatureForError (), GetValidTargets ());
1236 foreach (Attributable owner
in owners
)
1237 owner
.ApplyAttributeBuilder (this, cb
, PredefinedAttributes
.Get
);
1239 catch (Exception e
) {
1240 Error_AttributeEmitError (e
.Message
);
1244 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1245 if (allEmitted
.Contains (this)) {
1246 ArrayList a
= allEmitted
[this] as ArrayList
;
1248 a
= new ArrayList (2);
1249 allEmitted
[this] = a
;
1253 allEmitted
.Add (this, null);
1257 if (!RootContext
.VerifyClsCompliance
)
1260 // Here we are testing attribute arguments for array usage (error 3016)
1261 if (Owner
.IsClsComplianceRequired ()) {
1262 if (PosArguments
!= null)
1263 PosArguments
.CheckArrayAsAttribute ();
1265 if (NamedArguments
== null)
1268 NamedArguments
.CheckArrayAsAttribute ();
1272 private Expression
GetValue ()
1274 if (PosArguments
== null || PosArguments
.Count
< 1)
1277 return PosArguments
[0].Expr
;
1280 public string GetString ()
1282 Expression e
= GetValue ();
1283 if (e
is StringConstant
)
1284 return ((StringConstant
)e
).Value
;
1288 public bool GetBoolean ()
1290 Expression e
= GetValue ();
1291 if (e
is BoolConstant
)
1292 return ((BoolConstant
)e
).Value
;
1296 public Type
GetArgumentType ()
1298 TypeOf e
= GetValue () as TypeOf
;
1301 return e
.TypeArgument
;
1304 public override Expression
CreateExpressionTree (EmitContext ec
)
1306 throw new NotSupportedException ("ET");
1309 public override Expression
DoResolve (EmitContext ec
)
1311 throw new NotImplementedException ();
1314 public override void Emit (EmitContext ec
)
1316 throw new NotImplementedException ();
1322 /// For global attributes (assembly, module) we need special handling.
1323 /// Attributes can be located in the several files
1325 public class GlobalAttribute
: Attribute
1327 public readonly NamespaceEntry ns
;
1329 public GlobalAttribute (NamespaceEntry ns
, string target
,
1330 Expression left_expr
, string identifier
, Arguments
[] args
, Location loc
, bool nameEscaped
):
1331 base (target
, left_expr
, identifier
, args
, loc
, nameEscaped
)
1334 this.owners
= new Attributable
[1];
1337 public override void AttachTo (Attributable owner
)
1339 if (ExplicitTarget
== "assembly") {
1340 owners
[0] = CodeGen
.Assembly
;
1343 if (ExplicitTarget
== "module") {
1344 owners
[0] = RootContext
.ToplevelTypes
;
1347 throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget
);
1352 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1353 // each time a new file is parsed. However, we need to use the NamespaceEntry
1354 // in effect where the attribute was used. Since code elsewhere cannot assume
1355 // that the NamespaceEntry is right, just overwrite it.
1357 // Precondition: RootContext.ToplevelTypes == null
1359 if (RootContext
.ToplevelTypes
.NamespaceEntry
!= null)
1360 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1362 RootContext
.ToplevelTypes
.NamespaceEntry
= ns
;
1365 protected override bool IsSecurityActionValid (bool for_assembly
)
1367 return base.IsSecurityActionValid (true);
1372 RootContext
.ToplevelTypes
.NamespaceEntry
= null;
1375 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
1379 return base.ResolveAsTypeTerminal (expr
, ec
, silent
);
1386 protected override ConstructorInfo
ResolveConstructor (EmitContext ec
)
1390 return base.ResolveConstructor (ec
);
1397 protected override bool ResolveNamedArguments (EmitContext ec
)
1401 return base.ResolveNamedArguments (ec
);
1409 public class Attributes
{
1410 public readonly ArrayList Attrs
;
1412 public Attributes (Attribute a
)
1414 Attrs
= new ArrayList ();
1418 public Attributes (ArrayList attrs
)
1423 public void AddAttributes (ArrayList attrs
)
1425 Attrs
.AddRange (attrs
);
1428 public void AttachTo (Attributable attributable
)
1430 foreach (Attribute a
in Attrs
)
1431 a
.AttachTo (attributable
);
1434 public Attributes
Clone ()
1436 ArrayList al
= new ArrayList (Attrs
.Count
);
1437 foreach (Attribute a
in Attrs
)
1438 al
.Add (a
.Clone ());
1440 return new Attributes (al
);
1444 /// Checks whether attribute target is valid for the current element
1446 public bool CheckTargets ()
1448 foreach (Attribute a
in Attrs
) {
1449 if (!a
.CheckTarget ())
1455 public Attribute
Search (PredefinedAttribute t
)
1457 foreach (Attribute a
in Attrs
) {
1458 if (a
.ResolveType () == t
)
1465 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1467 public Attribute
[] SearchMulti (PredefinedAttribute t
)
1469 ArrayList ar
= null;
1471 foreach (Attribute a
in Attrs
) {
1472 if (a
.ResolveType () == t
) {
1474 ar
= new ArrayList ();
1479 return ar
== null ? null : ar
.ToArray (typeof (Attribute
)) as Attribute
[];
1486 ListDictionary ld
= Attrs
.Count
> 1 ? new ListDictionary () : null;
1488 foreach (Attribute a
in Attrs
)
1491 if (ld
== null || ld
.Count
== 0)
1494 foreach (DictionaryEntry d
in ld
) {
1495 if (d
.Value
== null)
1498 foreach (Attribute collision
in (ArrayList
)d
.Value
)
1499 Report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1501 Attribute a
= (Attribute
)d
.Key
;
1502 Report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times",
1503 a
.GetSignatureForError ());
1507 public bool Contains (PredefinedAttribute t
)
1509 return Search (t
) != null;
1514 /// Helper class for attribute verification routine.
1516 sealed class AttributeTester
1518 static PtrHashtable analyzed_types
;
1519 static PtrHashtable analyzed_types_obsolete
;
1520 static PtrHashtable analyzed_member_obsolete
;
1521 static PtrHashtable analyzed_method_excluded
;
1522 static PtrHashtable fixed_buffer_cache
;
1524 static object TRUE
= new object ();
1525 static object FALSE
= new object ();
1527 static AttributeTester ()
1532 private AttributeTester ()
1536 public static void Reset ()
1538 analyzed_types
= new PtrHashtable ();
1539 analyzed_types_obsolete
= new PtrHashtable ();
1540 analyzed_member_obsolete
= new PtrHashtable ();
1541 analyzed_method_excluded
= new PtrHashtable ();
1542 fixed_buffer_cache
= new PtrHashtable ();
1545 public enum Result
{
1552 /// Returns true if parameters of two compared methods are CLS-Compliant.
1553 /// It tests differing only in ref or out, or in array rank.
1555 public static Result
AreOverloadedMethodParamsClsCompliant (AParametersCollection pa
, AParametersCollection pb
)
1557 Type
[] types_a
= pa
.Types
;
1558 Type
[] types_b
= pb
.Types
;
1559 if (types_a
== null || types_b
== null)
1562 if (types_a
.Length
!= types_b
.Length
)
1565 Result result
= Result
.Ok
;
1566 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1567 Type aType
= types_a
[i
];
1568 Type bType
= types_b
[i
];
1570 if (aType
.IsArray
&& bType
.IsArray
) {
1571 Type a_el_type
= TypeManager
.GetElementType (aType
);
1572 Type b_el_type
= TypeManager
.GetElementType (bType
);
1573 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1574 result
= Result
.RefOutArrayError
;
1578 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1579 result
= Result
.ArrayArrayError
;
1587 const Parameter
.Modifier out_ref_mod
= (Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
1588 if ((pa
.FixedParameters
[i
].ModFlags
& out_ref_mod
) != (pb
.FixedParameters
[i
].ModFlags
& out_ref_mod
))
1589 result
= Result
.RefOutArrayError
;
1595 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1597 public static bool IsClsCompliant (Type type
)
1602 object type_compliance
= analyzed_types
[type
];
1603 if (type_compliance
!= null)
1604 return type_compliance
== TRUE
;
1606 if (type
.IsPointer
) {
1607 analyzed_types
.Add (type
, FALSE
);
1613 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1614 } else if (TypeManager
.IsNullableType (type
)) {
1615 result
= IsClsCompliant (TypeManager
.GetTypeArguments (type
) [0]);
1617 result
= AnalyzeTypeCompliance (type
);
1619 analyzed_types
.Add (type
, result
? TRUE
: FALSE
);
1624 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1626 public static IFixedBuffer
GetFixedBuffer (FieldInfo fi
)
1628 // Fixed buffer helper type is generated as value type
1629 if (TypeManager
.IsReferenceType (fi
.FieldType
))
1632 FieldBase fb
= TypeManager
.GetField (fi
);
1634 return fb
as IFixedBuffer
;
1637 if (TypeManager
.GetConstant (fi
) != null)
1640 object o
= fixed_buffer_cache
[fi
];
1642 PredefinedAttribute pa
= PredefinedAttributes
.Get
.FixedBuffer
;
1646 if (!fi
.IsDefined (pa
.Type
, false)) {
1647 fixed_buffer_cache
.Add (fi
, FALSE
);
1651 IFixedBuffer iff
= new FixedFieldExternal (fi
);
1652 fixed_buffer_cache
.Add (fi
, iff
);
1659 return (IFixedBuffer
)o
;
1662 public static void VerifyModulesClsCompliance ()
1664 Module
[] modules
= GlobalRootNamespace
.Instance
.Modules
;
1665 if (modules
== null)
1668 // The first module is generated assembly
1669 for (int i
= 1; i
< modules
.Length
; ++i
) {
1670 Module module
= modules
[i
];
1671 if (!GetClsCompliantAttributeValue (module
, null)) {
1672 Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1673 "to match the assembly", module
.Name
);
1679 public static Type
GetImportedIgnoreCaseClsType (string name
)
1681 foreach (Assembly a
in GlobalRootNamespace
.Instance
.Assemblies
) {
1682 Type t
= a
.GetType (name
, false, true);
1686 if (IsClsCompliant (t
))
1692 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider
, Assembly a
)
1694 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CLSCompliant
;
1698 object[] cls_attr
= attribute_provider
.GetCustomAttributes (pa
.Type
, false);
1699 if (cls_attr
.Length
== 0) {
1703 return GetClsCompliantAttributeValue (a
, null);
1706 return ((CLSCompliantAttribute
)cls_attr
[0]).IsCompliant
;
1709 static bool AnalyzeTypeCompliance (Type type
)
1711 type
= TypeManager
.DropGenericTypeArguments (type
);
1712 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1714 return ds
.IsClsComplianceRequired ();
1717 if (TypeManager
.IsGenericParameter (type
))
1720 return GetClsCompliantAttributeValue (type
, type
.Assembly
);
1724 /// Returns instance of ObsoleteAttribute when type is obsolete
1726 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1728 object type_obsolete
= analyzed_types_obsolete
[type
];
1729 if (type_obsolete
== FALSE
)
1732 if (type_obsolete
!= null)
1733 return (ObsoleteAttribute
)type_obsolete
;
1735 ObsoleteAttribute result
= null;
1736 if (TypeManager
.HasElementType (type
)) {
1737 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1738 } else if (TypeManager
.IsGenericParameter (type
))
1739 result
= null; // TODO: throw new NotSupportedException ()
1740 else if (TypeManager
.IsGenericType (type
) && !TypeManager
.IsGenericTypeDefinition (type
)) {
1741 return GetObsoleteAttribute (TypeManager
.DropGenericTypeArguments (type
));
1743 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1745 // Type is external, we can get attribute directly
1746 if (type_ds
== null) {
1747 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1749 object[] attribute
= type
.GetCustomAttributes (pa
.Type
, false);
1750 if (attribute
.Length
== 1)
1751 result
= (ObsoleteAttribute
) attribute
[0];
1754 result
= type_ds
.GetObsoleteAttribute ();
1758 // Cannot use .Add because of corlib bootstrap
1759 analyzed_types_obsolete
[type
] = result
== null ? FALSE
: result
;
1764 /// Returns instance of ObsoleteAttribute when method is obsolete
1766 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1768 IMethodData mc
= TypeManager
.GetMethod (mb
);
1770 return mc
.GetObsoleteAttribute ();
1772 // compiler generated methods are not registered by AddMethod
1773 if (mb
.DeclaringType
is TypeBuilder
)
1776 MemberInfo mi
= TypeManager
.GetPropertyFromAccessor (mb
);
1778 return GetMemberObsoleteAttribute (mi
);
1780 mi
= TypeManager
.GetEventFromAccessor (mb
);
1782 return GetMemberObsoleteAttribute (mi
);
1784 return GetMemberObsoleteAttribute (mb
);
1788 /// Returns instance of ObsoleteAttribute when member is obsolete
1790 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1792 object type_obsolete
= analyzed_member_obsolete
[mi
];
1793 if (type_obsolete
== FALSE
)
1796 if (type_obsolete
!= null)
1797 return (ObsoleteAttribute
)type_obsolete
;
1799 if ((mi
.DeclaringType
is TypeBuilder
) || TypeManager
.IsGenericType (mi
.DeclaringType
))
1802 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1806 ObsoleteAttribute oa
= System
.Attribute
.GetCustomAttribute (mi
, pa
.Type
, false)
1807 as ObsoleteAttribute
;
1808 analyzed_member_obsolete
.Add (mi
, oa
== null ? FALSE
: oa
);
1813 /// Common method for Obsolete error/warning reporting.
1815 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
)
1818 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1822 if (oa
.Message
== null || oa
.Message
.Length
== 0) {
1823 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1826 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1829 public static bool IsConditionalMethodExcluded (MethodBase mb
, Location loc
)
1831 object excluded
= analyzed_method_excluded
[mb
];
1832 if (excluded
!= null)
1833 return excluded
== TRUE
? true : false;
1835 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1839 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (pa
.Type
, true)
1840 as ConditionalAttribute
[];
1841 if (attrs
.Length
== 0) {
1842 analyzed_method_excluded
.Add (mb
, FALSE
);
1846 foreach (ConditionalAttribute a
in attrs
) {
1847 if (loc
.CompilationUnit
.IsConditionalDefined (a
.ConditionString
)) {
1848 analyzed_method_excluded
.Add (mb
, FALSE
);
1853 analyzed_method_excluded
.Add (mb
, TRUE
);
1858 /// Analyzes class whether it has attribute which has ConditionalAttribute
1859 /// and its condition is not defined.
1861 public static bool IsAttributeExcluded (Type type
, Location loc
)
1866 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1868 // TODO: add caching
1869 // TODO: merge all Type bases attribute caching to one cache to save memory
1870 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1871 if (class_decl
== null && pa
.IsDefined
) {
1872 object[] attributes
= type
.GetCustomAttributes (pa
.Type
, false);
1873 foreach (ConditionalAttribute ca
in attributes
) {
1874 if (loc
.CompilationUnit
.IsConditionalDefined (ca
.ConditionString
))
1877 return attributes
.Length
> 0;
1880 return class_decl
.IsExcluded ();
1883 public static Type
GetCoClassAttribute (Type type
)
1885 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1886 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CoClass
;
1891 object[] o
= type
.GetCustomAttributes (pa
.Type
, false);
1894 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1897 if (tc
.OptAttributes
== null)
1900 Attribute a
= tc
.OptAttributes
.Search (pa
);
1904 return a
.GetCoClassAttributeValue ();
1908 public class PredefinedAttributes
1911 public readonly PredefinedAttribute ParamArray
;
1912 public readonly PredefinedAttribute Out
;
1915 public readonly PredefinedAttribute Obsolete
;
1916 public readonly PredefinedAttribute DllImport
;
1917 public readonly PredefinedAttribute MethodImpl
;
1918 public readonly PredefinedAttribute MarshalAs
;
1919 public readonly PredefinedAttribute In
;
1920 public readonly PredefinedAttribute IndexerName
;
1921 public readonly PredefinedAttribute Conditional
;
1922 public readonly PredefinedAttribute CLSCompliant
;
1923 public readonly PredefinedAttribute Security
;
1924 public readonly PredefinedAttribute Required
;
1925 public readonly PredefinedAttribute Guid
;
1926 public readonly PredefinedAttribute AssemblyCulture
;
1927 public readonly PredefinedAttribute AssemblyVersion
;
1928 public readonly PredefinedAttribute ComImport
;
1929 public readonly PredefinedAttribute CoClass
;
1930 public readonly PredefinedAttribute AttributeUsage
;
1931 public readonly PredefinedAttribute DefaultParameterValue
;
1932 public readonly PredefinedAttribute OptionalParameter
;
1935 public readonly PredefinedAttribute DefaultCharset
;
1936 public readonly PredefinedAttribute TypeForwarder
;
1937 public readonly PredefinedAttribute FixedBuffer
;
1938 public readonly PredefinedAttribute CompilerGenerated
;
1939 public readonly PredefinedAttribute InternalsVisibleTo
;
1940 public readonly PredefinedAttribute RuntimeCompatibility
;
1941 public readonly PredefinedAttribute DebuggerHidden
;
1942 public readonly PredefinedAttribute UnsafeValueType
;
1945 public readonly PredefinedAttribute Extension
;
1948 // Optional types which are used as types and for member lookup
1950 public readonly PredefinedAttribute DefaultMember
;
1951 public readonly PredefinedAttribute DecimalConstant
;
1952 public readonly PredefinedAttribute StructLayout
;
1953 public readonly PredefinedAttribute FieldOffset
;
1955 public static PredefinedAttributes Get
= new PredefinedAttributes ();
1957 private PredefinedAttributes ()
1959 ParamArray
= new PredefinedAttribute ("System", "ParamArrayAttribute");
1960 Out
= new PredefinedAttribute ("System.Runtime.InteropServices", "OutAttribute");
1962 Obsolete
= new PredefinedAttribute ("System", "ObsoleteAttribute");
1963 DllImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "DllImportAttribute");
1964 MethodImpl
= new PredefinedAttribute ("System.Runtime.CompilerServices", "MethodImplAttribute");
1965 MarshalAs
= new PredefinedAttribute ("System.Runtime.InteropServices", "MarshalAsAttribute");
1966 In
= new PredefinedAttribute ("System.Runtime.InteropServices", "InAttribute");
1967 IndexerName
= new PredefinedAttribute ("System.Runtime.CompilerServices", "IndexerNameAttribute");
1968 Conditional
= new PredefinedAttribute ("System.Diagnostics", "ConditionalAttribute");
1969 CLSCompliant
= new PredefinedAttribute ("System", "CLSCompliantAttribute");
1970 Security
= new PredefinedAttribute ("System.Security.Permissions", "SecurityAttribute");
1971 Required
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1972 Guid
= new PredefinedAttribute ("System.Runtime.InteropServices", "GuidAttribute");
1973 AssemblyCulture
= new PredefinedAttribute ("System.Reflection", "AssemblyCultureAttribute");
1974 AssemblyVersion
= new PredefinedAttribute ("System.Reflection", "AssemblyVersionAttribute");
1975 ComImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "ComImportAttribute");
1976 CoClass
= new PredefinedAttribute ("System.Runtime.InteropServices", "CoClassAttribute");
1977 AttributeUsage
= new PredefinedAttribute ("System", "AttributeUsageAttribute");
1978 DefaultParameterValue
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1979 OptionalParameter
= new PredefinedAttribute ("System.Runtime.InteropServices", "OptionalAttribute");
1981 DefaultCharset
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultCharSetAttribute");
1982 TypeForwarder
= new PredefinedAttribute ("System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1983 FixedBuffer
= new PredefinedAttribute ("System.Runtime.CompilerServices", "FixedBufferAttribute");
1984 CompilerGenerated
= new PredefinedAttribute ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1985 InternalsVisibleTo
= new PredefinedAttribute ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1986 RuntimeCompatibility
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1987 DebuggerHidden
= new PredefinedAttribute ("System.Diagnostics", "DebuggerHiddenAttribute");
1988 UnsafeValueType
= new PredefinedAttribute ("System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1990 Extension
= new PredefinedAttribute ("System.Runtime.CompilerServices", "ExtensionAttribute");
1992 DefaultMember
= new PredefinedAttribute ("System.Reflection", "DefaultMemberAttribute");
1993 DecimalConstant
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DecimalConstantAttribute");
1994 StructLayout
= new PredefinedAttribute ("System.Runtime.InteropServices", "StructLayoutAttribute");
1995 FieldOffset
= new PredefinedAttribute ("System.Runtime.InteropServices", "FieldOffsetAttribute");
1998 public void Initialize ()
2000 foreach (FieldInfo fi
in GetType ().GetFields (BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
)) {
2001 ((PredefinedAttribute
) fi
.GetValue (this)).Resolve (true);
2005 public static void Reset ()
2007 Get
= new PredefinedAttributes ();
2011 public class PredefinedAttribute
2014 CustomAttributeBuilder cab
;
2015 ConstructorInfo ctor
;
2016 readonly string ns
, name
;
2018 public PredefinedAttribute (string ns
, string name
)
2024 public static bool operator == (Type type
, PredefinedAttribute pa
)
2026 return type
== pa
.type
;
2029 public static bool operator != (Type type
, PredefinedAttribute pa
)
2031 return type
!= pa
.type
;
2034 public ConstructorInfo Constructor
{
2035 get { return ctor; }
2038 public override int GetHashCode ()
2040 return base.GetHashCode ();
2043 public override bool Equals (object obj
)
2045 throw new NotSupportedException ();
2048 public void EmitAttribute (ConstructorBuilder builder
)
2050 if (ResolveBuilder ())
2051 builder
.SetCustomAttribute (cab
);
2054 public void EmitAttribute (MethodBuilder builder
)
2056 if (ResolveBuilder ())
2057 builder
.SetCustomAttribute (cab
);
2060 public void EmitAttribute (FieldBuilder builder
)
2062 if (ResolveBuilder ())
2063 builder
.SetCustomAttribute (cab
);
2066 public void EmitAttribute (TypeBuilder builder
)
2068 if (ResolveBuilder ())
2069 builder
.SetCustomAttribute (cab
);
2072 public void EmitAttribute (AssemblyBuilder builder
)
2074 if (ResolveBuilder ())
2075 builder
.SetCustomAttribute (cab
);
2078 public void EmitAttribute (ParameterBuilder builder
, Location loc
)
2080 if (ResolveBuilder ())
2081 builder
.SetCustomAttribute (cab
);
2084 public bool IsDefined
{
2085 get { return type != null && type != typeof (PredefinedAttribute); }
2088 public bool Resolve (bool canFail
)
2097 type
= TypeManager
.CoreLookupType (ns
, name
, Kind
.Class
, !canFail
);
2099 type
= typeof (PredefinedAttribute
);
2106 bool ResolveBuilder ()
2112 // Handle all parameter-less attributes as optional
2114 if (!Resolve (true))
2117 ConstructorInfo ci
= TypeManager
.GetPredefinedConstructor (type
, Location
.Null
, Type
.EmptyTypes
);
2121 cab
= new CustomAttributeBuilder (ci
, new object[0]);
2125 public bool ResolveConstructor (Location loc
, params Type
[] argType
)
2128 throw new InternalErrorException ("Predefined ctor redefined");
2130 if (!Resolve (false))
2133 ctor
= TypeManager
.GetPredefinedConstructor (type
, loc
, argType
);
2134 return ctor
!= null;
2138 get { return type; }