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 ());
206 /// This is rather hack. We report many emit attribute error with same error to be compatible with
207 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
209 public void Error_AttributeEmitError (string inner
)
211 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
212 TypeManager
.CSharpName (Type
), inner
);
215 public void Error_InvalidSecurityParent ()
217 Error_AttributeEmitError ("it is attached to invalid parent");
226 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IMemberContext ec
)
228 return expr
.ResolveAsTypeTerminal (ec
, false);
231 Type
ResolvePossibleAttributeType (ATypeNameExpression expr
, ref bool is_attr
)
233 TypeExpr te
= ResolveAsTypeTerminal (expr
, context
);
238 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
241 Report
.SymbolRelatedToPreviousError (t
);
242 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
248 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
250 void ResolveAttributeType ()
252 SessionReportPrinter resolve_printer
= new SessionReportPrinter ();
253 ReportPrinter prev_recorder
= context
.Compiler
.Report
.SetPrinter (resolve_printer
);
255 bool t1_is_attr
= false;
256 bool t2_is_attr
= false;
258 ATypeNameExpression expanded
= null;
261 t1
= ResolvePossibleAttributeType (expression
, ref t1_is_attr
);
266 expanded
= (ATypeNameExpression
) expression
.Clone (null);
267 expanded
.Name
+= "Attribute";
269 t2
= ResolvePossibleAttributeType (expanded
, ref t2_is_attr
);
272 resolve_printer
.EndSession ();
274 context
.Compiler
.Report
.SetPrinter (prev_recorder
);
277 if (t1_is_attr
&& t2_is_attr
) {
278 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{1}' and `{2}'. Use either `@{0}' or `{0}Attribute'",
279 GetSignatureForError (), expression
.GetSignatureForError (), expanded
.GetSignatureForError ());
280 resolve_error
= true;
294 resolve_printer
.Merge (prev_recorder
);
295 resolve_error
= true;
298 public virtual Type
ResolveType ()
300 if (Type
== null && !resolve_error
)
301 ResolveAttributeType ();
305 public override string GetSignatureForError ()
308 return TypeManager
.CSharpName (Type
);
310 return expression
.GetSignatureForError ();
313 public bool HasSecurityAttribute
{
315 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Security
;
316 return pa
.IsDefined
&& TypeManager
.IsSubclassOf (type
, pa
.Type
);
320 public bool IsValidSecurityAttribute ()
322 return HasSecurityAttribute
&& IsSecurityActionValid (false);
325 static bool IsValidArgumentType (Type t
)
328 t
= TypeManager
.GetElementType (t
);
330 return t
== TypeManager
.string_type
||
331 TypeManager
.IsPrimitiveType (t
) ||
332 TypeManager
.IsEnumType (t
) ||
333 t
== TypeManager
.object_type
||
334 t
== TypeManager
.type_type
;
337 // TODO: Don't use this ambiguous value
339 get { return expression.Name; }
342 void ApplyModuleCharSet ()
344 if (Type
!= PredefinedAttributes
.Get
.DllImport
)
347 if (!RootContext
.ToplevelTypes
.HasDefaultCharSet
)
350 const string CharSetEnumMember
= "CharSet";
351 if (NamedArguments
== null) {
352 NamedArguments
= new Arguments (1);
354 foreach (NamedArgument a
in NamedArguments
) {
355 if (a
.Name
.Value
== CharSetEnumMember
)
360 NamedArguments
.Add (new NamedArgument (new LocatedToken (loc
, CharSetEnumMember
),
361 Constant
.CreateConstant (typeof (CharSet
), RootContext
.ToplevelTypes
.DefaultCharSet
, Location
)));
365 get { return context.Compiler.Report; }
368 public CustomAttributeBuilder
Resolve ()
373 resolve_error
= true;
376 ResolveAttributeType ();
381 if (Type
.IsAbstract
) {
382 Report
.Error (653, Location
, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
386 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (Type
);
387 if (obsolete_attr
!= null) {
388 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, TypeManager
.CSharpName (Type
), Location
, Report
);
391 if (PosArguments
== null && NamedArguments
== null) {
392 object o
= att_cache
[Type
];
394 resolve_error
= false;
395 return (CustomAttributeBuilder
)o
;
399 ResolveContext rc
= new ResolveContext (context
, ResolveContext
.Options
.ConstantScope
);
400 ConstructorInfo ctor
= ResolveConstructor (rc
);
402 if (Type
is TypeBuilder
&&
403 TypeManager
.LookupDeclSpace (Type
).MemberCache
== null)
404 // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error.
405 // It'll be resolved again when the attached-to entity is emitted.
406 resolve_error
= false;
410 ApplyModuleCharSet ();
412 CustomAttributeBuilder cb
;
414 // SRE does not allow private ctor but we want to report all source code errors
418 if (NamedArguments
== null) {
419 cb
= new CustomAttributeBuilder (ctor
, pos_values
);
421 if (pos_values
.Length
== 0)
422 att_cache
.Add (Type
, cb
);
424 resolve_error
= false;
428 if (!ResolveNamedArguments (rc
)) {
432 cb
= new CustomAttributeBuilder (ctor
, pos_values
,
433 prop_info_arr
, prop_values_arr
,
434 field_info_arr
, field_values_arr
);
436 resolve_error
= false;
440 Error_AttributeArgumentNotValid (rc
, Location
);
445 protected virtual ConstructorInfo
ResolveConstructor (ResolveContext ec
)
447 if (PosArguments
!= null) {
449 PosArguments
.Resolve (ec
, out dynamic);
451 throw new NotImplementedException ("dynamic");
454 MethodGroupExpr mg
= MemberLookupFinal (ec
, ec
.CurrentType
,
455 Type
, ConstructorInfo
.ConstructorName
, MemberTypes
.Constructor
,
456 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
457 Location
) as MethodGroupExpr
;
460 throw new NotImplementedException ();
462 mg
= mg
.OverloadResolve (ec
, ref PosArguments
, false, Location
);
466 ConstructorInfo constructor
= (ConstructorInfo
)mg
;
467 if (PosArguments
== null) {
468 pos_values
= EmptyObject
;
472 AParametersCollection pd
= TypeManager
.GetParameterData (constructor
);
474 if (!PosArguments
.GetAttributableValue (ec
, out pos_values
))
477 // Here we do the checks which should be done by corlib or by runtime.
478 // However Zoltan doesn't like it and every Mono compiler has to do it again.
479 PredefinedAttributes pa
= PredefinedAttributes
.Get
;
480 if (Type
== pa
.Guid
) {
482 new Guid ((string)pos_values
[0]);
484 catch (Exception e
) {
485 Error_AttributeEmitError (e
.Message
);
490 if (Type
== pa
.AttributeUsage
&& (int)pos_values
[0] == 0) {
491 ec
.Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
495 if (Type
== pa
.IndexerName
|| Type
== pa
.Conditional
) {
496 string v
= pos_values
[0] as string;
497 if (!Tokenizer
.IsValidIdentifier (v
) || Tokenizer
.IsKeyword (v
)) {
498 ec
.Report
.Error (633, PosArguments
[0].Expr
.Location
,
499 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
504 if (Type
== pa
.MethodImpl
&& pos_values
.Length
== 1 &&
505 pd
.Types
[0] == TypeManager
.short_type
&&
506 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
507 Error_AttributeEmitError ("Incorrect argument value.");
514 protected virtual bool ResolveNamedArguments (ResolveContext ec
)
516 int named_arg_count
= NamedArguments
.Count
;
518 ArrayList field_infos
= new ArrayList (named_arg_count
);
519 ArrayList prop_infos
= new ArrayList (named_arg_count
);
520 ArrayList field_values
= new ArrayList (named_arg_count
);
521 ArrayList prop_values
= new ArrayList (named_arg_count
);
523 ArrayList seen_names
= new ArrayList (named_arg_count
);
525 foreach (NamedArgument a
in NamedArguments
) {
526 string name
= a
.Name
.Value
;
527 if (seen_names
.Contains (name
)) {
528 ec
.Report
.Error (643, a
.Name
.Location
, "Duplicate named attribute `{0}' argument", name
);
532 seen_names
.Add (name
);
536 Expression member
= Expression
.MemberLookup (ec
.Compiler
,
537 ec
.CurrentType
, Type
, name
,
539 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.Static
,
542 if (member
== null) {
543 member
= Expression
.MemberLookup (ec
.Compiler
, ec
.CurrentType
, Type
, name
,
544 MemberTypes
.All
, BindingFlags
.NonPublic
| BindingFlags
.Instance
| BindingFlags
.Static
,
547 if (member
!= null) {
548 ec
.Report
.SymbolRelatedToPreviousError (member
.Type
);
549 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError (), ec
.Report
);
555 Expression
.Error_TypeDoesNotContainDefinition (ec
, Location
, Type
, name
);
559 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
560 Error_InvalidNamedArgument (ec
, a
);
564 ObsoleteAttribute obsolete_attr
;
566 if (member
is PropertyExpr
) {
567 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
569 if (!pi
.CanWrite
|| !pi
.CanRead
|| pi
.GetGetMethod ().IsStatic
) {
570 ec
.Report
.SymbolRelatedToPreviousError (pi
);
571 Error_InvalidNamedArgument (ec
, a
);
575 if (!IsValidArgumentType (member
.Type
)) {
576 ec
.Report
.SymbolRelatedToPreviousError (pi
);
577 Error_InvalidNamedArgumentType (ec
, a
);
582 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
585 PropertyBase pb
= TypeManager
.GetProperty (pi
);
587 obsolete_attr
= pb
.GetObsoleteAttribute ();
589 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
591 prop_values
.Add (value);
595 FieldInfo fi
= ((FieldExpr
) member
).FieldInfo
;
597 if (fi
.IsInitOnly
|| fi
.IsStatic
) {
598 Error_InvalidNamedArgument (ec
, a
);
602 if (!IsValidArgumentType (member
.Type
)) {
603 ec
.Report
.SymbolRelatedToPreviousError (fi
);
604 Error_InvalidNamedArgumentType (ec
, a
);
609 if (!a
.Expr
.GetAttributableValue (ec
, member
.Type
, out value))
612 FieldBase fb
= TypeManager
.GetField (fi
);
614 obsolete_attr
= fb
.GetObsoleteAttribute ();
616 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
618 field_values
.Add (value);
619 field_infos
.Add (fi
);
622 if (obsolete_attr
!= null && !context
.IsObsolete
)
623 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
, Report
);
626 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
627 field_info_arr
= new FieldInfo
[field_infos
.Count
];
628 field_values_arr
= new object [field_values
.Count
];
629 prop_values_arr
= new object [prop_values
.Count
];
631 field_infos
.CopyTo (field_info_arr
, 0);
632 field_values
.CopyTo (field_values_arr
, 0);
634 prop_values
.CopyTo (prop_values_arr
, 0);
635 prop_infos
.CopyTo (prop_info_arr
, 0);
641 /// Get a string containing a list of valid targets for the attribute 'attr'
643 public string GetValidTargets ()
645 StringBuilder sb
= new StringBuilder ();
646 AttributeTargets targets
= GetAttributeUsage (Type
).ValidOn
;
648 if ((targets
& AttributeTargets
.Assembly
) != 0)
649 sb
.Append ("assembly, ");
651 if ((targets
& AttributeTargets
.Module
) != 0)
652 sb
.Append ("module, ");
654 if ((targets
& AttributeTargets
.Class
) != 0)
655 sb
.Append ("class, ");
657 if ((targets
& AttributeTargets
.Struct
) != 0)
658 sb
.Append ("struct, ");
660 if ((targets
& AttributeTargets
.Enum
) != 0)
661 sb
.Append ("enum, ");
663 if ((targets
& AttributeTargets
.Constructor
) != 0)
664 sb
.Append ("constructor, ");
666 if ((targets
& AttributeTargets
.Method
) != 0)
667 sb
.Append ("method, ");
669 if ((targets
& AttributeTargets
.Property
) != 0)
670 sb
.Append ("property, indexer, ");
672 if ((targets
& AttributeTargets
.Field
) != 0)
673 sb
.Append ("field, ");
675 if ((targets
& AttributeTargets
.Event
) != 0)
676 sb
.Append ("event, ");
678 if ((targets
& AttributeTargets
.Interface
) != 0)
679 sb
.Append ("interface, ");
681 if ((targets
& AttributeTargets
.Parameter
) != 0)
682 sb
.Append ("parameter, ");
684 if ((targets
& AttributeTargets
.Delegate
) != 0)
685 sb
.Append ("delegate, ");
687 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
688 sb
.Append ("return, ");
690 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
691 sb
.Append ("type parameter, ");
693 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
697 /// Returns AttributeUsage attribute based on types hierarchy
699 static AttributeUsageAttribute
GetAttributeUsage (Type type
)
701 AttributeUsageAttribute ua
= usage_attr_cache
[type
] as AttributeUsageAttribute
;
705 Class attr_class
= TypeManager
.LookupClass (type
);
706 PredefinedAttribute pa
= PredefinedAttributes
.Get
.AttributeUsage
;
708 if (attr_class
== null) {
710 return new AttributeUsageAttribute (0);
712 object[] usage_attr
= type
.GetCustomAttributes (pa
.Type
, true);
713 ua
= (AttributeUsageAttribute
)usage_attr
[0];
714 usage_attr_cache
.Add (type
, ua
);
719 if (attr_class
.OptAttributes
!= null)
720 a
= attr_class
.OptAttributes
.Search (pa
);
723 if (attr_class
.TypeBuilder
.BaseType
!= TypeManager
.attribute_type
)
724 ua
= GetAttributeUsage (attr_class
.TypeBuilder
.BaseType
);
726 ua
= DefaultUsageAttribute
;
728 ua
= a
.GetAttributeUsageAttribute ();
731 usage_attr_cache
.Add (type
, ua
);
735 AttributeUsageAttribute
GetAttributeUsageAttribute ()
737 if (pos_values
== null)
738 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
739 // But because a lot of attribute class code must be rewritten will be better to wait...
743 return DefaultUsageAttribute
;
745 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
747 object field
= GetPropertyValue ("AllowMultiple");
749 usage_attribute
.AllowMultiple
= (bool)field
;
751 field
= GetPropertyValue ("Inherited");
753 usage_attribute
.Inherited
= (bool)field
;
755 return usage_attribute
;
759 /// Returns custom name of indexer
761 public string GetIndexerAttributeValue ()
763 if (pos_values
== null)
764 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
765 // But because a lot of attribute class code must be rewritten will be better to wait...
771 return pos_values
[0] as string;
775 /// Returns condition of ConditionalAttribute
777 public string GetConditionalAttributeValue ()
779 if (pos_values
== null)
780 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
781 // But because a lot of attribute class code must be rewritten will be better to wait...
787 return (string)pos_values
[0];
791 /// Creates the instance of ObsoleteAttribute from this attribute instance
793 public ObsoleteAttribute
GetObsoleteAttribute ()
795 if (pos_values
== null)
796 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
797 // But because a lot of attribute class code must be rewritten will be better to wait...
803 if (pos_values
== null || pos_values
.Length
== 0)
804 return new ObsoleteAttribute ();
806 if (pos_values
.Length
== 1)
807 return new ObsoleteAttribute ((string)pos_values
[0]);
809 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
813 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
814 /// before ApplyAttribute. We need to resolve the arguments.
815 /// This situation occurs when class deps is differs from Emit order.
817 public bool GetClsCompliantAttributeValue ()
819 if (pos_values
== null)
820 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
821 // But because a lot of attribute class code must be rewritten will be better to wait...
827 return (bool)pos_values
[0];
830 public Type
GetCoClassAttributeValue ()
832 if (pos_values
== null)
838 return (Type
)pos_values
[0];
841 public bool CheckTarget ()
843 string[] valid_targets
= Owner
.ValidAttributeTargets
;
844 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
845 Target
= Owner
.AttributeTargets
;
849 // TODO: we can skip the first item
850 if (((IList
) valid_targets
).Contains (ExplicitTarget
)) {
851 switch (ExplicitTarget
) {
852 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
853 case "param": Target
= AttributeTargets
.Parameter
; return true;
854 case "field": Target
= AttributeTargets
.Field
; return true;
855 case "method": Target
= AttributeTargets
.Method
; return true;
856 case "property": Target
= AttributeTargets
.Property
; return true;
858 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
861 StringBuilder sb
= new StringBuilder ();
862 foreach (string s
in valid_targets
) {
866 sb
.Remove (sb
.Length
- 2, 2);
867 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
868 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
873 /// Tests permitted SecurityAction for assembly or other types
875 protected virtual bool IsSecurityActionValid (bool for_assembly
)
877 SecurityAction action
= GetSecurityActionValue ();
880 case SecurityAction
.Demand
:
881 case SecurityAction
.Assert
:
882 case SecurityAction
.Deny
:
883 case SecurityAction
.PermitOnly
:
884 case SecurityAction
.LinkDemand
:
885 case SecurityAction
.InheritanceDemand
:
890 case SecurityAction
.RequestMinimum
:
891 case SecurityAction
.RequestOptional
:
892 case SecurityAction
.RequestRefuse
:
898 Error_AttributeEmitError ("SecurityAction is out of range");
902 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
906 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
908 return (SecurityAction
)pos_values
[0];
912 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
914 /// <returns></returns>
915 public void ExtractSecurityPermissionSet (ListDictionary permissions
)
917 Type orig_assembly_type
= null;
919 if (TypeManager
.LookupDeclSpace (Type
) != null) {
920 if (!RootContext
.StdLib
) {
921 orig_assembly_type
= Type
.GetType (Type
.FullName
);
923 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
924 if (orig_version_path
== null) {
925 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
929 if (orig_sec_assembly
== null) {
930 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
931 orig_sec_assembly
= Assembly
.LoadFile (file
);
934 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
935 if (orig_assembly_type
== null) {
936 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
937 "was not found in previous version of assembly");
943 SecurityAttribute sa
;
944 // For all non-selfreferencing security attributes we can avoid all hacks
945 if (orig_assembly_type
== null) {
946 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
948 if (prop_info_arr
!= null) {
949 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
950 PropertyInfo pi
= prop_info_arr
[i
];
951 pi
.SetValue (sa
, prop_values_arr
[i
], null);
955 // HACK: All security attributes have same ctor syntax
956 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
958 // All types are from newly created assembly but for invocation with old one we need to convert them
959 if (prop_info_arr
!= null) {
960 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
961 PropertyInfo emited_pi
= prop_info_arr
[i
];
962 // FIXME: We are missing return type filter
963 // TODO: pi can be null
964 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
);
966 object old_instance
= TypeManager
.IsEnumType (pi
.PropertyType
) ?
967 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
970 pi
.SetValue (sa
, old_instance
, null);
976 perm
= sa
.CreatePermission ();
977 SecurityAction action
= GetSecurityActionValue ();
979 // IS is correct because for corlib we are using an instance from old corlib
980 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
982 case SecurityAction
.Demand
:
983 action
= (SecurityAction
)13;
985 case SecurityAction
.LinkDemand
:
986 action
= (SecurityAction
)14;
988 case SecurityAction
.InheritanceDemand
:
989 action
= (SecurityAction
)15;
994 PermissionSet ps
= (PermissionSet
)permissions
[action
];
996 if (sa
is PermissionSetAttribute
)
997 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
999 ps
= new PermissionSet (PermissionState
.None
);
1001 permissions
.Add (action
, ps
);
1002 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
1003 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
1004 permissions
[action
] = ps
;
1006 ps
.AddPermission (perm
);
1009 public object GetPropertyValue (string name
)
1011 if (prop_info_arr
== null)
1014 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1015 if (prop_info_arr
[i
].Name
== name
)
1016 return prop_values_arr
[i
];
1023 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1024 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1025 // However, we can't, since it appears that the .NET 1.1 SRE hangs when given a MarshalAsAttribute.
1028 public UnmanagedMarshal
GetMarshal (Attributable attr
)
1030 UnmanagedType UnmanagedType
;
1031 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (UnmanagedType
))
1032 UnmanagedType
= (UnmanagedType
) System
.Enum
.ToObject (typeof (UnmanagedType
), pos_values
[0]);
1034 UnmanagedType
= (UnmanagedType
) pos_values
[0];
1036 object value = GetFieldValue ("SizeParamIndex");
1037 if (value != null && UnmanagedType
!= UnmanagedType
.LPArray
) {
1038 Error_AttributeEmitError ("SizeParamIndex field is not valid for the specified unmanaged type");
1042 object o
= GetFieldValue ("ArraySubType");
1043 UnmanagedType array_sub_type
= o
== null ? (UnmanagedType
) 0x50 /* NATIVE_MAX */ : (UnmanagedType
) o
;
1045 switch (UnmanagedType
) {
1046 case UnmanagedType
.CustomMarshaler
: {
1047 MethodInfo define_custom
= typeof (UnmanagedMarshal
).GetMethod ("DefineCustom",
1048 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1049 if (define_custom
== null) {
1050 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1054 object [] args
= new object [4];
1055 args
[0] = GetFieldValue ("MarshalTypeRef");
1056 args
[1] = GetFieldValue ("MarshalCookie");
1057 args
[2] = GetFieldValue ("MarshalType");
1058 args
[3] = Guid
.Empty
;
1059 return (UnmanagedMarshal
) define_custom
.Invoke (null, args
);
1061 case UnmanagedType
.LPArray
: {
1062 object size_const
= GetFieldValue ("SizeConst");
1063 object size_param_index
= GetFieldValue ("SizeParamIndex");
1065 if ((size_const
!= null) || (size_param_index
!= null)) {
1066 MethodInfo define_array
= typeof (UnmanagedMarshal
).GetMethod ("DefineLPArrayInternal",
1067 BindingFlags
.Static
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1068 if (define_array
== null) {
1069 Report
.RuntimeMissingSupport (Location
, "set marshal info");
1073 object [] args
= new object [3];
1074 args
[0] = array_sub_type
;
1075 args
[1] = size_const
== null ? -1 : size_const
;
1076 args
[2] = size_param_index
== null ? -1 : size_param_index
;
1077 return (UnmanagedMarshal
) define_array
.Invoke (null, args
);
1080 return UnmanagedMarshal
.DefineLPArray (array_sub_type
);
1082 case UnmanagedType
.SafeArray
:
1083 return UnmanagedMarshal
.DefineSafeArray (array_sub_type
);
1085 case UnmanagedType
.ByValArray
:
1086 FieldBase fm
= attr
as FieldBase
;
1088 Error_AttributeEmitError ("Specified unmanaged type is only valid on fields");
1091 return UnmanagedMarshal
.DefineByValArray ((int) GetFieldValue ("SizeConst"));
1093 case UnmanagedType
.ByValTStr
:
1094 return UnmanagedMarshal
.DefineByValTStr ((int) GetFieldValue ("SizeConst"));
1097 return UnmanagedMarshal
.DefineUnmanagedMarshal (UnmanagedType
);
1101 object GetFieldValue (string name
)
1104 if (field_info_arr
== null)
1107 foreach (FieldInfo fi
in field_info_arr
) {
1108 if (fi
.Name
== name
)
1109 return GetValue (field_values_arr
[i
]);
1115 static object GetValue (object value)
1117 if (value is EnumConstant
)
1118 return ((EnumConstant
) value).GetValue ();
1125 public CharSet
GetCharSetValue ()
1127 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1130 public bool HasField (string fieldName
)
1132 if (field_info_arr
== null)
1135 foreach (FieldInfo fi
in field_info_arr
) {
1136 if (fi
.Name
== fieldName
)
1143 public bool IsInternalMethodImplAttribute
{
1145 if (Type
!= PredefinedAttributes
.Get
.MethodImpl
)
1148 MethodImplOptions options
;
1149 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1150 options
= (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1152 options
= (MethodImplOptions
)pos_values
[0];
1154 return (options
& MethodImplOptions
.InternalCall
) != 0;
1158 public LayoutKind
GetLayoutKindValue ()
1160 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1161 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1163 return (LayoutKind
)pos_values
[0];
1166 public object GetParameterDefaultValue ()
1168 return pos_values
[0];
1171 public override bool Equals (object obj
)
1173 Attribute a
= obj
as Attribute
;
1177 return Type
== a
.Type
&& Target
== a
.Target
;
1180 public override int GetHashCode ()
1182 return base.GetHashCode ();
1186 /// Emit attribute for Attributable symbol
1188 public void Emit (ListDictionary allEmitted
)
1190 CustomAttributeBuilder cb
= Resolve ();
1194 AttributeUsageAttribute usage_attr
= GetAttributeUsage (Type
);
1195 if ((usage_attr
.ValidOn
& Target
) == 0) {
1196 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1197 "It is valid on `{1}' declarations only",
1198 GetSignatureForError (), GetValidTargets ());
1203 foreach (Attributable target
in targets
)
1204 target
.ApplyAttributeBuilder (this, cb
, PredefinedAttributes
.Get
);
1205 } catch (Exception e
) {
1206 Error_AttributeEmitError (e
.Message
);
1210 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1211 if (allEmitted
.Contains (this)) {
1212 ArrayList a
= allEmitted
[this] as ArrayList
;
1214 a
= new ArrayList (2);
1215 allEmitted
[this] = a
;
1219 allEmitted
.Add (this, null);
1223 if (!RootContext
.VerifyClsCompliance
)
1226 // Here we are testing attribute arguments for array usage (error 3016)
1227 if (Owner
.IsClsComplianceRequired ()) {
1228 if (PosArguments
!= null)
1229 PosArguments
.CheckArrayAsAttribute (context
.Compiler
);
1231 if (NamedArguments
== null)
1234 NamedArguments
.CheckArrayAsAttribute (context
.Compiler
);
1238 private Expression
GetValue ()
1240 if (PosArguments
== null || PosArguments
.Count
< 1)
1243 return PosArguments
[0].Expr
;
1246 public string GetString ()
1248 Expression e
= GetValue ();
1249 if (e
is StringConstant
)
1250 return ((StringConstant
)e
).Value
;
1254 public bool GetBoolean ()
1256 Expression e
= GetValue ();
1257 if (e
is BoolConstant
)
1258 return ((BoolConstant
)e
).Value
;
1262 public Type
GetArgumentType ()
1264 TypeOf e
= GetValue () as TypeOf
;
1267 return e
.TypeArgument
;
1270 public override Expression
CreateExpressionTree (ResolveContext ec
)
1272 throw new NotSupportedException ("ET");
1275 public override Expression
DoResolve (ResolveContext ec
)
1277 throw new NotImplementedException ();
1280 public override void Emit (EmitContext ec
)
1282 throw new NotImplementedException ();
1288 /// For global attributes (assembly, module) we need special handling.
1289 /// Attributes can be located in the several files
1291 public class GlobalAttribute
: Attribute
1293 public readonly NamespaceEntry ns
;
1295 public GlobalAttribute (NamespaceEntry ns
, string target
, ATypeNameExpression expression
,
1296 Arguments
[] args
, Location loc
, bool nameEscaped
):
1297 base (target
, expression
, args
, loc
, nameEscaped
)
1302 public override void AttachTo (Attributable target
, IMemberContext context
)
1304 if (ExplicitTarget
== "assembly") {
1305 base.AttachTo (CodeGen
.Assembly
, context
);
1309 if (ExplicitTarget
== "module") {
1310 base.AttachTo (RootContext
.ToplevelTypes
, context
);
1314 throw new NotImplementedException ("Unknown global explicit target " + ExplicitTarget
);
1319 // RootContext.ToplevelTypes has a single NamespaceEntry which gets overwritten
1320 // each time a new file is parsed. However, we need to use the NamespaceEntry
1321 // in effect where the attribute was used. Since code elsewhere cannot assume
1322 // that the NamespaceEntry is right, just overwrite it.
1324 // Precondition: RootContext.ToplevelTypes == null
1326 if (RootContext
.ToplevelTypes
.NamespaceEntry
!= null)
1327 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1329 RootContext
.ToplevelTypes
.NamespaceEntry
= ns
;
1332 protected override bool IsSecurityActionValid (bool for_assembly
)
1334 return base.IsSecurityActionValid (true);
1339 RootContext
.ToplevelTypes
.NamespaceEntry
= null;
1342 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IMemberContext ec
)
1346 return base.ResolveAsTypeTerminal (expr
, ec
);
1353 protected override ConstructorInfo
ResolveConstructor (ResolveContext ec
)
1357 return base.ResolveConstructor (ec
);
1364 protected override bool ResolveNamedArguments (ResolveContext ec
)
1368 return base.ResolveNamedArguments (ec
);
1376 public class Attributes
{
1377 public readonly ArrayList Attrs
;
1379 public Attributes (Attribute a
)
1381 Attrs
= new ArrayList ();
1385 public Attributes (ArrayList attrs
)
1390 public void AddAttributes (ArrayList attrs
)
1392 Attrs
.AddRange (attrs
);
1395 public void AttachTo (Attributable attributable
, IMemberContext context
)
1397 foreach (Attribute a
in Attrs
)
1398 a
.AttachTo (attributable
, context
);
1401 public Attributes
Clone ()
1403 ArrayList al
= new ArrayList (Attrs
.Count
);
1404 foreach (Attribute a
in Attrs
)
1405 al
.Add (a
.Clone ());
1407 return new Attributes (al
);
1411 /// Checks whether attribute target is valid for the current element
1413 public bool CheckTargets ()
1415 foreach (Attribute a
in Attrs
) {
1416 if (!a
.CheckTarget ())
1422 public Attribute
Search (PredefinedAttribute t
)
1424 foreach (Attribute a
in Attrs
) {
1425 if (a
.ResolveType () == t
)
1432 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1434 public Attribute
[] SearchMulti (PredefinedAttribute t
)
1436 ArrayList ar
= null;
1438 foreach (Attribute a
in Attrs
) {
1439 if (a
.ResolveType () == t
) {
1441 ar
= new ArrayList ();
1446 return ar
== null ? null : ar
.ToArray (typeof (Attribute
)) as Attribute
[];
1453 ListDictionary ld
= Attrs
.Count
> 1 ? new ListDictionary () : null;
1455 foreach (Attribute a
in Attrs
)
1458 if (ld
== null || ld
.Count
== 0)
1461 foreach (DictionaryEntry d
in ld
) {
1462 if (d
.Value
== null)
1465 Report report
= RootContext
.ToplevelTypes
.Compiler
.Report
;
1466 foreach (Attribute collision
in (ArrayList
)d
.Value
)
1467 report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1469 Attribute a
= (Attribute
)d
.Key
;
1470 report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times",
1471 a
.GetSignatureForError ());
1475 public bool Contains (PredefinedAttribute t
)
1477 return Search (t
) != null;
1482 /// Helper class for attribute verification routine.
1484 sealed class AttributeTester
1486 static PtrHashtable analyzed_types
;
1487 static PtrHashtable analyzed_types_obsolete
;
1488 static PtrHashtable analyzed_member_obsolete
;
1489 static PtrHashtable analyzed_method_excluded
;
1490 static PtrHashtable fixed_buffer_cache
;
1492 static object TRUE
= new object ();
1493 static object FALSE
= new object ();
1495 static AttributeTester ()
1500 private AttributeTester ()
1504 public static void Reset ()
1506 analyzed_types
= new PtrHashtable ();
1507 analyzed_types_obsolete
= new PtrHashtable ();
1508 analyzed_member_obsolete
= new PtrHashtable ();
1509 analyzed_method_excluded
= new PtrHashtable ();
1510 fixed_buffer_cache
= new PtrHashtable ();
1513 public enum Result
{
1520 /// Returns true if parameters of two compared methods are CLS-Compliant.
1521 /// It tests differing only in ref or out, or in array rank.
1523 public static Result
AreOverloadedMethodParamsClsCompliant (AParametersCollection pa
, AParametersCollection pb
)
1525 Type
[] types_a
= pa
.Types
;
1526 Type
[] types_b
= pb
.Types
;
1527 if (types_a
== null || types_b
== null)
1530 if (types_a
.Length
!= types_b
.Length
)
1533 Result result
= Result
.Ok
;
1534 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1535 Type aType
= types_a
[i
];
1536 Type bType
= types_b
[i
];
1538 if (aType
.IsArray
&& bType
.IsArray
) {
1539 Type a_el_type
= TypeManager
.GetElementType (aType
);
1540 Type b_el_type
= TypeManager
.GetElementType (bType
);
1541 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1542 result
= Result
.RefOutArrayError
;
1546 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1547 result
= Result
.ArrayArrayError
;
1555 const Parameter
.Modifier out_ref_mod
= (Parameter
.Modifier
.OUTMASK
| Parameter
.Modifier
.REFMASK
);
1556 if ((pa
.FixedParameters
[i
].ModFlags
& out_ref_mod
) != (pb
.FixedParameters
[i
].ModFlags
& out_ref_mod
))
1557 result
= Result
.RefOutArrayError
;
1563 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1565 public static bool IsClsCompliant (Type type
)
1570 object type_compliance
= analyzed_types
[type
];
1571 if (type_compliance
!= null)
1572 return type_compliance
== TRUE
;
1574 if (type
.IsPointer
) {
1575 analyzed_types
.Add (type
, FALSE
);
1581 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1582 } else if (TypeManager
.IsNullableType (type
)) {
1583 result
= IsClsCompliant (TypeManager
.TypeToCoreType (TypeManager
.GetTypeArguments (type
) [0]));
1585 result
= AnalyzeTypeCompliance (type
);
1587 analyzed_types
.Add (type
, result
? TRUE
: FALSE
);
1592 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1594 public static IFixedBuffer
GetFixedBuffer (FieldInfo fi
)
1596 // Fixed buffer helper type is generated as value type
1597 if (TypeManager
.IsReferenceType (fi
.FieldType
))
1600 FieldBase fb
= TypeManager
.GetField (fi
);
1602 return fb
as IFixedBuffer
;
1605 if (TypeManager
.GetConstant (fi
) != null)
1608 object o
= fixed_buffer_cache
[fi
];
1610 PredefinedAttribute pa
= PredefinedAttributes
.Get
.FixedBuffer
;
1614 if (!fi
.IsDefined (pa
.Type
, false)) {
1615 fixed_buffer_cache
.Add (fi
, FALSE
);
1619 IFixedBuffer iff
= new FixedFieldExternal (fi
);
1620 fixed_buffer_cache
.Add (fi
, iff
);
1627 return (IFixedBuffer
)o
;
1630 public static void VerifyModulesClsCompliance (CompilerContext ctx
)
1632 Module
[] modules
= GlobalRootNamespace
.Instance
.Modules
;
1633 if (modules
== null)
1636 // The first module is generated assembly
1637 for (int i
= 1; i
< modules
.Length
; ++i
) {
1638 Module module
= modules
[i
];
1639 if (!GetClsCompliantAttributeValue (module
, null)) {
1640 ctx
.Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1641 "to match the assembly", module
.Name
);
1647 public static Type
GetImportedIgnoreCaseClsType (string name
)
1649 foreach (Assembly a
in GlobalRootNamespace
.Instance
.Assemblies
) {
1650 Type t
= a
.GetType (name
, false, true);
1654 if (IsClsCompliant (t
))
1660 static bool GetClsCompliantAttributeValue (ICustomAttributeProvider attribute_provider
, Assembly a
)
1662 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CLSCompliant
;
1666 object[] cls_attr
= attribute_provider
.GetCustomAttributes (pa
.Type
, false);
1667 if (cls_attr
.Length
== 0) {
1671 return GetClsCompliantAttributeValue (a
, null);
1674 return ((CLSCompliantAttribute
)cls_attr
[0]).IsCompliant
;
1677 static bool AnalyzeTypeCompliance (Type type
)
1679 type
= TypeManager
.DropGenericTypeArguments (type
);
1680 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1682 return ds
.IsClsComplianceRequired ();
1685 if (TypeManager
.IsGenericParameter (type
))
1688 return GetClsCompliantAttributeValue (type
, type
.Assembly
);
1692 /// Returns instance of ObsoleteAttribute when type is obsolete
1694 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1696 object type_obsolete
= analyzed_types_obsolete
[type
];
1697 if (type_obsolete
== FALSE
)
1700 if (type_obsolete
!= null)
1701 return (ObsoleteAttribute
)type_obsolete
;
1703 ObsoleteAttribute result
= null;
1704 if (TypeManager
.HasElementType (type
)) {
1705 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1706 } else if (TypeManager
.IsGenericParameter (type
))
1707 result
= null; // TODO: throw new NotSupportedException ()
1708 else if (TypeManager
.IsGenericType (type
) && !TypeManager
.IsGenericTypeDefinition (type
)) {
1709 return GetObsoleteAttribute (TypeManager
.DropGenericTypeArguments (type
));
1711 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1713 // Type is external, we can get attribute directly
1714 if (type_ds
== null) {
1715 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1717 object[] attribute
= type
.GetCustomAttributes (pa
.Type
, false);
1718 if (attribute
.Length
== 1)
1719 result
= (ObsoleteAttribute
) attribute
[0];
1722 result
= type_ds
.GetObsoleteAttribute ();
1726 // Cannot use .Add because of corlib bootstrap
1727 analyzed_types_obsolete
[type
] = result
== null ? FALSE
: result
;
1732 /// Returns instance of ObsoleteAttribute when method is obsolete
1734 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1736 IMethodData mc
= TypeManager
.GetMethod (mb
);
1738 return mc
.GetObsoleteAttribute ();
1740 // compiler generated methods are not registered by AddMethod
1741 if (mb
.DeclaringType
is TypeBuilder
)
1744 MemberInfo mi
= TypeManager
.GetPropertyFromAccessor (mb
);
1746 return GetMemberObsoleteAttribute (mi
);
1748 mi
= TypeManager
.GetEventFromAccessor (mb
);
1750 return GetMemberObsoleteAttribute (mi
);
1752 return GetMemberObsoleteAttribute (mb
);
1756 /// Returns instance of ObsoleteAttribute when member is obsolete
1758 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1760 object type_obsolete
= analyzed_member_obsolete
[mi
];
1761 if (type_obsolete
== FALSE
)
1764 if (type_obsolete
!= null)
1765 return (ObsoleteAttribute
)type_obsolete
;
1767 if ((mi
.DeclaringType
is TypeBuilder
) || TypeManager
.IsGenericType (mi
.DeclaringType
))
1770 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Obsolete
;
1774 ObsoleteAttribute oa
= System
.Attribute
.GetCustomAttribute (mi
, pa
.Type
, false)
1775 as ObsoleteAttribute
;
1776 analyzed_member_obsolete
.Add (mi
, oa
== null ? FALSE
: oa
);
1781 /// Common method for Obsolete error/warning reporting.
1783 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
, Report Report
)
1786 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1790 if (oa
.Message
== null || oa
.Message
.Length
== 0) {
1791 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1794 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1797 public static bool IsConditionalMethodExcluded (MethodBase mb
, Location loc
)
1799 object excluded
= analyzed_method_excluded
[mb
];
1800 if (excluded
!= null)
1801 return excluded
== TRUE
? true : false;
1803 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1807 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (pa
.Type
, true)
1808 as ConditionalAttribute
[];
1809 if (attrs
.Length
== 0) {
1810 analyzed_method_excluded
.Add (mb
, FALSE
);
1814 foreach (ConditionalAttribute a
in attrs
) {
1815 if (loc
.CompilationUnit
.IsConditionalDefined (a
.ConditionString
)) {
1816 analyzed_method_excluded
.Add (mb
, FALSE
);
1821 analyzed_method_excluded
.Add (mb
, TRUE
);
1826 /// Analyzes class whether it has attribute which has ConditionalAttribute
1827 /// and its condition is not defined.
1829 public static bool IsAttributeExcluded (Type type
, Location loc
)
1834 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1836 // TODO: add caching
1837 // TODO: merge all Type bases attribute caching to one cache to save memory
1838 PredefinedAttribute pa
= PredefinedAttributes
.Get
.Conditional
;
1839 if (class_decl
== null && pa
.IsDefined
) {
1840 object[] attributes
= type
.GetCustomAttributes (pa
.Type
, false);
1841 foreach (ConditionalAttribute ca
in attributes
) {
1842 if (loc
.CompilationUnit
.IsConditionalDefined (ca
.ConditionString
))
1845 return attributes
.Length
> 0;
1848 return class_decl
.IsExcluded ();
1851 public static Type
GetCoClassAttribute (Type type
)
1853 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1854 PredefinedAttribute pa
= PredefinedAttributes
.Get
.CoClass
;
1859 object[] o
= type
.GetCustomAttributes (pa
.Type
, false);
1862 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1865 if (tc
.OptAttributes
== null)
1868 Attribute a
= tc
.OptAttributes
.Search (pa
);
1872 return a
.GetCoClassAttributeValue ();
1876 public class PredefinedAttributes
1879 public readonly PredefinedAttribute ParamArray
;
1880 public readonly PredefinedAttribute Out
;
1883 public readonly PredefinedAttribute Obsolete
;
1884 public readonly PredefinedAttribute DllImport
;
1885 public readonly PredefinedAttribute MethodImpl
;
1886 public readonly PredefinedAttribute MarshalAs
;
1887 public readonly PredefinedAttribute In
;
1888 public readonly PredefinedAttribute IndexerName
;
1889 public readonly PredefinedAttribute Conditional
;
1890 public readonly PredefinedAttribute CLSCompliant
;
1891 public readonly PredefinedAttribute Security
;
1892 public readonly PredefinedAttribute Required
;
1893 public readonly PredefinedAttribute Guid
;
1894 public readonly PredefinedAttribute AssemblyCulture
;
1895 public readonly PredefinedAttribute AssemblyVersion
;
1896 public readonly PredefinedAttribute ComImport
;
1897 public readonly PredefinedAttribute CoClass
;
1898 public readonly PredefinedAttribute AttributeUsage
;
1899 public readonly PredefinedAttribute DefaultParameterValue
;
1900 public readonly PredefinedAttribute OptionalParameter
;
1903 public readonly PredefinedAttribute DefaultCharset
;
1904 public readonly PredefinedAttribute TypeForwarder
;
1905 public readonly PredefinedAttribute FixedBuffer
;
1906 public readonly PredefinedAttribute CompilerGenerated
;
1907 public readonly PredefinedAttribute InternalsVisibleTo
;
1908 public readonly PredefinedAttribute RuntimeCompatibility
;
1909 public readonly PredefinedAttribute DebuggerHidden
;
1910 public readonly PredefinedAttribute UnsafeValueType
;
1913 public readonly PredefinedAttribute Extension
;
1916 public readonly PredefinedAttribute Dynamic
;
1919 // Optional types which are used as types and for member lookup
1921 public readonly PredefinedAttribute DefaultMember
;
1922 public readonly PredefinedAttribute DecimalConstant
;
1923 public readonly PredefinedAttribute StructLayout
;
1924 public readonly PredefinedAttribute FieldOffset
;
1926 public static PredefinedAttributes Get
= new PredefinedAttributes ();
1928 private PredefinedAttributes ()
1930 ParamArray
= new PredefinedAttribute ("System", "ParamArrayAttribute");
1931 Out
= new PredefinedAttribute ("System.Runtime.InteropServices", "OutAttribute");
1933 Obsolete
= new PredefinedAttribute ("System", "ObsoleteAttribute");
1934 DllImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "DllImportAttribute");
1935 MethodImpl
= new PredefinedAttribute ("System.Runtime.CompilerServices", "MethodImplAttribute");
1936 MarshalAs
= new PredefinedAttribute ("System.Runtime.InteropServices", "MarshalAsAttribute");
1937 In
= new PredefinedAttribute ("System.Runtime.InteropServices", "InAttribute");
1938 IndexerName
= new PredefinedAttribute ("System.Runtime.CompilerServices", "IndexerNameAttribute");
1939 Conditional
= new PredefinedAttribute ("System.Diagnostics", "ConditionalAttribute");
1940 CLSCompliant
= new PredefinedAttribute ("System", "CLSCompliantAttribute");
1941 Security
= new PredefinedAttribute ("System.Security.Permissions", "SecurityAttribute");
1942 Required
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RequiredAttributeAttribute");
1943 Guid
= new PredefinedAttribute ("System.Runtime.InteropServices", "GuidAttribute");
1944 AssemblyCulture
= new PredefinedAttribute ("System.Reflection", "AssemblyCultureAttribute");
1945 AssemblyVersion
= new PredefinedAttribute ("System.Reflection", "AssemblyVersionAttribute");
1946 ComImport
= new PredefinedAttribute ("System.Runtime.InteropServices", "ComImportAttribute");
1947 CoClass
= new PredefinedAttribute ("System.Runtime.InteropServices", "CoClassAttribute");
1948 AttributeUsage
= new PredefinedAttribute ("System", "AttributeUsageAttribute");
1949 DefaultParameterValue
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultParameterValueAttribute");
1950 OptionalParameter
= new PredefinedAttribute ("System.Runtime.InteropServices", "OptionalAttribute");
1952 DefaultCharset
= new PredefinedAttribute ("System.Runtime.InteropServices", "DefaultCharSetAttribute");
1953 TypeForwarder
= new PredefinedAttribute ("System.Runtime.CompilerServices", "TypeForwardedToAttribute");
1954 FixedBuffer
= new PredefinedAttribute ("System.Runtime.CompilerServices", "FixedBufferAttribute");
1955 CompilerGenerated
= new PredefinedAttribute ("System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
1956 InternalsVisibleTo
= new PredefinedAttribute ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
1957 RuntimeCompatibility
= new PredefinedAttribute ("System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
1958 DebuggerHidden
= new PredefinedAttribute ("System.Diagnostics", "DebuggerHiddenAttribute");
1959 UnsafeValueType
= new PredefinedAttribute ("System.Runtime.CompilerServices", "UnsafeValueTypeAttribute");
1961 Extension
= new PredefinedAttribute ("System.Runtime.CompilerServices", "ExtensionAttribute");
1963 Dynamic
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DynamicAttribute");
1965 DefaultMember
= new PredefinedAttribute ("System.Reflection", "DefaultMemberAttribute");
1966 DecimalConstant
= new PredefinedAttribute ("System.Runtime.CompilerServices", "DecimalConstantAttribute");
1967 StructLayout
= new PredefinedAttribute ("System.Runtime.InteropServices", "StructLayoutAttribute");
1968 FieldOffset
= new PredefinedAttribute ("System.Runtime.InteropServices", "FieldOffsetAttribute");
1971 public void Initialize ()
1973 foreach (FieldInfo fi
in GetType ().GetFields (BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
)) {
1974 ((PredefinedAttribute
) fi
.GetValue (this)).Resolve (true);
1978 public static void Reset ()
1980 Get
= new PredefinedAttributes ();
1984 public class PredefinedAttribute
1987 CustomAttributeBuilder cab
;
1988 ConstructorInfo ctor
;
1989 readonly string ns
, name
;
1991 public PredefinedAttribute (string ns
, string name
)
1997 public static bool operator == (Type type
, PredefinedAttribute pa
)
1999 return type
== pa
.type
;
2002 public static bool operator != (Type type
, PredefinedAttribute pa
)
2004 return type
!= pa
.type
;
2007 public ConstructorInfo Constructor
{
2008 get { return ctor; }
2011 public override int GetHashCode ()
2013 return base.GetHashCode ();
2016 public override bool Equals (object obj
)
2018 throw new NotSupportedException ();
2021 public void EmitAttribute (ConstructorBuilder builder
)
2023 if (ResolveBuilder ())
2024 builder
.SetCustomAttribute (cab
);
2027 public void EmitAttribute (MethodBuilder builder
)
2029 if (ResolveBuilder ())
2030 builder
.SetCustomAttribute (cab
);
2033 public void EmitAttribute (PropertyBuilder builder
)
2035 if (ResolveBuilder ())
2036 builder
.SetCustomAttribute (cab
);
2039 public void EmitAttribute (FieldBuilder builder
)
2041 if (ResolveBuilder ())
2042 builder
.SetCustomAttribute (cab
);
2045 public void EmitAttribute (TypeBuilder builder
)
2047 if (ResolveBuilder ())
2048 builder
.SetCustomAttribute (cab
);
2051 public void EmitAttribute (AssemblyBuilder builder
)
2053 if (ResolveBuilder ())
2054 builder
.SetCustomAttribute (cab
);
2057 public void EmitAttribute (ParameterBuilder builder
, Location loc
)
2059 if (ResolveBuilder ())
2060 builder
.SetCustomAttribute (cab
);
2063 public bool IsDefined
{
2064 get { return type != null && type != typeof (PredefinedAttribute); }
2067 public bool Resolve (bool canFail
)
2076 type
= TypeManager
.CoreLookupType (RootContext
.ToplevelTypes
.Compiler
, ns
, name
, Kind
.Class
, !canFail
);
2078 type
= typeof (PredefinedAttribute
);
2085 bool ResolveBuilder ()
2091 // Handle all parameter-less attributes as optional
2093 if (!Resolve (true))
2096 ConstructorInfo ci
= TypeManager
.GetPredefinedConstructor (type
, Location
.Null
, Type
.EmptyTypes
);
2100 cab
= new CustomAttributeBuilder (ci
, new object[0]);
2104 public bool ResolveConstructor (Location loc
, params Type
[] argType
)
2107 throw new InternalErrorException ("Predefined ctor redefined");
2109 if (!Resolve (false))
2112 ctor
= TypeManager
.GetPredefinedConstructor (type
, loc
, argType
);
2113 return ctor
!= null;
2117 get { return type; }