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
.Generic
;
16 using System
.Reflection
;
17 using System
.Reflection
.Emit
;
18 using System
.Runtime
.InteropServices
;
19 using System
.Runtime
.CompilerServices
;
20 using System
.Security
;
21 using System
.Security
.Permissions
;
25 namespace Mono
.CSharp
{
28 /// Base class for objects that can have Attributes applied to them.
30 public abstract class Attributable
{
32 // Holds all attributes attached to this element
34 protected Attributes attributes
;
36 public void AddAttributes (Attributes attrs
, IMemberContext context
)
41 if (attributes
== null)
44 throw new NotImplementedException ();
46 attributes
.AttachTo (this, context
);
49 public Attributes OptAttributes
{
59 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
61 public abstract void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
, PredefinedAttributes pa
);
64 /// Returns one AttributeTarget for this element.
66 public abstract AttributeTargets AttributeTargets { get; }
68 public abstract bool IsClsComplianceRequired ();
71 /// Gets list of valid attribute targets for explicit target declaration.
72 /// The first array item is default target. Don't break this rule.
74 public abstract string[] ValidAttributeTargets { get; }
77 public class Attribute
: Expression
79 public readonly string ExplicitTarget
;
80 public AttributeTargets Target
;
81 readonly ATypeNameExpression expression
;
83 Arguments PosArguments
;
84 Arguments NamedArguments
;
87 readonly bool nameEscaped
;
90 // An attribute can be attached to multiple targets (e.g. multiple fields)
92 protected Attributable
[] targets
;
95 // A member context for the attribute, it's much easier to hold it here
96 // than trying to pull it during resolve
98 IMemberContext context
;
100 static readonly AttributeUsageAttribute DefaultUsageAttribute
= new AttributeUsageAttribute (AttributeTargets
.All
);
101 static Assembly orig_sec_assembly
;
102 public static readonly object[] EmptyObject
= new object [0];
104 // non-null if named args present after Resolve () is called
105 PropertyInfo
[] prop_info_arr
;
106 FieldInfo
[] field_info_arr
;
107 object [] field_values_arr
;
108 object [] prop_values_arr
;
109 object [] pos_values
;
111 static Dictionary
<Type
, AttributeUsageAttribute
> usage_attr_cache
;
112 // Cache for parameter-less attributes
113 static Dictionary
<Type
, CustomAttributeBuilder
> att_cache
;
115 public Attribute (string target
, ATypeNameExpression expr
, Arguments
[] args
, Location loc
, bool nameEscaped
)
117 this.expression
= expr
;
119 PosArguments
= args
[0];
120 NamedArguments
= args
[1];
123 ExplicitTarget
= target
;
124 this.nameEscaped
= nameEscaped
;
127 public Attribute
Clone ()
129 Attribute a
= new Attribute (ExplicitTarget
, expression
, null, loc
, nameEscaped
);
130 a
.PosArguments
= PosArguments
;
131 a
.NamedArguments
= NamedArguments
;
140 public static void Reset ()
142 usage_attr_cache
= new Dictionary
<Type
, AttributeUsageAttribute
> (ReferenceEquality
<Type
>.Default
);
143 att_cache
= new Dictionary
<Type
, CustomAttributeBuilder
> (ReferenceEquality
<Type
>.Default
);
147 // When the same attribute is attached to multiple fiels
148 // we use @target field as a list of targets. The attribute
149 // has to be resolved only once but emitted for each target.
151 public virtual void AttachTo (Attributable target
, IMemberContext context
)
153 if (this.targets
== null) {
154 this.targets
= new Attributable
[] { target }
;
155 this.context
= context
;
159 // Resize target array
160 Attributable
[] new_array
= new Attributable
[this.targets
.Length
+ 1];
161 targets
.CopyTo (new_array
, 0);
162 new_array
[targets
.Length
] = target
;
163 this.targets
= new_array
;
165 // No need to update context, different targets cannot have
166 // different contexts, it's enough to remove same attributes
167 // from secondary members.
169 target
.OptAttributes
= null;
172 static void Error_InvalidNamedArgument (ResolveContext rc
, NamedArgument name
)
174 rc
.Report
.Error (617, name
.Location
, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
175 "must be fields which are not readonly, static, const or read-write properties which are " +
176 "public and not static",
180 static void Error_InvalidNamedArgumentType (ResolveContext rc
, NamedArgument name
)
182 rc
.Report
.Error (655, name
.Location
,
183 "`{0}' is not a valid named attribute argument because it is not a valid attribute parameter type",
187 public static void Error_AttributeArgumentNotValid (ResolveContext rc
, Location loc
)
189 rc
.Report
.Error (182, loc
,
190 "An attribute argument must be a constant expression, typeof " +
191 "expression or array creation expression");
194 public void Error_MissingGuidAttribute ()
196 Report
.Error (596, Location
, "The Guid attribute must be specified with the ComImport attribute");
199 public void Error_MisusedExtensionAttribute ()
201 Report
.Error (1112, Location
, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
204 public void Error_MisusedDynamicAttribute ()
206 Report
.Error (1970, loc
, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
210 /// This is rather hack. We report many emit attribute error with same error to be compatible with
211 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
213 public void Error_AttributeEmitError (string inner
)
215 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
216 TypeManager
.CSharpName (Type
), inner
);
219 public void Error_InvalidSecurityParent ()
221 Error_AttributeEmitError ("it is attached to invalid parent");
230 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IMemberContext ec
)
232 return expr
.ResolveAsTypeTerminal (ec
, false);
235 Type
ResolvePossibleAttributeType (ATypeNameExpression expr
, ref bool is_attr
)
237 TypeExpr te
= ResolveAsTypeTerminal (expr
, context
);
242 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
245 Report
.SymbolRelatedToPreviousError (t
);
246 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
252 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
254 void ResolveAttributeType ()
256 SessionReportPrinter resolve_printer
= new SessionReportPrinter ();
257 ReportPrinter prev_recorder
= context
.Compiler
.Report
.SetPrinter (resolve_printer
);
259 bool t1_is_attr
= false;
260 bool t2_is_attr
= false;
262 ATypeNameExpression expanded
= null;
265 t1
= ResolvePossibleAttributeType (expression
, ref t1_is_attr
);
270 expanded
= (ATypeNameExpression
) expression
.Clone (null);
271 expanded
.Name
+= "Attribute";
273 t2
= ResolvePossibleAttributeType (expanded
, ref t2_is_attr
);
276 resolve_printer
.EndSession ();
278 context
.Compiler
.Report
.SetPrinter (prev_recorder
);
281 if (t1_is_attr
&& t2_is_attr
) {
282 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
283 GetSignatureForError (), expression
.GetSignatureForError (), expanded
.GetSignatureForError ());
284 resolve_error
= true;
298 resolve_printer
.Merge (prev_recorder
);
299 resolve_error
= true;
302 public virtual Type
ResolveType ()
304 if (Type
== null && !resolve_error
)
305 ResolveAttributeType ();
309 public override string GetSignatureForError ()
312 return TypeManager
.CSharpName (Type
);
314 return expression
.GetSignatureForError ();
317 public bool HasSecurityAttribute
{
319 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Security
;
320 return pa
.IsDefined
&& TypeManager
.IsSubclassOf (type
, pa
.Type
);
324 public bool IsValidSecurityAttribute ()
326 return HasSecurityAttribute
&& IsSecurityActionValid (false);
329 static bool IsValidArgumentType (Type t
)
332 t
= TypeManager
.GetElementType (t
);
334 return t
== TypeManager
.string_type
||
335 TypeManager
.IsPrimitiveType (t
) ||
336 TypeManager
.IsEnumType (t
) ||
337 t
== TypeManager
.object_type
||
338 t
== TypeManager
.type_type
;
341 // TODO: Don't use this ambiguous value
343 get { return expression.Name; }
346 void ApplyModuleCharSet (ResolveContext rc
)
348 if (Type
!= PredefinedAttributes
.Get
.DllImport
)
351 if (!RootContext
.ToplevelTypes
.HasDefaultCharSet
)
354 const string CharSetEnumMember
= "CharSet";
355 if (NamedArguments
== null) {
356 NamedArguments
= new Arguments (1);
358 foreach (NamedArgument a
in NamedArguments
) {
359 if (a
.Name
== CharSetEnumMember
)
364 NamedArguments
.Add (new NamedArgument (CharSetEnumMember
, loc
,
365 Constant
.CreateConstant (rc
, typeof (CharSet
), RootContext
.ToplevelTypes
.DefaultCharSet
, Location
)));
368 public Report Report
{
369 get { return context.Compiler.Report; }
372 public CustomAttributeBuilder
Resolve ()
377 resolve_error
= true;
380 ResolveAttributeType ();
385 if (Type
.IsAbstract
) {
386 Report
.Error (653, Location
, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
390 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (Type
);
391 if (obsolete_attr
!= null) {
392 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, TypeManager
.CSharpName (Type
), Location
, Report
);
395 CustomAttributeBuilder cb
;
396 if (PosArguments
== null && NamedArguments
== null) {
397 if (att_cache
.TryGetValue (Type
, out cb
)) {
398 resolve_error
= false;
403 ResolveContext rc
= new ResolveContext (context
, ResolveContext
.Options
.ConstantScope
);
404 var ctor
= ResolveConstructor (rc
);
406 if (Type
is TypeBuilder
&&
407 TypeManager
.LookupDeclSpace (Type
).MemberCache
== null)
408 // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error.
409 // It'll be resolved again when the attached-to entity is emitted.
410 resolve_error
= false;
414 ApplyModuleCharSet (rc
);
417 var ctor_meta
= (ConstructorInfo
) ctor
.MetaInfo
;
418 // SRE does not allow private ctor but we want to report all source code errors
419 if (ctor
.MetaInfo
.IsPrivate
)
422 if (NamedArguments
== null) {
423 cb
= new CustomAttributeBuilder (ctor_meta
, pos_values
);
425 if (pos_values
.Length
== 0)
426 att_cache
.Add (Type
, cb
);
428 resolve_error
= false;
432 if (!ResolveNamedArguments (rc
)) {
436 cb
= new CustomAttributeBuilder (ctor_meta
, pos_values
,
437 prop_info_arr
, prop_values_arr
,
438 field_info_arr
, field_values_arr
);
440 resolve_error
= false;
444 Error_AttributeArgumentNotValid (rc
, Location
);
449 protected virtual MethodSpec
ResolveConstructor (ResolveContext ec
)
451 if (PosArguments
!= null) {
453 PosArguments
.Resolve (ec
, out dynamic);
455 Error_AttributeArgumentNotValid (ec
, loc
);
460 MethodGroupExpr mg
= MemberLookupFinal (ec
, ec
.CurrentType
,
461 Type
, ConstructorInfo
.ConstructorName
, MemberTypes
.Constructor
,
462 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
463 Location
) as MethodGroupExpr
;
466 throw new NotImplementedException ();
468 mg
= mg
.OverloadResolve (ec
, ref PosArguments
, false, Location
);
472 var constructor
= (MethodSpec
) mg
;
473 if (PosArguments
== null) {
474 pos_values
= EmptyObject
;
478 if (!PosArguments
.GetAttributableValue (ec
, out pos_values
))
481 // Here we do the checks which should be done by corlib or by runtime.
482 // However Zoltan doesn't like it and every Mono compiler has to do it again.
483 PredefinedAttributes pa
= PredefinedAttributes
.Get
;
484 if (Type
== pa
.Guid
) {
486 new Guid ((string)pos_values
[0]);
488 catch (Exception e
) {
489 Error_AttributeEmitError (e
.Message
);
494 if (Type
== pa
.AttributeUsage
&& (int)pos_values
[0] == 0) {
495 ec
.Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
499 if (Type
== pa
.IndexerName
|| Type
== pa
.Conditional
) {
500 string v
= pos_values
[0] as string;
501 if (!Tokenizer
.IsValidIdentifier (v
) || Tokenizer
.IsKeyword (v
)) {
502 ec
.Report
.Error (633, PosArguments
[0].Expr
.Location
,
503 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
508 if (Type
== pa
.MethodImpl
&& pos_values
.Length
== 1 &&
509 constructor
.Parameters
.Types
[0] == TypeManager
.short_type
&&
510 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
511 Error_AttributeEmitError ("Incorrect argument value.");
518 protected virtual bool ResolveNamedArguments (ResolveContext ec
)
520 int named_arg_count
= NamedArguments
.Count
;
522 var field_infos
= new List
<FieldInfo
> (named_arg_count
);
523 var prop_infos
= new List
<PropertyInfo
> (named_arg_count
);
524 var field_values
= new List
<object> (named_arg_count
);
525 var prop_values
= new List
<object> (named_arg_count
);
527 var seen_names
= new List
<string> (named_arg_count
);
529 foreach (NamedArgument a
in NamedArguments
) {
530 string name
= a
.Name
;
531 if (seen_names
.Contains (name
)) {
532 ec
.Report
.Error (643, a
.Location
, "Duplicate named attribute `{0}' argument", name
);
536 seen_names
.Add (name
);
540 Expression member
= Expression
.MemberLookup (ec
.Compiler
,
541 ec
.CurrentType
, Type
, name
,
543 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.Static
,
546 if (member
== null) {
547 member
= Expression
.MemberLookup (ec
.Compiler
, ec
.CurrentType
, Type
, name
,
548 MemberTypes
.All
, BindingFlags
.NonPublic
| BindingFlags
.Instance
| BindingFlags
.Static
,
551 if (member
!= null) {
552 ec
.Report
.SymbolRelatedToPreviousError (member
.Type
);
553 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError (), ec
.Report
);
559 Expression
.Error_TypeDoesNotContainDefinition (ec
, Location
, Type
, name
);
563 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
564 Error_InvalidNamedArgument (ec
, a
);
568 ObsoleteAttribute obsolete_attr
;
570 if (member
is PropertyExpr
) {
571 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
573 if (!pi
.CanWrite
|| !pi
.CanRead
|| pi
.GetGetMethod ().IsStatic
) {
574 ec
.Report
.SymbolRelatedToPreviousError (pi
);
575 Error_InvalidNamedArgument (ec
, a
);
579 if (!IsValidArgumentType (member
.Type
)) {
580 ec
.Report
.SymbolRelatedToPreviousError (pi
);
581 Error_InvalidNamedArgumentType (ec
, a
);
586 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
589 PropertyBase pb
= TypeManager
.GetProperty (pi
);
591 obsolete_attr
= pb
.GetObsoleteAttribute ();
593 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
595 prop_values
.Add (value);
599 var fi
= ((FieldExpr
) member
).Spec
;
601 if (fi
.IsReadOnly
|| fi
.IsStatic
) {
602 Error_InvalidNamedArgument (ec
, a
);
606 if (!IsValidArgumentType (member
.Type
)) {
607 ec
.Report
.SymbolRelatedToPreviousError (fi
.MetaInfo
);
608 Error_InvalidNamedArgumentType (ec
, a
);
613 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
616 FieldBase fb
= TypeManager
.GetField (fi
.MetaInfo
);
618 obsolete_attr
= fb
.GetObsoleteAttribute ();
620 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
.MetaInfo
);
622 field_values
.Add (value);
623 field_infos
.Add (fi
.MetaInfo
);
626 if (obsolete_attr
!= null && !context
.IsObsolete
)
627 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
, Report
);
630 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
631 field_info_arr
= new FieldInfo
[field_infos
.Count
];
632 field_values_arr
= new object [field_values
.Count
];
633 prop_values_arr
= new object [prop_values
.Count
];
635 field_infos
.CopyTo (field_info_arr
, 0);
636 field_values
.CopyTo (field_values_arr
, 0);
638 prop_values
.CopyTo (prop_values_arr
, 0);
639 prop_infos
.CopyTo (prop_info_arr
, 0);
645 /// Get a string containing a list of valid targets for the attribute 'attr'
647 public string GetValidTargets ()
649 StringBuilder sb
= new StringBuilder ();
650 AttributeTargets targets
= GetAttributeUsage (Type
).ValidOn
;
652 if ((targets
& AttributeTargets
.Assembly
) != 0)
653 sb
.Append ("assembly, ");
655 if ((targets
& AttributeTargets
.Module
) != 0)
656 sb
.Append ("module, ");
658 if ((targets
& AttributeTargets
.Class
) != 0)
659 sb
.Append ("class, ");
661 if ((targets
& AttributeTargets
.Struct
) != 0)
662 sb
.Append ("struct, ");
664 if ((targets
& AttributeTargets
.Enum
) != 0)
665 sb
.Append ("enum, ");
667 if ((targets
& AttributeTargets
.Constructor
) != 0)
668 sb
.Append ("constructor, ");
670 if ((targets
& AttributeTargets
.Method
) != 0)
671 sb
.Append ("method, ");
673 if ((targets
& AttributeTargets
.Property
) != 0)
674 sb
.Append ("property, indexer, ");
676 if ((targets
& AttributeTargets
.Field
) != 0)
677 sb
.Append ("field, ");
679 if ((targets
& AttributeTargets
.Event
) != 0)
680 sb
.Append ("event, ");
682 if ((targets
& AttributeTargets
.Interface
) != 0)
683 sb
.Append ("interface, ");
685 if ((targets
& AttributeTargets
.Parameter
) != 0)
686 sb
.Append ("parameter, ");
688 if ((targets
& AttributeTargets
.Delegate
) != 0)
689 sb
.Append ("delegate, ");
691 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
692 sb
.Append ("return, ");
694 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
695 sb
.Append ("type parameter, ");
697 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
701 /// Returns AttributeUsage attribute based on types hierarchy
703 static AttributeUsageAttribute
GetAttributeUsage (Type type
)
705 AttributeUsageAttribute ua
;
706 if (usage_attr_cache
.TryGetValue (type
, out ua
))
709 Class attr_class
= TypeManager
.LookupClass (type
);
710 PredefinedAttribute pa
= PredefinedAttributes
.Get
.AttributeUsage
;
712 if (attr_class
== null) {
714 return new AttributeUsageAttribute (0);
716 object[] usage_attr
= type
.GetCustomAttributes (pa
.Type
, true);
717 ua
= (AttributeUsageAttribute
)usage_attr
[0];
718 usage_attr_cache
.Add (type
, ua
);
723 if (attr_class
.OptAttributes
!= null)
724 a
= attr_class
.OptAttributes
.Search (pa
);
727 if (attr_class
.TypeBuilder
.BaseType
!= TypeManager
.attribute_type
)
728 ua
= GetAttributeUsage (attr_class
.TypeBuilder
.BaseType
);
730 ua
= DefaultUsageAttribute
;
732 ua
= a
.GetAttributeUsageAttribute ();
735 usage_attr_cache
.Add (type
, ua
);
739 AttributeUsageAttribute
GetAttributeUsageAttribute ()
741 if (pos_values
== null)
742 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
743 // But because a lot of attribute class code must be rewritten will be better to wait...
747 return DefaultUsageAttribute
;
749 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
751 object field
= GetPropertyValue ("AllowMultiple");
753 usage_attribute
.AllowMultiple
= (bool)field
;
755 field
= GetPropertyValue ("Inherited");
757 usage_attribute
.Inherited
= (bool)field
;
759 return usage_attribute
;
763 /// Returns custom name of indexer
765 public string GetIndexerAttributeValue ()
767 if (pos_values
== null)
768 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
769 // But because a lot of attribute class code must be rewritten will be better to wait...
775 return pos_values
[0] as string;
779 /// Returns condition of ConditionalAttribute
781 public string GetConditionalAttributeValue ()
783 if (pos_values
== null)
784 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
785 // But because a lot of attribute class code must be rewritten will be better to wait...
791 return (string)pos_values
[0];
795 /// Creates the instance of ObsoleteAttribute from this attribute instance
797 public ObsoleteAttribute
GetObsoleteAttribute ()
799 if (pos_values
== null)
800 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
801 // But because a lot of attribute class code must be rewritten will be better to wait...
807 if (pos_values
== null || pos_values
.Length
== 0)
808 return new ObsoleteAttribute ();
810 if (pos_values
.Length
== 1)
811 return new ObsoleteAttribute ((string)pos_values
[0]);
813 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
817 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
818 /// before ApplyAttribute. We need to resolve the arguments.
819 /// This situation occurs when class deps is differs from Emit order.
821 public bool GetClsCompliantAttributeValue ()
823 if (pos_values
== null)
824 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
825 // But because a lot of attribute class code must be rewritten will be better to wait...
831 return (bool)pos_values
[0];
834 public Type
GetCoClassAttributeValue ()
836 if (pos_values
== null)
842 return (Type
)pos_values
[0];
845 public bool CheckTarget ()
847 string[] valid_targets
= Owner
.ValidAttributeTargets
;
848 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
849 Target
= Owner
.AttributeTargets
;
853 // TODO: we can skip the first item
854 if (Array
.Exists (valid_targets
, i
=> i
== ExplicitTarget
)) {
855 switch (ExplicitTarget
) {
856 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
857 case "param": Target
= AttributeTargets
.Parameter
; return true;
858 case "field": Target
= AttributeTargets
.Field
; return true;
859 case "method": Target
= AttributeTargets
.Method
; return true;
860 case "property": Target
= AttributeTargets
.Property
; return true;
862 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
865 StringBuilder sb
= new StringBuilder ();
866 foreach (string s
in valid_targets
) {
870 sb
.Remove (sb
.Length
- 2, 2);
871 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
872 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
877 /// Tests permitted SecurityAction for assembly or other types
879 protected virtual bool IsSecurityActionValid (bool for_assembly
)
881 SecurityAction action
= GetSecurityActionValue ();
884 case SecurityAction
.Demand
:
885 case SecurityAction
.Assert
:
886 case SecurityAction
.Deny
:
887 case SecurityAction
.PermitOnly
:
888 case SecurityAction
.LinkDemand
:
889 case SecurityAction
.InheritanceDemand
:
894 case SecurityAction
.RequestMinimum
:
895 case SecurityAction
.RequestOptional
:
896 case SecurityAction
.RequestRefuse
:
902 Error_AttributeEmitError ("SecurityAction is out of range");
906 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
910 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
912 return (SecurityAction
)pos_values
[0];
916 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
918 /// <returns></returns>
919 public void ExtractSecurityPermissionSet (Dictionary
<SecurityAction
, PermissionSet
> permissions
)
921 Type orig_assembly_type
= null;
923 if (TypeManager
.LookupDeclSpace (Type
) != null) {
924 if (!RootContext
.StdLib
) {
925 orig_assembly_type
= Type
.GetType (Type
.FullName
);
927 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
928 if (orig_version_path
== null) {
929 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
933 if (orig_sec_assembly
== null) {
934 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
935 orig_sec_assembly
= Assembly
.LoadFile (file
);
938 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
939 if (orig_assembly_type
== null) {
940 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
941 "was not found in previous version of assembly");
947 SecurityAttribute sa
;
948 // For all non-selfreferencing security attributes we can avoid all hacks
949 if (orig_assembly_type
== null) {
950 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
952 if (prop_info_arr
!= null) {
953 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
954 PropertyInfo pi
= prop_info_arr
[i
];
955 pi
.SetValue (sa
, prop_values_arr
[i
], null);
959 // HACK: All security attributes have same ctor syntax
960 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
962 // All types are from newly created assembly but for invocation with old one we need to convert them
963 if (prop_info_arr
!= null) {
964 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
965 PropertyInfo emited_pi
= prop_info_arr
[i
];
966 // FIXME: We are missing return type filter
967 // TODO: pi can be null
968 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
);
970 object old_instance
= TypeManager
.IsEnumType (pi
.PropertyType
) ?
971 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
974 pi
.SetValue (sa
, old_instance
, null);
980 perm
= sa
.CreatePermission ();
981 SecurityAction action
= GetSecurityActionValue ();
983 // IS is correct because for corlib we are using an instance from old corlib
984 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
986 case SecurityAction
.Demand
:
987 action
= (SecurityAction
)13;
989 case SecurityAction
.LinkDemand
:
990 action
= (SecurityAction
)14;
992 case SecurityAction
.InheritanceDemand
:
993 action
= (SecurityAction
)15;
999 if (!permissions
.TryGetValue (action
, out ps
)) {
1000 if (sa
is PermissionSetAttribute
)
1001 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
1003 ps
= new PermissionSet (PermissionState
.None
);
1005 permissions
.Add (action
, ps
);
1006 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
1007 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
1008 permissions
[action
] = ps
;
1010 ps
.AddPermission (perm
);
1013 public object GetPropertyValue (string name
)
1015 if (prop_info_arr
== null)
1018 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1019 if (prop_info_arr
[i
].Name
== name
)
1020 return prop_values_arr
[i
];
1027 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1028 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1029 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1032 public UnmanagedMarshal
GetMarshal (Attributable attr
)
1034 UnmanagedType UnmanagedType
;
1035 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (UnmanagedType
))
1036 UnmanagedType
= (UnmanagedType
) System
.Enum
.ToObject (typeof (UnmanagedType
), pos_values
[0]);
1038 UnmanagedType
= (UnmanagedType
) pos_values
[0];
1040 object value = GetFieldValue ("SizeParamIndex");
1041 if (value != null && UnmanagedType
!= UnmanagedType
.LPArray
) {
1042 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1046 object o
= GetFieldValue ("ArraySubType");
1047 UnmanagedType array_sub_type
= o
== null ? (UnmanagedType
) 0x50 /* NATIVE_MAX */ : (UnmanagedType
) o
;
1049 switch (UnmanagedType
) {
1050 case UnmanagedType
.CustomMarshaler
: {
1051 MethodInfo define_custom
= typeof (UnmanagedMarshal
).GetMethod ("DefineCustom",
1052 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1053 if (define_custom
== null) {
1054 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1058 object [] args
= new object [4];
1059 args
[0] = GetFieldValue ("MarshalTypeRef");
1060 args
[1] = GetFieldValue ("MarshalCookie");
1061 args
[2] = GetFieldValue ("MarshalType");
1062 args
[3] = Guid
.Empty
;
1063 return (UnmanagedMarshal
) define_custom
.Invoke (null, args
);
1065 case UnmanagedType
.LPArray
: {
1066 object size_const
= GetFieldValue ("SizeConst");
1067 object size_param_index
= GetFieldValue ("SizeParamIndex");
1069 if ((size_const
!= null) || (size_param_index
!= null)) {
1070 MethodInfo define_array
= typeof (UnmanagedMarshal
).GetMethod ("DefineLPArrayInternal",
1071 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1072 if (define_array
== null) {
1073 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1077 object [] args
= new object [3];
1078 args
[0] = array_sub_type
;
1079 args
[1] = size_const
== null ? -1 : size_const
;
1080 args
[2] = size_param_index
== null ? -1 : size_param_index
;
1081 return (UnmanagedMarshal
) define_array
.Invoke (null, args
);
1084 return UnmanagedMarshal
.DefineLPArray (array_sub_type
);
1086 case UnmanagedType
.SafeArray
:
1087 return UnmanagedMarshal
.DefineSafeArray (array_sub_type
);
1089 case UnmanagedType
.ByValArray
:
1090 FieldBase fm
= attr
as FieldBase
;
1092 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1095 return UnmanagedMarshal
.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1097 case UnmanagedType
.ByValTStr
:
1098 return UnmanagedMarshal
.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1101 return UnmanagedMarshal
.DefineUnmanagedMarshal (UnmanagedType
);
1105 object GetFieldValue (string name
)
1108 if (field_info_arr
== null)
1111 foreach (FieldInfo fi
in field_info_arr
) {
1112 if (fi
.Name
== name
)
1113 return GetValue (field_values_arr
[i
]);
1119 static object GetValue (object value)
1121 if (value is EnumConstant
)
1122 return ((EnumConstant
) value).GetValue ();
1129 public CharSet
GetCharSetValue ()
1131 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1134 public bool HasField (string fieldName
)
1136 if (field_info_arr
== null)
1139 foreach (FieldInfo fi
in field_info_arr
) {
1140 if (fi
.Name
== fieldName
)
1147 public bool IsInternalMethodImplAttribute
{
1149 if (Type
!= PredefinedAttributes
.Get
.MethodImpl
)
1152 MethodImplOptions options
;
1153 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1154 options
= (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1156 options
= (MethodImplOptions
)pos_values
[0];
1158 return (options
& MethodImplOptions
.InternalCall
) != 0;
1162 public LayoutKind
GetLayoutKindValue ()
1164 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1165 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1167 return (LayoutKind
)pos_values
[0];
1170 public object GetParameterDefaultValue ()
1172 return pos_values
[0];
1175 public override bool Equals (object obj
)
1177 Attribute a
= obj
as Attribute
;
1181 return Type
== a
.Type
&& Target
== a
.Target
;
1184 public override int GetHashCode ()
1186 return type
.GetHashCode () ^ Target
.GetHashCode ();
1190 /// Emit attribute for Attributable symbol
1192 public void Emit (Dictionary
<Attribute
, List
<Attribute
>> allEmitted
)
1194 CustomAttributeBuilder cb
= Resolve ();
1198 AttributeUsageAttribute usage_attr
= GetAttributeUsage (Type
);
1199 if ((usage_attr
.ValidOn
& Target
) == 0) {
1200 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1201 "It is valid on `{1}' declarations only",
1202 GetSignatureForError (), GetValidTargets ());
1206 var predefined
= PredefinedAttributes
.Get
;
1209 foreach (Attributable target
in targets
)
1210 target
.ApplyAttributeBuilder (this, cb
, predefined
);
1211 } catch (Exception e
) {
1212 Error_AttributeEmitError (e
.Message
);
1216 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1217 if (allEmitted
.ContainsKey (this)) {
1218 var a
= allEmitted
[this];
1220 a
= new List
<Attribute
> (2);
1221 allEmitted
[this] = a
;
1225 allEmitted
.Add (this, null);
1229 if (!RootContext
.VerifyClsCompliance
)
1232 // Here we are testing attribute arguments for array usage (error 3016)
1233 if (Owner
.IsClsComplianceRequired ()) {
1234 if (PosArguments
!= null)
1235 PosArguments
.CheckArrayAsAttribute (context
.Compiler
);
1237 if (NamedArguments
== null)
1240 NamedArguments
.CheckArrayAsAttribute (context
.Compiler
);
1244 private Expression
GetValue ()
1246 if (PosArguments
== null || PosArguments
.Count
< 1)
1249 return PosArguments
[0].Expr
;
1252 public string GetString ()
1254 Expression e
= GetValue ();
1255 if (e
is StringConstant
)
1256 return ((StringConstant
)e
).Value
;
1260 public bool GetBoolean ()
1262 Expression e
= GetValue ();
1263 if (e
is BoolConstant
)
1264 return ((BoolConstant
)e
).Value
;
1268 public Type
GetArgumentType ()
1270 TypeOf e
= GetValue () as TypeOf
;
1273 return e
.TypeArgument
;
1276 public override Expression
CreateExpressionTree (ResolveContext ec
)
1278 throw new NotSupportedException ("ET");
1281 protected override Expression
DoResolve (ResolveContext ec
)
1283 throw new NotImplementedException ();
1286 public override void Emit (EmitContext ec
)
1288 throw new NotImplementedException ();
1294 /// For global attributes (assembly, module) we need special handling.
1295 /// Attributes can be located in the several files
1297 public class GlobalAttribute
: Attribute
1299 public readonly NamespaceEntry ns
;
1301 public GlobalAttribute (NamespaceEntry ns
, string target
, ATypeNameExpression expression
,
1302 Arguments
[] args
, Location loc
, bool nameEscaped
):
1303 base (target
, expression
, args
, loc
, nameEscaped
)
1308 public override void AttachTo (Attributable target
, IMemberContext context
)
1310 if (ExplicitTarget
== "assembly") {
1311 base.AttachTo (CodeGen
.Assembly
, context
);
1315 if (ExplicitTarget
== "module") {
1316 base.AttachTo (RootContext
.ToplevelTypes
, context
);
1320 throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget
);
1325 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1326 // each time a new file is parsed. However, we need to use the NamespaceEntry
1327 // in effect where the attribute was used. Since code elsewhere cannot assume
1328 // that the NamespaceEntry is right, just overwrite it.
1330 // Precondition: RootContext.ToplevelTypes == null
1332 if (RootContext
.ToplevelTypes
.NamespaceEntry
!= null)
1333 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1335 RootContext
.ToplevelTypes
.NamespaceEntry
= ns
;
1338 protected override bool IsSecurityActionValid (bool for_assembly
)
1340 return base.IsSecurityActionValid (true);
1345 RootContext
.ToplevelTypes
.NamespaceEntry
= null;
1348 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IMemberContext ec
)
1352 return base.ResolveAsTypeTerminal (expr
, ec
);
1359 protected override MethodSpec
ResolveConstructor (ResolveContext ec
)
1363 return base.ResolveConstructor (ec
);
1370 protected override bool ResolveNamedArguments (ResolveContext ec
)
1374 return base.ResolveNamedArguments (ec
);
1382 public class Attributes
{
1383 public readonly List
<Attribute
> Attrs
;
1385 public Attributes (Attribute a
)
1387 Attrs
= new List
<Attribute
> ();
1391 public Attributes (List
<Attribute
> attrs
)
1396 public void AddAttributes (List
<Attribute
> attrs
)
1398 Attrs
.AddRange (attrs
);
1401 public void AttachTo (Attributable attributable
, IMemberContext context
)
1403 foreach (Attribute a
in Attrs
)
1404 a
.AttachTo (attributable
, context
);
1407 public Attributes
Clone ()
1409 var al
= new List
<Attribute
> (Attrs
.Count
);
1410 foreach (Attribute a
in Attrs
)
1411 al
.Add (a
.Clone ());
1413 return new Attributes (al
);
1417 /// Checks whether attribute target is valid for the current element
1419 public bool CheckTargets ()
1421 foreach (Attribute a
in Attrs
) {
1422 if (!a
.CheckTarget ())
1428 public Attribute
Search (PredefinedAttribute t
)
1430 foreach (Attribute a
in Attrs
) {
1431 if (a
.ResolveType () == t
)
1438 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1440 public Attribute
[] SearchMulti (PredefinedAttribute t
)
1442 List
<Attribute
> ar
= null;
1444 foreach (Attribute a
in Attrs
) {
1445 if (a
.ResolveType () == t
) {
1447 ar
= new List
<Attribute
> (Attrs
.Count
);
1452 return ar
== null ? null : ar
.ToArray ();
1459 Dictionary
<Attribute
, List
<Attribute
>> ld
= Attrs
.Count
> 1 ? new Dictionary
<Attribute
, List
<Attribute
>> () : null;
1461 foreach (Attribute a
in Attrs
)
1464 if (ld
== null || ld
.Count
== 0)
1467 foreach (var d
in ld
) {
1468 if (d
.Value
== null)
1471 Attribute a
= d
.Key
;
1473 foreach (Attribute collision
in d
.Value
)
1474 a
.Report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1476 a
.Report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times",
1477 a
.GetSignatureForError ());
1481 public bool Contains (PredefinedAttribute t
)
1483 return Search (t
) != null;
1488 /// Helper class for attribute verification routine.
1490 sealed class AttributeTester
1492 static Dictionary
<Type
, bool> analyzed_types
;
1493 static Dictionary
<Type
, ObsoleteAttribute
> analyzed_types_obsolete
;
1494 static Dictionary
<MemberInfo
, ObsoleteAttribute
> analyzed_member_obsolete
;
1495 static Dictionary
<MethodBase
, bool> analyzed_method_excluded
;
1496 // static Dictionary<FieldInfo, IFixedBuffer> fixed_buffer_cache;
1498 static AttributeTester ()
1503 private AttributeTester ()
1507 public static void Reset ()
1509 analyzed_types
= new Dictionary
<Type
, bool> (ReferenceEquality
<Type
>.Default
);
1510 analyzed_types_obsolete
= new Dictionary
<Type
, ObsoleteAttribute
> (ReferenceEquality
<Type
>.Default
);
1511 analyzed_member_obsolete
= new Dictionary
<MemberInfo
, ObsoleteAttribute
> (ReferenceEquality
<MemberInfo
>.Default
);
1512 analyzed_method_excluded
= new Dictionary
<MethodBase
, bool> (ReferenceEquality
<MethodBase
>.Default
);
1513 // fixed_buffer_cache = new Dictionary<FieldInfo, IFixedBuffer> (ReferenceEquality<FieldInfo>.Default);
1516 public enum Result
{
1523 /// Returns true if parameters of two compared methods are CLS-Compliant.
1524 /// It tests differing only in ref or out, or in array rank.
1526 public static Result
AreOverloadedMethodParamsClsCompliant (AParametersCollection pa
, AParametersCollection pb
)
1528 Type
[] types_a
= pa
.Types
;
1529 Type
[] types_b
= pb
.Types
;
1530 if (types_a
== null || types_b
== null)
1533 if (types_a
.Length
!= types_b
.Length
)
1536 Result result
= Result
.Ok
;
1537 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1538 Type aType
= types_a
[i
];
1539 Type bType
= types_b
[i
];
1541 if (aType
.IsArray
&& bType
.IsArray
) {
1542 Type a_el_type
= TypeManager
.GetElementType (aType
);
1543 Type b_el_type
= TypeManager
.GetElementType (bType
);
1544 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1545 result
= Result
.RefOutArrayError
;
1549 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1550 result
= Result
.ArrayArrayError
;
1558 const Parameter
.Modifier out_ref_mod
= (Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
1559 if ((pa
.FixedParameters
[i
].ModFlags
& out_ref_mod
) != (pb
.FixedParameters
[i
].ModFlags
& out_ref_mod
))
1560 result
= Result
.RefOutArrayError
;
1566 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1568 public static bool IsClsCompliant (Type type
)
1574 if (analyzed_types
.TryGetValue (type
, out result
))
1577 if (type
.IsPointer
) {
1578 analyzed_types
.Add (type
, false);
1583 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1584 } else if (TypeManager
.IsNullableType (type
)) {
1585 result
= IsClsCompliant (TypeManager
.TypeToCoreType (TypeManager
.GetTypeArguments (type
) [0]));
1587 result
= AnalyzeTypeCompliance (type
);
1589 analyzed_types
.Add (type
, result
);
1593 public static void VerifyModulesClsCompliance (CompilerContext ctx
)
1595 Module
[] modules
= GlobalRootNamespace
.Instance
.Modules
;
1596 if (modules
== null)
1599 // The first module is generated assembly
1600 for (int i
= 1; i
< modules
.Length
; ++i
) {
1601 Module module
= modules
[i
];
1602 if (!GetClsCompliantAttributeValue (module
, null)) {
1603 ctx
.Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1604 "to match the assembly", module
.Name
);
1610 public static Type
GetImportedIgnoreCaseClsType (string name
)
1612 foreach (Assembly a
in GlobalRootNamespace
.Instance
.Assemblies
) {
1613 Type t
= a
.GetType (name
, false, true);
1617 if (IsClsCompliant (t
))
1623 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider
, Assembly a
)
1625 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CLSCompliant
;
1629 object[] cls_attr
= attribute_provider
.GetCustomAttributes (pa
.Type
, false);
1630 if (cls_attr
.Length
== 0) {
1634 return GetClsCompliantAttributeValue (a
, null);
1637 return ((CLSCompliantAttribute
)cls_attr
[0]).IsCompliant
;
1640 static bool AnalyzeTypeCompliance (Type type
)
1642 type
= TypeManager
.DropGenericTypeArguments (type
);
1643 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1645 return ds
.IsClsComplianceRequired ();
1648 if (TypeManager
.IsGenericParameter (type
))
1651 return GetClsCompliantAttributeValue (type
, type
.Assembly
);
1655 /// Returns instance of ObsoleteAttribute when type is obsolete
1657 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1659 ObsoleteAttribute result
;
1660 if (analyzed_types_obsolete
.TryGetValue (type
, out result
))
1663 if (TypeManager
.HasElementType (type
)) {
1664 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1665 } else if (TypeManager
.IsGenericParameter (type
))
1666 result
= null; // TODO: throw new NotSupportedException ()
1667 else if (TypeManager
.IsGenericType (type
) && !TypeManager
.IsGenericTypeDefinition (type
)) {
1668 return GetObsoleteAttribute (TypeManager
.DropGenericTypeArguments (type
));
1670 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1672 // Type is external, we can get attribute directly
1673 if (type_ds
== null) {
1674 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1676 object[] attribute
= type
.GetCustomAttributes (pa
.Type
, false);
1677 if (attribute
.Length
== 1)
1678 result
= (ObsoleteAttribute
) attribute
[0];
1681 result
= type_ds
.GetObsoleteAttribute ();
1685 // Cannot use .Add because of corlib bootstrap
1686 analyzed_types_obsolete
[type
] = result
;
1691 /// Returns instance of ObsoleteAttribute when method is obsolete
1693 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1695 IMethodData mc
= TypeManager
.GetMethod (mb
);
1697 return mc
.GetObsoleteAttribute ();
1699 // compiler generated methods are not registered by AddMethod
1700 if (mb
.DeclaringType
is TypeBuilder
)
1703 MemberInfo mi
= TypeManager
.GetPropertyFromAccessor (mb
);
1705 return GetMemberObsoleteAttribute (mi
);
1707 mi
= TypeManager
.GetEventFromAccessor (mb
);
1709 return GetMemberObsoleteAttribute (mi
);
1711 return GetMemberObsoleteAttribute (mb
);
1715 /// Returns instance of ObsoleteAttribute when member is obsolete
1717 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1719 ObsoleteAttribute oa
;
1720 if (analyzed_member_obsolete
.TryGetValue (mi
, out oa
))
1723 if ((mi
.DeclaringType
is TypeBuilder
) || TypeManager
.IsGenericType (mi
.DeclaringType
))
1726 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1730 oa
= System
.Attribute
.GetCustomAttribute (mi
, pa
.Type
, false) as ObsoleteAttribute
;
1731 analyzed_member_obsolete
.Add (mi
, oa
);
1736 /// Common method for Obsolete error/warning reporting.
1738 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
, Report Report
)
1741 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1745 if (oa
.Message
== null || oa
.Message
.Length
== 0) {
1746 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1749 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1752 public static bool IsConditionalMethodExcluded (MethodBase mb
, Location loc
)
1755 if (analyzed_method_excluded
.TryGetValue (mb
, out excluded
))
1758 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1762 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (pa
.Type
, true)
1763 as ConditionalAttribute
[];
1764 if (attrs
.Length
== 0) {
1765 analyzed_method_excluded
.Add (mb
, false);
1769 foreach (ConditionalAttribute a
in attrs
) {
1770 if (loc
.CompilationUnit
.IsConditionalDefined (a
.ConditionString
)) {
1771 analyzed_method_excluded
.Add (mb
, false);
1776 analyzed_method_excluded
.Add (mb
, true);
1781 /// Analyzes class whether it has attribute which has ConditionalAttribute
1782 /// and its condition is not defined.
1784 public static bool IsAttributeExcluded (Type type
, Location loc
)
1789 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1791 // TODO: add caching
1792 // TODO: merge all Type bases attribute caching to one cache to save memory
1793 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1794 if (class_decl
== null && pa
.IsDefined
) {
1795 object[] attributes
= type
.GetCustomAttributes (pa
.Type
, false);
1796 foreach (ConditionalAttribute ca
in attributes
) {
1797 if (loc
.CompilationUnit
.IsConditionalDefined (ca
.ConditionString
))
1800 return attributes
.Length
> 0;
1803 return class_decl
.IsExcluded ();
1806 public static Type
GetCoClassAttribute (Type type
)
1808 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1809 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CoClass
;
1814 object[] o
= type
.GetCustomAttributes (pa
.Type
, false);
1817 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1820 if (tc
.OptAttributes
== null)
1823 Attribute a
= tc
.OptAttributes
.Search (pa
);
1827 return a
.GetCoClassAttributeValue ();
1831 public class PredefinedAttributes
1834 public readonly PredefinedAttribute ParamArray
;
1835 public readonly PredefinedAttribute Out
;
1838 public readonly PredefinedAttribute Obsolete
;
1839 public readonly PredefinedAttribute DllImport
;
1840 public readonly PredefinedAttribute MethodImpl
;
1841 public readonly PredefinedAttribute MarshalAs
;
1842 public readonly PredefinedAttribute In
;
1843 public readonly PredefinedAttribute IndexerName
;
1844 public readonly PredefinedAttribute Conditional
;
1845 public readonly PredefinedAttribute CLSCompliant
;
1846 public readonly PredefinedAttribute Security
;
1847 public readonly PredefinedAttribute Required
;
1848 public readonly PredefinedAttribute Guid
;
1849 public readonly PredefinedAttribute AssemblyCulture
;
1850 public readonly PredefinedAttribute AssemblyVersion
;
1851 public readonly PredefinedAttribute ComImport
;
1852 public readonly PredefinedAttribute CoClass
;
1853 public readonly PredefinedAttribute AttributeUsage
;
1854 public readonly PredefinedAttribute DefaultParameterValue
;
1855 public readonly PredefinedAttribute OptionalParameter
;
1858 public readonly PredefinedAttribute DefaultCharset
;
1859 public readonly PredefinedAttribute TypeForwarder
;
1860 public readonly PredefinedAttribute FixedBuffer
;
1861 public readonly PredefinedAttribute CompilerGenerated
;
1862 public readonly PredefinedAttribute InternalsVisibleTo
;
1863 public readonly PredefinedAttribute RuntimeCompatibility
;
1864 public readonly PredefinedAttribute DebuggerHidden
;
1865 public readonly PredefinedAttribute UnsafeValueType
;
1868 public readonly PredefinedAttribute Extension
;
1871 public readonly PredefinedAttribute Dynamic
;
1872 public readonly PredefinedAttribute DynamicTransform
; // DynamicAttribute with transform arguments
1875 // Optional types which are used as types and for member lookup
1877 public readonly PredefinedAttribute DefaultMember
;
1878 public readonly PredefinedAttribute DecimalConstant
;
1879 public readonly PredefinedAttribute StructLayout
;
1880 public readonly PredefinedAttribute FieldOffset
;
1882 public static PredefinedAttributes Get
= new PredefinedAttributes ();
1884 private PredefinedAttributes ()
1886 ParamArray
= new PredefinedAttribute ("System", "ParamArrayAttribute");
1887 Out
= new PredefinedAttribute ("System.Runtime.InteropServices", "OutAttribute");
1889 Obsolete
= new PredefinedAttribute ("System", "ObsoleteAttribute");
1890 DllImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "DllImportAttribute");
1891 MethodImpl
= new PredefinedAttribute ("System.Runtime.CompilerServices", "MethodImplAttribute");
1892 MarshalAs
= new PredefinedAttribute ("System.Runtime.InteropServices", "MarshalAsAttribute");
1893 In
= new PredefinedAttribute ("System.Runtime.InteropServices", "InAttribute");
1894 IndexerName
= new PredefinedAttribute ("System.Runtime.CompilerServices", "IndexerNameAttribute");
1895 Conditional
= new PredefinedAttribute ("System.Diagnostics", "ConditionalAttribute");
1896 CLSCompliant
= new PredefinedAttribute ("System", "CLSCompliantAttribute");
1897 Security
= new PredefinedAttribute ("System.Security.Permissions", "SecurityAttribute");
1898 Required
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1899 Guid
= new PredefinedAttribute ("System.Runtime.InteropServices", "GuidAttribute");
1900 AssemblyCulture
= new PredefinedAttribute ("System.Reflection", "AssemblyCultureAttribute");
1901 AssemblyVersion
= new PredefinedAttribute ("System.Reflection", "AssemblyVersionAttribute");
1902 ComImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "ComImportAttribute");
1903 CoClass
= new PredefinedAttribute ("System.Runtime.InteropServices", "CoClassAttribute");
1904 AttributeUsage
= new PredefinedAttribute ("System", "AttributeUsageAttribute");
1905 DefaultParameterValue
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1906 OptionalParameter
= new PredefinedAttribute ("System.Runtime.InteropServices", "OptionalAttribute");
1908 DefaultCharset
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultCharSetAttribute");
1909 TypeForwarder
= new PredefinedAttribute ("System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1910 FixedBuffer
= new PredefinedAttribute ("System.Runtime.CompilerServices", "FixedBufferAttribute");
1911 CompilerGenerated
= new PredefinedAttribute ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1912 InternalsVisibleTo
= new PredefinedAttribute ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1913 RuntimeCompatibility
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1914 DebuggerHidden
= new PredefinedAttribute ("System.Diagnostics", "DebuggerHiddenAttribute");
1915 UnsafeValueType
= new PredefinedAttribute ("System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1917 Extension
= new PredefinedAttribute ("System.Runtime.CompilerServices", "ExtensionAttribute");
1919 Dynamic
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DynamicAttribute");
1920 DynamicTransform
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DynamicAttribute");
1922 DefaultMember
= new PredefinedAttribute ("System.Reflection", "DefaultMemberAttribute");
1923 DecimalConstant
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DecimalConstantAttribute");
1924 StructLayout
= new PredefinedAttribute ("System.Runtime.InteropServices", "StructLayoutAttribute");
1925 FieldOffset
= new PredefinedAttribute ("System.Runtime.InteropServices", "FieldOffsetAttribute");
1928 public void Initialize (CompilerContext ctx
)
1930 foreach (FieldInfo fi
in GetType ().GetFields (BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
)) {
1931 ((PredefinedAttribute
) fi
.GetValue (this)).Initialize (ctx
, true);
1935 public static void Reset ()
1937 Get
= new PredefinedAttributes ();
1941 public class PredefinedAttribute
1944 CustomAttributeBuilder cab
;
1945 ConstructorInfo ctor
;
1946 readonly string ns
, name
;
1947 CompilerContext compiler
;
1949 static readonly Type NotFound
= typeof (PredefinedAttribute
);
1951 public PredefinedAttribute (string ns
, string name
)
1957 public static bool operator == (Type type
, PredefinedAttribute pa
)
1959 return type
== pa
.type
;
1962 public static bool operator != (Type type
, PredefinedAttribute pa
)
1964 return type
!= pa
.type
;
1967 public ConstructorInfo Constructor
{
1968 get { return ctor; }
1971 public override int GetHashCode ()
1973 return base.GetHashCode ();
1976 public string GetSignatureForError ()
1978 return ns
+ "." + name
;
1981 public override bool Equals (object obj
)
1983 throw new NotSupportedException ();
1986 public void EmitAttribute (ConstructorBuilder builder
)
1988 if (ResolveBuilder ())
1989 builder
.SetCustomAttribute (cab
);
1992 public void EmitAttribute (MethodBuilder builder
)
1994 if (ResolveBuilder ())
1995 builder
.SetCustomAttribute (cab
);
1998 public void EmitAttribute (PropertyBuilder builder
)
2000 if (ResolveBuilder ())
2001 builder
.SetCustomAttribute (cab
);
2004 public void EmitAttribute (FieldBuilder builder
)
2006 if (ResolveBuilder ())
2007 builder
.SetCustomAttribute (cab
);
2010 public void EmitAttribute (TypeBuilder builder
)
2012 if (ResolveBuilder ())
2013 builder
.SetCustomAttribute (cab
);
2016 public void EmitAttribute (AssemblyBuilder builder
)
2018 if (ResolveBuilder ())
2019 builder
.SetCustomAttribute (cab
);
2022 public void EmitAttribute (ParameterBuilder builder
)
2024 if (ResolveBuilder ())
2025 builder
.SetCustomAttribute (cab
);
2028 public bool IsDefined
{
2029 get { return type != null && type != NotFound; }
2032 public void Initialize (CompilerContext ctx
, bool canFail
)
2034 this.compiler
= ctx
;
2038 public bool Resolve (bool canFail
)
2047 type
= TypeManager
.CoreLookupType (compiler
, ns
, name
, MemberKind
.Class
, !canFail
);
2056 bool ResolveBuilder ()
2062 // Handle all parameter-less attributes as optional
2064 if (!Resolve (true))
2067 ConstructorInfo ci
= TypeManager
.GetPredefinedConstructor (type
, Location
.Null
, Type
.EmptyTypes
);
2071 cab
= new CustomAttributeBuilder (ci
, new object[0]);
2075 public bool ResolveConstructor (Location loc
, params Type
[] argType
)
2078 throw new InternalErrorException ("Predefined ctor redefined");
2080 if (!Resolve (false))
2083 ctor
= TypeManager
.GetPredefinedConstructor (type
, loc
, argType
);
2084 return ctor
!= null;
2088 get { return type; }