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 // Holds all attributes attached to this element
35 protected Attributes attributes
;
37 public void AddAttributes (Attributes attrs
, IMemberContext context
)
42 if (attributes
== null)
45 throw new NotImplementedException ();
47 attributes
.AttachTo (this, context
);
50 public Attributes OptAttributes
{
60 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
62 public abstract void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
, PredefinedAttributes pa
);
65 /// Returns one AttributeTarget for this element.
67 public abstract AttributeTargets AttributeTargets { 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
80 public readonly string ExplicitTarget
;
81 public AttributeTargets Target
;
82 readonly ATypeNameExpression expression
;
84 Arguments PosArguments
;
85 Arguments NamedArguments
;
88 readonly bool nameEscaped
;
91 // An attribute can be attached to multiple targets (e.g. multiple fields)
93 protected Attributable
[] targets
;
96 // A member context for the attribute, it's much easier to hold it here
97 // than trying to pull it during resolve
99 IMemberContext context
;
101 static readonly AttributeUsageAttribute DefaultUsageAttribute
= new AttributeUsageAttribute (AttributeTargets
.All
);
102 static Assembly orig_sec_assembly
;
103 public static readonly object[] EmptyObject
= new object [0];
105 // non-null if named args present after Resolve () is called
106 PropertyInfo
[] prop_info_arr
;
107 FieldInfo
[] field_info_arr
;
108 object [] field_values_arr
;
109 object [] prop_values_arr
;
110 object [] pos_values
;
112 static PtrHashtable usage_attr_cache
;
113 // Cache for parameter-less attributes
114 static PtrHashtable att_cache
;
116 public Attribute (string target
, ATypeNameExpression expr
, Arguments
[] args
, Location loc
, bool nameEscaped
)
118 this.expression
= expr
;
120 PosArguments
= args
[0];
121 NamedArguments
= args
[1];
124 ExplicitTarget
= target
;
125 this.nameEscaped
= nameEscaped
;
128 public Attribute
Clone ()
130 Attribute a
= new Attribute (ExplicitTarget
, expression
, null, loc
, nameEscaped
);
131 a
.PosArguments
= PosArguments
;
132 a
.NamedArguments
= NamedArguments
;
141 public static void Reset ()
143 usage_attr_cache
= new PtrHashtable ();
144 att_cache
= new PtrHashtable ();
148 // When the same attribute is attached to multiple fiels
149 // we use @target field as a list of targets. The attribute
150 // has to be resolved only once but emitted for each target.
152 public virtual void AttachTo (Attributable target
, IMemberContext context
)
154 if (this.targets
== null) {
155 this.targets
= new Attributable
[] { target }
;
156 this.context
= context
;
160 // Resize target array
161 Attributable
[] new_array
= new Attributable
[this.targets
.Length
+ 1];
162 targets
.CopyTo (new_array
, 0);
163 new_array
[targets
.Length
] = target
;
164 this.targets
= new_array
;
166 // No need to update context, different targets cannot have
167 // different contexts, it's enough to remove same attributes
168 // from secondary members.
170 target
.OptAttributes
= null;
173 static void Error_InvalidNamedArgument (ResolveContext rc
, NamedArgument name
)
175 rc
.Report
.Error (617, name
.Name
.Location
, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
176 "must be fields which are not readonly, static, const or read-write properties which are " +
177 "public and not static",
181 static void Error_InvalidNamedArgumentType (ResolveContext rc
, NamedArgument name
)
183 rc
.Report
.Error (655, name
.Name
.Location
,
184 "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
188 public static void Error_AttributeArgumentNotValid (ResolveContext rc
, Location loc
)
190 rc
.Report
.Error (182, loc
,
191 "An attribute argument must be a constant expression, typeof " +
192 "expression or array creation expression");
195 public void Error_MissingGuidAttribute ()
197 Report
.Error (596, Location
, "The Guid attribute must be specified with the ComImport attribute");
200 public void Error_MisusedExtensionAttribute ()
202 Report
.Error (1112, Location
, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
205 public void Error_MisusedDynamicAttribute ()
207 Report
.Error (1970, loc
, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
211 /// This is rather hack. We report many emit attribute error with same error to be compatible with
212 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
214 public void Error_AttributeEmitError (string inner
)
216 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
217 TypeManager
.CSharpName (Type
), inner
);
220 public void Error_InvalidSecurityParent ()
222 Error_AttributeEmitError ("it is attached to invalid parent");
231 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IMemberContext ec
)
233 return expr
.ResolveAsTypeTerminal (ec
, false);
236 Type
ResolvePossibleAttributeType (ATypeNameExpression expr
, ref bool is_attr
)
238 TypeExpr te
= ResolveAsTypeTerminal (expr
, context
);
243 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
246 Report
.SymbolRelatedToPreviousError (t
);
247 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
253 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
255 void ResolveAttributeType ()
257 SessionReportPrinter resolve_printer
= new SessionReportPrinter ();
258 ReportPrinter prev_recorder
= context
.Compiler
.Report
.SetPrinter (resolve_printer
);
260 bool t1_is_attr
= false;
261 bool t2_is_attr
= false;
263 ATypeNameExpression expanded
= null;
266 t1
= ResolvePossibleAttributeType (expression
, ref t1_is_attr
);
271 expanded
= (ATypeNameExpression
) expression
.Clone (null);
272 expanded
.Name
+= "Attribute";
274 t2
= ResolvePossibleAttributeType (expanded
, ref t2_is_attr
);
277 resolve_printer
.EndSession ();
279 context
.Compiler
.Report
.SetPrinter (prev_recorder
);
282 if (t1_is_attr
&& t2_is_attr
) {
283 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
284 GetSignatureForError (), expression
.GetSignatureForError (), expanded
.GetSignatureForError ());
285 resolve_error
= true;
299 resolve_printer
.Merge (prev_recorder
);
300 resolve_error
= true;
303 public virtual Type
ResolveType ()
305 if (Type
== null && !resolve_error
)
306 ResolveAttributeType ();
310 public override string GetSignatureForError ()
313 return TypeManager
.CSharpName (Type
);
315 return expression
.GetSignatureForError ();
318 public bool HasSecurityAttribute
{
320 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Security
;
321 return pa
.IsDefined
&& TypeManager
.IsSubclassOf (type
, pa
.Type
);
325 public bool IsValidSecurityAttribute ()
327 return HasSecurityAttribute
&& IsSecurityActionValid (false);
330 static bool IsValidArgumentType (Type t
)
333 t
= TypeManager
.GetElementType (t
);
335 return t
== TypeManager
.string_type
||
336 TypeManager
.IsPrimitiveType (t
) ||
337 TypeManager
.IsEnumType (t
) ||
338 t
== TypeManager
.object_type
||
339 t
== TypeManager
.type_type
;
342 // TODO: Don't use this ambiguous value
344 get { return expression.Name; }
347 void ApplyModuleCharSet ()
349 if (Type
!= PredefinedAttributes
.Get
.DllImport
)
352 if (!RootContext
.ToplevelTypes
.HasDefaultCharSet
)
355 const string CharSetEnumMember
= "CharSet";
356 if (NamedArguments
== null) {
357 NamedArguments
= new Arguments (1);
359 foreach (NamedArgument a
in NamedArguments
) {
360 if (a
.Name
.Value
== CharSetEnumMember
)
365 NamedArguments
.Add (new NamedArgument (new LocatedToken (loc
, CharSetEnumMember
),
366 Constant
.CreateConstant (typeof (CharSet
), RootContext
.ToplevelTypes
.DefaultCharSet
, Location
)));
370 get { return context.Compiler.Report; }
373 public CustomAttributeBuilder
Resolve ()
378 resolve_error
= true;
381 ResolveAttributeType ();
386 if (Type
.IsAbstract
) {
387 Report
.Error (653, Location
, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
391 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (Type
);
392 if (obsolete_attr
!= null) {
393 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, TypeManager
.CSharpName (Type
), Location
, Report
);
396 if (PosArguments
== null && NamedArguments
== null) {
397 object o
= att_cache
[Type
];
399 resolve_error
= false;
400 return (CustomAttributeBuilder
)o
;
404 ResolveContext rc
= new ResolveContext (context
, ResolveContext
.Options
.ConstantScope
);
405 ConstructorInfo ctor
= ResolveConstructor (rc
);
407 if (Type
is TypeBuilder
&&
408 TypeManager
.LookupDeclSpace (Type
).MemberCache
== null)
409 // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error.
410 // It'll be resolved again when the attached-to entity is emitted.
411 resolve_error
= false;
415 ApplyModuleCharSet ();
417 CustomAttributeBuilder cb
;
419 // SRE does not allow private ctor but we want to report all source code errors
423 if (NamedArguments
== null) {
424 cb
= new CustomAttributeBuilder (ctor
, pos_values
);
426 if (pos_values
.Length
== 0)
427 att_cache
.Add (Type
, cb
);
429 resolve_error
= false;
433 if (!ResolveNamedArguments (rc
)) {
437 cb
= new CustomAttributeBuilder (ctor
, pos_values
,
438 prop_info_arr
, prop_values_arr
,
439 field_info_arr
, field_values_arr
);
441 resolve_error
= false;
445 Error_AttributeArgumentNotValid (rc
, Location
);
450 protected virtual ConstructorInfo
ResolveConstructor (ResolveContext ec
)
452 if (PosArguments
!= null) {
454 PosArguments
.Resolve (ec
, out dynamic);
456 Error_AttributeArgumentNotValid (ec
, loc
);
461 MethodGroupExpr mg
= MemberLookupFinal (ec
, ec
.CurrentType
,
462 Type
, ConstructorInfo
.ConstructorName
, MemberTypes
.Constructor
,
463 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
464 Location
) as MethodGroupExpr
;
467 throw new NotImplementedException ();
469 mg
= mg
.OverloadResolve (ec
, ref PosArguments
, false, Location
);
473 ConstructorInfo constructor
= (ConstructorInfo
)mg
;
474 if (PosArguments
== null) {
475 pos_values
= EmptyObject
;
479 AParametersCollection pd
= TypeManager
.GetParameterData (constructor
);
481 if (!PosArguments
.GetAttributableValue (ec
, out pos_values
))
484 // Here we do the checks which should be done by corlib or by runtime.
485 // However Zoltan doesn't like it and every Mono compiler has to do it again.
486 PredefinedAttributes pa
= PredefinedAttributes
.Get
;
487 if (Type
== pa
.Guid
) {
489 new Guid ((string)pos_values
[0]);
491 catch (Exception e
) {
492 Error_AttributeEmitError (e
.Message
);
497 if (Type
== pa
.AttributeUsage
&& (int)pos_values
[0] == 0) {
498 ec
.Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
502 if (Type
== pa
.IndexerName
|| Type
== pa
.Conditional
) {
503 string v
= pos_values
[0] as string;
504 if (!Tokenizer
.IsValidIdentifier (v
) || Tokenizer
.IsKeyword (v
)) {
505 ec
.Report
.Error (633, PosArguments
[0].Expr
.Location
,
506 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
511 if (Type
== pa
.MethodImpl
&& pos_values
.Length
== 1 &&
512 pd
.Types
[0] == TypeManager
.short_type
&&
513 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
514 Error_AttributeEmitError ("Incorrect argument value.");
521 protected virtual bool ResolveNamedArguments (ResolveContext ec
)
523 int named_arg_count
= NamedArguments
.Count
;
525 ArrayList field_infos
= new ArrayList (named_arg_count
);
526 ArrayList prop_infos
= new ArrayList (named_arg_count
);
527 ArrayList field_values
= new ArrayList (named_arg_count
);
528 ArrayList prop_values
= new ArrayList (named_arg_count
);
530 ArrayList seen_names
= new ArrayList (named_arg_count
);
532 foreach (NamedArgument a
in NamedArguments
) {
533 string name
= a
.Name
.Value
;
534 if (seen_names
.Contains (name
)) {
535 ec
.Report
.Error (643, a
.Name
.Location
, "Duplicate named attribute `{0}' argument", name
);
539 seen_names
.Add (name
);
543 Expression member
= Expression
.MemberLookup (ec
.Compiler
,
544 ec
.CurrentType
, Type
, name
,
546 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.Static
,
549 if (member
== null) {
550 member
= Expression
.MemberLookup (ec
.Compiler
, ec
.CurrentType
, Type
, name
,
551 MemberTypes
.All
, BindingFlags
.NonPublic
| BindingFlags
.Instance
| BindingFlags
.Static
,
554 if (member
!= null) {
555 ec
.Report
.SymbolRelatedToPreviousError (member
.Type
);
556 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError (), ec
.Report
);
562 Expression
.Error_TypeDoesNotContainDefinition (ec
, Location
, Type
, name
);
566 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
567 Error_InvalidNamedArgument (ec
, a
);
571 ObsoleteAttribute obsolete_attr
;
573 if (member
is PropertyExpr
) {
574 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
576 if (!pi
.CanWrite
|| !pi
.CanRead
|| pi
.GetGetMethod ().IsStatic
) {
577 ec
.Report
.SymbolRelatedToPreviousError (pi
);
578 Error_InvalidNamedArgument (ec
, a
);
582 if (!IsValidArgumentType (member
.Type
)) {
583 ec
.Report
.SymbolRelatedToPreviousError (pi
);
584 Error_InvalidNamedArgumentType (ec
, a
);
589 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
592 PropertyBase pb
= TypeManager
.GetProperty (pi
);
594 obsolete_attr
= pb
.GetObsoleteAttribute ();
596 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
598 prop_values
.Add (value);
602 FieldInfo fi
= ((FieldExpr
) member
).FieldInfo
;
604 if (fi
.IsInitOnly
|| fi
.IsStatic
) {
605 Error_InvalidNamedArgument (ec
, a
);
609 if (!IsValidArgumentType (member
.Type
)) {
610 ec
.Report
.SymbolRelatedToPreviousError (fi
);
611 Error_InvalidNamedArgumentType (ec
, a
);
616 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
619 FieldBase fb
= TypeManager
.GetField (fi
);
621 obsolete_attr
= fb
.GetObsoleteAttribute ();
623 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
625 field_values
.Add (value);
626 field_infos
.Add (fi
);
629 if (obsolete_attr
!= null && !context
.IsObsolete
)
630 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
, Report
);
633 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
634 field_info_arr
= new FieldInfo
[field_infos
.Count
];
635 field_values_arr
= new object [field_values
.Count
];
636 prop_values_arr
= new object [prop_values
.Count
];
638 field_infos
.CopyTo (field_info_arr
, 0);
639 field_values
.CopyTo (field_values_arr
, 0);
641 prop_values
.CopyTo (prop_values_arr
, 0);
642 prop_infos
.CopyTo (prop_info_arr
, 0);
648 /// Get a string containing a list of valid targets for the attribute 'attr'
650 public string GetValidTargets ()
652 StringBuilder sb
= new StringBuilder ();
653 AttributeTargets targets
= GetAttributeUsage (Type
).ValidOn
;
655 if ((targets
& AttributeTargets
.Assembly
) != 0)
656 sb
.Append ("assembly, ");
658 if ((targets
& AttributeTargets
.Module
) != 0)
659 sb
.Append ("module, ");
661 if ((targets
& AttributeTargets
.Class
) != 0)
662 sb
.Append ("class, ");
664 if ((targets
& AttributeTargets
.Struct
) != 0)
665 sb
.Append ("struct, ");
667 if ((targets
& AttributeTargets
.Enum
) != 0)
668 sb
.Append ("enum, ");
670 if ((targets
& AttributeTargets
.Constructor
) != 0)
671 sb
.Append ("constructor, ");
673 if ((targets
& AttributeTargets
.Method
) != 0)
674 sb
.Append ("method, ");
676 if ((targets
& AttributeTargets
.Property
) != 0)
677 sb
.Append ("property, indexer, ");
679 if ((targets
& AttributeTargets
.Field
) != 0)
680 sb
.Append ("field, ");
682 if ((targets
& AttributeTargets
.Event
) != 0)
683 sb
.Append ("event, ");
685 if ((targets
& AttributeTargets
.Interface
) != 0)
686 sb
.Append ("interface, ");
688 if ((targets
& AttributeTargets
.Parameter
) != 0)
689 sb
.Append ("parameter, ");
691 if ((targets
& AttributeTargets
.Delegate
) != 0)
692 sb
.Append ("delegate, ");
694 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
695 sb
.Append ("return, ");
697 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
698 sb
.Append ("type parameter, ");
700 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
704 /// Returns AttributeUsage attribute based on types hierarchy
706 static AttributeUsageAttribute
GetAttributeUsage (Type type
)
708 AttributeUsageAttribute ua
= usage_attr_cache
[type
] as AttributeUsageAttribute
;
712 Class attr_class
= TypeManager
.LookupClass (type
);
713 PredefinedAttribute pa
= PredefinedAttributes
.Get
.AttributeUsage
;
715 if (attr_class
== null) {
717 return new AttributeUsageAttribute (0);
719 object[] usage_attr
= type
.GetCustomAttributes (pa
.Type
, true);
720 ua
= (AttributeUsageAttribute
)usage_attr
[0];
721 usage_attr_cache
.Add (type
, ua
);
726 if (attr_class
.OptAttributes
!= null)
727 a
= attr_class
.OptAttributes
.Search (pa
);
730 if (attr_class
.TypeBuilder
.BaseType
!= TypeManager
.attribute_type
)
731 ua
= GetAttributeUsage (attr_class
.TypeBuilder
.BaseType
);
733 ua
= DefaultUsageAttribute
;
735 ua
= a
.GetAttributeUsageAttribute ();
738 usage_attr_cache
.Add (type
, ua
);
742 AttributeUsageAttribute
GetAttributeUsageAttribute ()
744 if (pos_values
== null)
745 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
746 // But because a lot of attribute class code must be rewritten will be better to wait...
750 return DefaultUsageAttribute
;
752 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
754 object field
= GetPropertyValue ("AllowMultiple");
756 usage_attribute
.AllowMultiple
= (bool)field
;
758 field
= GetPropertyValue ("Inherited");
760 usage_attribute
.Inherited
= (bool)field
;
762 return usage_attribute
;
766 /// Returns custom name of indexer
768 public string GetIndexerAttributeValue ()
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...
778 return pos_values
[0] as string;
782 /// Returns condition of ConditionalAttribute
784 public string GetConditionalAttributeValue ()
786 if (pos_values
== null)
787 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
788 // But because a lot of attribute class code must be rewritten will be better to wait...
794 return (string)pos_values
[0];
798 /// Creates the instance of ObsoleteAttribute from this attribute instance
800 public ObsoleteAttribute
GetObsoleteAttribute ()
802 if (pos_values
== null)
803 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
804 // But because a lot of attribute class code must be rewritten will be better to wait...
810 if (pos_values
== null || pos_values
.Length
== 0)
811 return new ObsoleteAttribute ();
813 if (pos_values
.Length
== 1)
814 return new ObsoleteAttribute ((string)pos_values
[0]);
816 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
820 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
821 /// before ApplyAttribute. We need to resolve the arguments.
822 /// This situation occurs when class deps is differs from Emit order.
824 public bool GetClsCompliantAttributeValue ()
826 if (pos_values
== null)
827 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
828 // But because a lot of attribute class code must be rewritten will be better to wait...
834 return (bool)pos_values
[0];
837 public Type
GetCoClassAttributeValue ()
839 if (pos_values
== null)
845 return (Type
)pos_values
[0];
848 public bool CheckTarget ()
850 string[] valid_targets
= Owner
.ValidAttributeTargets
;
851 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
852 Target
= Owner
.AttributeTargets
;
856 // TODO: we can skip the first item
857 if (((IList
) valid_targets
).Contains (ExplicitTarget
)) {
858 switch (ExplicitTarget
) {
859 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
860 case "param": Target
= AttributeTargets
.Parameter
; return true;
861 case "field": Target
= AttributeTargets
.Field
; return true;
862 case "method": Target
= AttributeTargets
.Method
; return true;
863 case "property": Target
= AttributeTargets
.Property
; return true;
865 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
868 StringBuilder sb
= new StringBuilder ();
869 foreach (string s
in valid_targets
) {
873 sb
.Remove (sb
.Length
- 2, 2);
874 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
875 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
880 /// Tests permitted SecurityAction for assembly or other types
882 protected virtual bool IsSecurityActionValid (bool for_assembly
)
884 SecurityAction action
= GetSecurityActionValue ();
887 case SecurityAction
.Demand
:
888 case SecurityAction
.Assert
:
889 case SecurityAction
.Deny
:
890 case SecurityAction
.PermitOnly
:
891 case SecurityAction
.LinkDemand
:
892 case SecurityAction
.InheritanceDemand
:
897 case SecurityAction
.RequestMinimum
:
898 case SecurityAction
.RequestOptional
:
899 case SecurityAction
.RequestRefuse
:
905 Error_AttributeEmitError ("SecurityAction is out of range");
909 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
913 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
915 return (SecurityAction
)pos_values
[0];
919 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
921 /// <returns></returns>
922 public void ExtractSecurityPermissionSet (ListDictionary permissions
)
924 Type orig_assembly_type
= null;
926 if (TypeManager
.LookupDeclSpace (Type
) != null) {
927 if (!RootContext
.StdLib
) {
928 orig_assembly_type
= Type
.GetType (Type
.FullName
);
930 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
931 if (orig_version_path
== null) {
932 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
936 if (orig_sec_assembly
== null) {
937 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
938 orig_sec_assembly
= Assembly
.LoadFile (file
);
941 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
942 if (orig_assembly_type
== null) {
943 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
944 "was not found in previous version of assembly");
950 SecurityAttribute sa
;
951 // For all non-selfreferencing security attributes we can avoid all hacks
952 if (orig_assembly_type
== null) {
953 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
955 if (prop_info_arr
!= null) {
956 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
957 PropertyInfo pi
= prop_info_arr
[i
];
958 pi
.SetValue (sa
, prop_values_arr
[i
], null);
962 // HACK: All security attributes have same ctor syntax
963 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
965 // All types are from newly created assembly but for invocation with old one we need to convert them
966 if (prop_info_arr
!= null) {
967 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
968 PropertyInfo emited_pi
= prop_info_arr
[i
];
969 // FIXME: We are missing return type filter
970 // TODO: pi can be null
971 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
);
973 object old_instance
= TypeManager
.IsEnumType (pi
.PropertyType
) ?
974 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
977 pi
.SetValue (sa
, old_instance
, null);
983 perm
= sa
.CreatePermission ();
984 SecurityAction action
= GetSecurityActionValue ();
986 // IS is correct because for corlib we are using an instance from old corlib
987 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
989 case SecurityAction
.Demand
:
990 action
= (SecurityAction
)13;
992 case SecurityAction
.LinkDemand
:
993 action
= (SecurityAction
)14;
995 case SecurityAction
.InheritanceDemand
:
996 action
= (SecurityAction
)15;
1001 PermissionSet ps
= (PermissionSet
)permissions
[action
];
1003 if (sa
is PermissionSetAttribute
)
1004 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
1006 ps
= new PermissionSet (PermissionState
.None
);
1008 permissions
.Add (action
, ps
);
1009 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
1010 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
1011 permissions
[action
] = ps
;
1013 ps
.AddPermission (perm
);
1016 public object GetPropertyValue (string name
)
1018 if (prop_info_arr
== null)
1021 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1022 if (prop_info_arr
[i
].Name
== name
)
1023 return prop_values_arr
[i
];
1030 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1031 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1032 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1035 public UnmanagedMarshal
GetMarshal (Attributable attr
)
1037 UnmanagedType UnmanagedType
;
1038 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (UnmanagedType
))
1039 UnmanagedType
= (UnmanagedType
) System
.Enum
.ToObject (typeof (UnmanagedType
), pos_values
[0]);
1041 UnmanagedType
= (UnmanagedType
) pos_values
[0];
1043 object value = GetFieldValue ("SizeParamIndex");
1044 if (value != null && UnmanagedType
!= UnmanagedType
.LPArray
) {
1045 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1049 object o
= GetFieldValue ("ArraySubType");
1050 UnmanagedType array_sub_type
= o
== null ? (UnmanagedType
) 0x50 /* NATIVE_MAX */ : (UnmanagedType
) o
;
1052 switch (UnmanagedType
) {
1053 case UnmanagedType
.CustomMarshaler
: {
1054 MethodInfo define_custom
= typeof (UnmanagedMarshal
).GetMethod ("DefineCustom",
1055 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1056 if (define_custom
== null) {
1057 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1061 object [] args
= new object [4];
1062 args
[0] = GetFieldValue ("MarshalTypeRef");
1063 args
[1] = GetFieldValue ("MarshalCookie");
1064 args
[2] = GetFieldValue ("MarshalType");
1065 args
[3] = Guid
.Empty
;
1066 return (UnmanagedMarshal
) define_custom
.Invoke (null, args
);
1068 case UnmanagedType
.LPArray
: {
1069 object size_const
= GetFieldValue ("SizeConst");
1070 object size_param_index
= GetFieldValue ("SizeParamIndex");
1072 if ((size_const
!= null) || (size_param_index
!= null)) {
1073 MethodInfo define_array
= typeof (UnmanagedMarshal
).GetMethod ("DefineLPArrayInternal",
1074 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1075 if (define_array
== null) {
1076 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1080 object [] args
= new object [3];
1081 args
[0] = array_sub_type
;
1082 args
[1] = size_const
== null ? -1 : size_const
;
1083 args
[2] = size_param_index
== null ? -1 : size_param_index
;
1084 return (UnmanagedMarshal
) define_array
.Invoke (null, args
);
1087 return UnmanagedMarshal
.DefineLPArray (array_sub_type
);
1089 case UnmanagedType
.SafeArray
:
1090 return UnmanagedMarshal
.DefineSafeArray (array_sub_type
);
1092 case UnmanagedType
.ByValArray
:
1093 FieldBase fm
= attr
as FieldBase
;
1095 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1098 return UnmanagedMarshal
.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1100 case UnmanagedType
.ByValTStr
:
1101 return UnmanagedMarshal
.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1104 return UnmanagedMarshal
.DefineUnmanagedMarshal (UnmanagedType
);
1108 object GetFieldValue (string name
)
1111 if (field_info_arr
== null)
1114 foreach (FieldInfo fi
in field_info_arr
) {
1115 if (fi
.Name
== name
)
1116 return GetValue (field_values_arr
[i
]);
1122 static object GetValue (object value)
1124 if (value is EnumConstant
)
1125 return ((EnumConstant
) value).GetValue ();
1132 public CharSet
GetCharSetValue ()
1134 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1137 public bool HasField (string fieldName
)
1139 if (field_info_arr
== null)
1142 foreach (FieldInfo fi
in field_info_arr
) {
1143 if (fi
.Name
== fieldName
)
1150 public bool IsInternalMethodImplAttribute
{
1152 if (Type
!= PredefinedAttributes
.Get
.MethodImpl
)
1155 MethodImplOptions options
;
1156 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1157 options
= (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1159 options
= (MethodImplOptions
)pos_values
[0];
1161 return (options
& MethodImplOptions
.InternalCall
) != 0;
1165 public LayoutKind
GetLayoutKindValue ()
1167 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1168 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1170 return (LayoutKind
)pos_values
[0];
1173 public object GetParameterDefaultValue ()
1175 return pos_values
[0];
1178 public override bool Equals (object obj
)
1180 Attribute a
= obj
as Attribute
;
1184 return Type
== a
.Type
&& Target
== a
.Target
;
1187 public override int GetHashCode ()
1189 return base.GetHashCode ();
1193 /// Emit attribute for Attributable symbol
1195 public void Emit (ListDictionary allEmitted
)
1197 CustomAttributeBuilder cb
= Resolve ();
1201 AttributeUsageAttribute usage_attr
= GetAttributeUsage (Type
);
1202 if ((usage_attr
.ValidOn
& Target
) == 0) {
1203 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1204 "It is valid on `{1}' declarations only",
1205 GetSignatureForError (), GetValidTargets ());
1209 var predefined
= PredefinedAttributes
.Get
;
1212 foreach (Attributable target
in targets
)
1213 target
.ApplyAttributeBuilder (this, cb
, predefined
);
1214 } catch (Exception e
) {
1215 Error_AttributeEmitError (e
.Message
);
1219 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1220 if (allEmitted
.Contains (this)) {
1221 ArrayList a
= allEmitted
[this] as ArrayList
;
1223 a
= new ArrayList (2);
1224 allEmitted
[this] = a
;
1228 allEmitted
.Add (this, null);
1232 if (!RootContext
.VerifyClsCompliance
)
1235 // Here we are testing attribute arguments for array usage (error 3016)
1236 if (Owner
.IsClsComplianceRequired ()) {
1237 if (PosArguments
!= null)
1238 PosArguments
.CheckArrayAsAttribute (context
.Compiler
);
1240 if (NamedArguments
== null)
1243 NamedArguments
.CheckArrayAsAttribute (context
.Compiler
);
1247 private Expression
GetValue ()
1249 if (PosArguments
== null || PosArguments
.Count
< 1)
1252 return PosArguments
[0].Expr
;
1255 public string GetString ()
1257 Expression e
= GetValue ();
1258 if (e
is StringConstant
)
1259 return ((StringConstant
)e
).Value
;
1263 public bool GetBoolean ()
1265 Expression e
= GetValue ();
1266 if (e
is BoolConstant
)
1267 return ((BoolConstant
)e
).Value
;
1271 public Type
GetArgumentType ()
1273 TypeOf e
= GetValue () as TypeOf
;
1276 return e
.TypeArgument
;
1279 public override Expression
CreateExpressionTree (ResolveContext ec
)
1281 throw new NotSupportedException ("ET");
1284 public override Expression
DoResolve (ResolveContext ec
)
1286 throw new NotImplementedException ();
1289 public override void Emit (EmitContext ec
)
1291 throw new NotImplementedException ();
1297 /// For global attributes (assembly, module) we need special handling.
1298 /// Attributes can be located in the several files
1300 public class GlobalAttribute
: Attribute
1302 public readonly NamespaceEntry ns
;
1304 public GlobalAttribute (NamespaceEntry ns
, string target
, ATypeNameExpression expression
,
1305 Arguments
[] args
, Location loc
, bool nameEscaped
):
1306 base (target
, expression
, args
, loc
, nameEscaped
)
1311 public override void AttachTo (Attributable target
, IMemberContext context
)
1313 if (ExplicitTarget
== "assembly") {
1314 base.AttachTo (CodeGen
.Assembly
, context
);
1318 if (ExplicitTarget
== "module") {
1319 base.AttachTo (RootContext
.ToplevelTypes
, context
);
1323 throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget
);
1328 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1329 // each time a new file is parsed. However, we need to use the NamespaceEntry
1330 // in effect where the attribute was used. Since code elsewhere cannot assume
1331 // that the NamespaceEntry is right, just overwrite it.
1333 // Precondition: RootContext.ToplevelTypes == null
1335 if (RootContext
.ToplevelTypes
.NamespaceEntry
!= null)
1336 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1338 RootContext
.ToplevelTypes
.NamespaceEntry
= ns
;
1341 protected override bool IsSecurityActionValid (bool for_assembly
)
1343 return base.IsSecurityActionValid (true);
1348 RootContext
.ToplevelTypes
.NamespaceEntry
= null;
1351 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IMemberContext ec
)
1355 return base.ResolveAsTypeTerminal (expr
, ec
);
1362 protected override ConstructorInfo
ResolveConstructor (ResolveContext ec
)
1366 return base.ResolveConstructor (ec
);
1373 protected override bool ResolveNamedArguments (ResolveContext ec
)
1377 return base.ResolveNamedArguments (ec
);
1385 public class Attributes
{
1386 public readonly ArrayList Attrs
;
1388 public Attributes (Attribute a
)
1390 Attrs
= new ArrayList ();
1394 public Attributes (ArrayList attrs
)
1399 public void AddAttributes (ArrayList attrs
)
1401 Attrs
.AddRange (attrs
);
1404 public void AttachTo (Attributable attributable
, IMemberContext context
)
1406 foreach (Attribute a
in Attrs
)
1407 a
.AttachTo (attributable
, context
);
1410 public Attributes
Clone ()
1412 ArrayList al
= new ArrayList (Attrs
.Count
);
1413 foreach (Attribute a
in Attrs
)
1414 al
.Add (a
.Clone ());
1416 return new Attributes (al
);
1420 /// Checks whether attribute target is valid for the current element
1422 public bool CheckTargets ()
1424 foreach (Attribute a
in Attrs
) {
1425 if (!a
.CheckTarget ())
1431 public Attribute
Search (PredefinedAttribute t
)
1433 foreach (Attribute a
in Attrs
) {
1434 if (a
.ResolveType () == t
)
1441 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1443 public Attribute
[] SearchMulti (PredefinedAttribute t
)
1445 ArrayList ar
= null;
1447 foreach (Attribute a
in Attrs
) {
1448 if (a
.ResolveType () == t
) {
1450 ar
= new ArrayList ();
1455 return ar
== null ? null : ar
.ToArray (typeof (Attribute
)) as Attribute
[];
1462 ListDictionary ld
= Attrs
.Count
> 1 ? new ListDictionary () : null;
1464 foreach (Attribute a
in Attrs
)
1467 if (ld
== null || ld
.Count
== 0)
1470 foreach (DictionaryEntry d
in ld
) {
1471 if (d
.Value
== null)
1474 Report report
= RootContext
.ToplevelTypes
.Compiler
.Report
;
1475 foreach (Attribute collision
in (ArrayList
)d
.Value
)
1476 report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1478 Attribute a
= (Attribute
)d
.Key
;
1479 report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times",
1480 a
.GetSignatureForError ());
1484 public bool Contains (PredefinedAttribute t
)
1486 return Search (t
) != null;
1491 /// Helper class for attribute verification routine.
1493 sealed class AttributeTester
1495 static PtrHashtable analyzed_types
;
1496 static PtrHashtable analyzed_types_obsolete
;
1497 static PtrHashtable analyzed_member_obsolete
;
1498 static PtrHashtable analyzed_method_excluded
;
1499 static PtrHashtable fixed_buffer_cache
;
1501 static object TRUE
= new object ();
1502 static object FALSE
= new object ();
1504 static AttributeTester ()
1509 private AttributeTester ()
1513 public static void Reset ()
1515 analyzed_types
= new PtrHashtable ();
1516 analyzed_types_obsolete
= new PtrHashtable ();
1517 analyzed_member_obsolete
= new PtrHashtable ();
1518 analyzed_method_excluded
= new PtrHashtable ();
1519 fixed_buffer_cache
= new PtrHashtable ();
1522 public enum Result
{
1529 /// Returns true if parameters of two compared methods are CLS-Compliant.
1530 /// It tests differing only in ref or out, or in array rank.
1532 public static Result
AreOverloadedMethodParamsClsCompliant (AParametersCollection pa
, AParametersCollection pb
)
1534 Type
[] types_a
= pa
.Types
;
1535 Type
[] types_b
= pb
.Types
;
1536 if (types_a
== null || types_b
== null)
1539 if (types_a
.Length
!= types_b
.Length
)
1542 Result result
= Result
.Ok
;
1543 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1544 Type aType
= types_a
[i
];
1545 Type bType
= types_b
[i
];
1547 if (aType
.IsArray
&& bType
.IsArray
) {
1548 Type a_el_type
= TypeManager
.GetElementType (aType
);
1549 Type b_el_type
= TypeManager
.GetElementType (bType
);
1550 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1551 result
= Result
.RefOutArrayError
;
1555 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1556 result
= Result
.ArrayArrayError
;
1564 const Parameter
.Modifier out_ref_mod
= (Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
1565 if ((pa
.FixedParameters
[i
].ModFlags
& out_ref_mod
) != (pb
.FixedParameters
[i
].ModFlags
& out_ref_mod
))
1566 result
= Result
.RefOutArrayError
;
1572 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1574 public static bool IsClsCompliant (Type type
)
1579 object type_compliance
= analyzed_types
[type
];
1580 if (type_compliance
!= null)
1581 return type_compliance
== TRUE
;
1583 if (type
.IsPointer
) {
1584 analyzed_types
.Add (type
, FALSE
);
1590 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1591 } else if (TypeManager
.IsNullableType (type
)) {
1592 result
= IsClsCompliant (TypeManager
.TypeToCoreType (TypeManager
.GetTypeArguments (type
) [0]));
1594 result
= AnalyzeTypeCompliance (type
);
1596 analyzed_types
.Add (type
, result
? TRUE
: FALSE
);
1601 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1603 public static IFixedBuffer
GetFixedBuffer (FieldInfo fi
)
1605 // Fixed buffer helper type is generated as value type
1606 if (TypeManager
.IsReferenceType (fi
.FieldType
))
1609 FieldBase fb
= TypeManager
.GetField (fi
);
1611 return fb
as IFixedBuffer
;
1614 if (TypeManager
.GetConstant (fi
) != null)
1617 object o
= fixed_buffer_cache
[fi
];
1619 PredefinedAttribute pa
= PredefinedAttributes
.Get
.FixedBuffer
;
1623 if (!fi
.IsDefined (pa
.Type
, false)) {
1624 fixed_buffer_cache
.Add (fi
, FALSE
);
1628 IFixedBuffer iff
= new FixedFieldExternal (fi
);
1629 fixed_buffer_cache
.Add (fi
, iff
);
1636 return (IFixedBuffer
)o
;
1639 public static void VerifyModulesClsCompliance (CompilerContext ctx
)
1641 Module
[] modules
= GlobalRootNamespace
.Instance
.Modules
;
1642 if (modules
== null)
1645 // The first module is generated assembly
1646 for (int i
= 1; i
< modules
.Length
; ++i
) {
1647 Module module
= modules
[i
];
1648 if (!GetClsCompliantAttributeValue (module
, null)) {
1649 ctx
.Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1650 "to match the assembly", module
.Name
);
1656 public static Type
GetImportedIgnoreCaseClsType (string name
)
1658 foreach (Assembly a
in GlobalRootNamespace
.Instance
.Assemblies
) {
1659 Type t
= a
.GetType (name
, false, true);
1663 if (IsClsCompliant (t
))
1669 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider
, Assembly a
)
1671 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CLSCompliant
;
1675 object[] cls_attr
= attribute_provider
.GetCustomAttributes (pa
.Type
, false);
1676 if (cls_attr
.Length
== 0) {
1680 return GetClsCompliantAttributeValue (a
, null);
1683 return ((CLSCompliantAttribute
)cls_attr
[0]).IsCompliant
;
1686 static bool AnalyzeTypeCompliance (Type type
)
1688 type
= TypeManager
.DropGenericTypeArguments (type
);
1689 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1691 return ds
.IsClsComplianceRequired ();
1694 if (TypeManager
.IsGenericParameter (type
))
1697 return GetClsCompliantAttributeValue (type
, type
.Assembly
);
1701 /// Returns instance of ObsoleteAttribute when type is obsolete
1703 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1705 object type_obsolete
= analyzed_types_obsolete
[type
];
1706 if (type_obsolete
== FALSE
)
1709 if (type_obsolete
!= null)
1710 return (ObsoleteAttribute
)type_obsolete
;
1712 ObsoleteAttribute result
= null;
1713 if (TypeManager
.HasElementType (type
)) {
1714 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1715 } else if (TypeManager
.IsGenericParameter (type
))
1716 result
= null; // TODO: throw new NotSupportedException ()
1717 else if (TypeManager
.IsGenericType (type
) && !TypeManager
.IsGenericTypeDefinition (type
)) {
1718 return GetObsoleteAttribute (TypeManager
.DropGenericTypeArguments (type
));
1720 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1722 // Type is external, we can get attribute directly
1723 if (type_ds
== null) {
1724 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1726 object[] attribute
= type
.GetCustomAttributes (pa
.Type
, false);
1727 if (attribute
.Length
== 1)
1728 result
= (ObsoleteAttribute
) attribute
[0];
1731 result
= type_ds
.GetObsoleteAttribute ();
1735 // Cannot use .Add because of corlib bootstrap
1736 analyzed_types_obsolete
[type
] = result
== null ? FALSE
: result
;
1741 /// Returns instance of ObsoleteAttribute when method is obsolete
1743 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1745 IMethodData mc
= TypeManager
.GetMethod (mb
);
1747 return mc
.GetObsoleteAttribute ();
1749 // compiler generated methods are not registered by AddMethod
1750 if (mb
.DeclaringType
is TypeBuilder
)
1753 MemberInfo mi
= TypeManager
.GetPropertyFromAccessor (mb
);
1755 return GetMemberObsoleteAttribute (mi
);
1757 mi
= TypeManager
.GetEventFromAccessor (mb
);
1759 return GetMemberObsoleteAttribute (mi
);
1761 return GetMemberObsoleteAttribute (mb
);
1765 /// Returns instance of ObsoleteAttribute when member is obsolete
1767 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1769 object type_obsolete
= analyzed_member_obsolete
[mi
];
1770 if (type_obsolete
== FALSE
)
1773 if (type_obsolete
!= null)
1774 return (ObsoleteAttribute
)type_obsolete
;
1776 if ((mi
.DeclaringType
is TypeBuilder
) || TypeManager
.IsGenericType (mi
.DeclaringType
))
1779 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1783 ObsoleteAttribute oa
= System
.Attribute
.GetCustomAttribute (mi
, pa
.Type
, false)
1784 as ObsoleteAttribute
;
1785 analyzed_member_obsolete
.Add (mi
, oa
== null ? FALSE
: oa
);
1790 /// Common method for Obsolete error/warning reporting.
1792 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
, Report Report
)
1795 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1799 if (oa
.Message
== null || oa
.Message
.Length
== 0) {
1800 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1803 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1806 public static bool IsConditionalMethodExcluded (MethodBase mb
, Location loc
)
1808 object excluded
= analyzed_method_excluded
[mb
];
1809 if (excluded
!= null)
1810 return excluded
== TRUE
? true : false;
1812 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1816 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (pa
.Type
, true)
1817 as ConditionalAttribute
[];
1818 if (attrs
.Length
== 0) {
1819 analyzed_method_excluded
.Add (mb
, FALSE
);
1823 foreach (ConditionalAttribute a
in attrs
) {
1824 if (loc
.CompilationUnit
.IsConditionalDefined (a
.ConditionString
)) {
1825 analyzed_method_excluded
.Add (mb
, FALSE
);
1830 analyzed_method_excluded
.Add (mb
, TRUE
);
1835 /// Analyzes class whether it has attribute which has ConditionalAttribute
1836 /// and its condition is not defined.
1838 public static bool IsAttributeExcluded (Type type
, Location loc
)
1843 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1845 // TODO: add caching
1846 // TODO: merge all Type bases attribute caching to one cache to save memory
1847 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1848 if (class_decl
== null && pa
.IsDefined
) {
1849 object[] attributes
= type
.GetCustomAttributes (pa
.Type
, false);
1850 foreach (ConditionalAttribute ca
in attributes
) {
1851 if (loc
.CompilationUnit
.IsConditionalDefined (ca
.ConditionString
))
1854 return attributes
.Length
> 0;
1857 return class_decl
.IsExcluded ();
1860 public static Type
GetCoClassAttribute (Type type
)
1862 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1863 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CoClass
;
1868 object[] o
= type
.GetCustomAttributes (pa
.Type
, false);
1871 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1874 if (tc
.OptAttributes
== null)
1877 Attribute a
= tc
.OptAttributes
.Search (pa
);
1881 return a
.GetCoClassAttributeValue ();
1885 public class PredefinedAttributes
1888 public readonly PredefinedAttribute ParamArray
;
1889 public readonly PredefinedAttribute Out
;
1892 public readonly PredefinedAttribute Obsolete
;
1893 public readonly PredefinedAttribute DllImport
;
1894 public readonly PredefinedAttribute MethodImpl
;
1895 public readonly PredefinedAttribute MarshalAs
;
1896 public readonly PredefinedAttribute In
;
1897 public readonly PredefinedAttribute IndexerName
;
1898 public readonly PredefinedAttribute Conditional
;
1899 public readonly PredefinedAttribute CLSCompliant
;
1900 public readonly PredefinedAttribute Security
;
1901 public readonly PredefinedAttribute Required
;
1902 public readonly PredefinedAttribute Guid
;
1903 public readonly PredefinedAttribute AssemblyCulture
;
1904 public readonly PredefinedAttribute AssemblyVersion
;
1905 public readonly PredefinedAttribute ComImport
;
1906 public readonly PredefinedAttribute CoClass
;
1907 public readonly PredefinedAttribute AttributeUsage
;
1908 public readonly PredefinedAttribute DefaultParameterValue
;
1909 public readonly PredefinedAttribute OptionalParameter
;
1912 public readonly PredefinedAttribute DefaultCharset
;
1913 public readonly PredefinedAttribute TypeForwarder
;
1914 public readonly PredefinedAttribute FixedBuffer
;
1915 public readonly PredefinedAttribute CompilerGenerated
;
1916 public readonly PredefinedAttribute InternalsVisibleTo
;
1917 public readonly PredefinedAttribute RuntimeCompatibility
;
1918 public readonly PredefinedAttribute DebuggerHidden
;
1919 public readonly PredefinedAttribute UnsafeValueType
;
1922 public readonly PredefinedAttribute Extension
;
1925 public readonly PredefinedAttribute Dynamic
;
1928 // Optional types which are used as types and for member lookup
1930 public readonly PredefinedAttribute DefaultMember
;
1931 public readonly PredefinedAttribute DecimalConstant
;
1932 public readonly PredefinedAttribute StructLayout
;
1933 public readonly PredefinedAttribute FieldOffset
;
1935 public static PredefinedAttributes Get
= new PredefinedAttributes ();
1937 private PredefinedAttributes ()
1939 ParamArray
= new PredefinedAttribute ("System", "ParamArrayAttribute");
1940 Out
= new PredefinedAttribute ("System.Runtime.InteropServices", "OutAttribute");
1942 Obsolete
= new PredefinedAttribute ("System", "ObsoleteAttribute");
1943 DllImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "DllImportAttribute");
1944 MethodImpl
= new PredefinedAttribute ("System.Runtime.CompilerServices", "MethodImplAttribute");
1945 MarshalAs
= new PredefinedAttribute ("System.Runtime.InteropServices", "MarshalAsAttribute");
1946 In
= new PredefinedAttribute ("System.Runtime.InteropServices", "InAttribute");
1947 IndexerName
= new PredefinedAttribute ("System.Runtime.CompilerServices", "IndexerNameAttribute");
1948 Conditional
= new PredefinedAttribute ("System.Diagnostics", "ConditionalAttribute");
1949 CLSCompliant
= new PredefinedAttribute ("System", "CLSCompliantAttribute");
1950 Security
= new PredefinedAttribute ("System.Security.Permissions", "SecurityAttribute");
1951 Required
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1952 Guid
= new PredefinedAttribute ("System.Runtime.InteropServices", "GuidAttribute");
1953 AssemblyCulture
= new PredefinedAttribute ("System.Reflection", "AssemblyCultureAttribute");
1954 AssemblyVersion
= new PredefinedAttribute ("System.Reflection", "AssemblyVersionAttribute");
1955 ComImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "ComImportAttribute");
1956 CoClass
= new PredefinedAttribute ("System.Runtime.InteropServices", "CoClassAttribute");
1957 AttributeUsage
= new PredefinedAttribute ("System", "AttributeUsageAttribute");
1958 DefaultParameterValue
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1959 OptionalParameter
= new PredefinedAttribute ("System.Runtime.InteropServices", "OptionalAttribute");
1961 DefaultCharset
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultCharSetAttribute");
1962 TypeForwarder
= new PredefinedAttribute ("System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1963 FixedBuffer
= new PredefinedAttribute ("System.Runtime.CompilerServices", "FixedBufferAttribute");
1964 CompilerGenerated
= new PredefinedAttribute ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1965 InternalsVisibleTo
= new PredefinedAttribute ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1966 RuntimeCompatibility
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1967 DebuggerHidden
= new PredefinedAttribute ("System.Diagnostics", "DebuggerHiddenAttribute");
1968 UnsafeValueType
= new PredefinedAttribute ("System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1970 Extension
= new PredefinedAttribute ("System.Runtime.CompilerServices", "ExtensionAttribute");
1972 Dynamic
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DynamicAttribute");
1974 DefaultMember
= new PredefinedAttribute ("System.Reflection", "DefaultMemberAttribute");
1975 DecimalConstant
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DecimalConstantAttribute");
1976 StructLayout
= new PredefinedAttribute ("System.Runtime.InteropServices", "StructLayoutAttribute");
1977 FieldOffset
= new PredefinedAttribute ("System.Runtime.InteropServices", "FieldOffsetAttribute");
1980 public void Initialize ()
1982 foreach (FieldInfo fi
in GetType ().GetFields (BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
)) {
1983 ((PredefinedAttribute
) fi
.GetValue (this)).Resolve (true);
1987 public static void Reset ()
1989 Get
= new PredefinedAttributes ();
1993 public class PredefinedAttribute
1996 CustomAttributeBuilder cab
;
1997 ConstructorInfo ctor
;
1998 readonly string ns
, name
;
2000 static readonly Type NotFound
= typeof (PredefinedAttribute
);
2002 public PredefinedAttribute (string ns
, string name
)
2008 public static bool operator == (Type type
, PredefinedAttribute pa
)
2010 return type
== pa
.type
;
2013 public static bool operator != (Type type
, PredefinedAttribute pa
)
2015 return type
!= pa
.type
;
2018 public ConstructorInfo Constructor
{
2019 get { return ctor; }
2022 public override int GetHashCode ()
2024 return base.GetHashCode ();
2027 public string GetSignatureForError ()
2029 return ns
+ "." + name
;
2032 public override bool Equals (object obj
)
2034 throw new NotSupportedException ();
2037 public void EmitAttribute (ConstructorBuilder builder
)
2039 if (ResolveBuilder ())
2040 builder
.SetCustomAttribute (cab
);
2043 public void EmitAttribute (MethodBuilder builder
)
2045 if (ResolveBuilder ())
2046 builder
.SetCustomAttribute (cab
);
2049 public void EmitAttribute (PropertyBuilder builder
)
2051 if (ResolveBuilder ())
2052 builder
.SetCustomAttribute (cab
);
2055 public void EmitAttribute (FieldBuilder builder
)
2057 if (ResolveBuilder ())
2058 builder
.SetCustomAttribute (cab
);
2061 public void EmitAttribute (TypeBuilder builder
)
2063 if (ResolveBuilder ())
2064 builder
.SetCustomAttribute (cab
);
2067 public void EmitAttribute (AssemblyBuilder builder
)
2069 if (ResolveBuilder ())
2070 builder
.SetCustomAttribute (cab
);
2073 public void EmitAttribute (ParameterBuilder builder
)
2075 if (ResolveBuilder ())
2076 builder
.SetCustomAttribute (cab
);
2079 public bool IsDefined
{
2080 get { return type != null && type != NotFound; }
2083 public bool Resolve (bool canFail
)
2092 type
= TypeManager
.CoreLookupType (RootContext
.ToplevelTypes
.Compiler
, ns
, name
, Kind
.Class
, !canFail
);
2101 bool ResolveBuilder ()
2107 // Handle all parameter-less attributes as optional
2109 if (!Resolve (true))
2112 ConstructorInfo ci
= TypeManager
.GetPredefinedConstructor (type
, Location
.Null
, Type
.EmptyTypes
);
2116 cab
= new CustomAttributeBuilder (ci
, new object[0]);
2120 public bool ResolveConstructor (Location loc
, params Type
[] argType
)
2123 throw new InternalErrorException ("Predefined ctor redefined");
2125 if (!Resolve (false))
2128 ctor
= TypeManager
.GetPredefinedConstructor (type
, loc
, argType
);
2129 return ctor
!= null;
2133 get { return type; }