2 // attribute.cs: Attribute Handler
4 // Author: Ravi Pratap (ravi@ximian.com)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System
.Diagnostics
;
15 using System
.Collections
;
16 using System
.Collections
.Specialized
;
17 using System
.Reflection
;
18 using System
.Reflection
.Emit
;
19 using System
.Runtime
.InteropServices
;
20 using System
.Runtime
.CompilerServices
;
21 using System
.Security
;
22 using System
.Security
.Permissions
;
26 namespace Mono
.CSharp
{
29 /// Base class for objects that can have Attributes applied to them.
31 public abstract class Attributable
{
33 /// Attributes for this type
35 protected Attributes attributes
;
37 public Attributable (Attributes attrs
)
40 OptAttributes
= attrs
;
43 public Attributes OptAttributes
51 if (attributes
!= null) {
52 attributes
.AttachTo (this);
58 /// Use member-specific procedure to apply attribute @a in @cb to the entity being built in @builder
60 public abstract void ApplyAttributeBuilder (Attribute a
, CustomAttributeBuilder cb
);
63 /// Returns one AttributeTarget for this element.
65 public abstract AttributeTargets AttributeTargets { get; }
67 public abstract IResolveContext ResolveContext { get; }
69 public abstract bool IsClsComplianceRequired ();
72 /// Gets list of valid attribute targets for explicit target declaration.
73 /// The first array item is default target. Don't break this rule.
75 public abstract string[] ValidAttributeTargets { get; }
78 public class Attribute
{
79 public readonly string ExplicitTarget
;
80 public AttributeTargets Target
;
82 // TODO: remove this member
83 public readonly string Name
;
84 public readonly Expression LeftExpr
;
85 public readonly string Identifier
;
87 readonly ArrayList PosArguments
;
88 readonly ArrayList NamedArguments
;
90 public readonly Location Location
;
95 readonly bool nameEscaped
;
97 // It can contain more onwers when the attribute is applied to multiple fiels.
98 Attributable
[] owners
;
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 PtrHashtable usage_attr_cache
;
112 // Cache for parameter-less attributes
113 static PtrHashtable att_cache
;
115 public Attribute (string target
, Expression left_expr
, string identifier
, object[] args
, Location loc
, bool nameEscaped
)
117 LeftExpr
= left_expr
;
118 Identifier
= identifier
;
119 Name
= LeftExpr
== null ? identifier
: LeftExpr
+ "." + identifier
;
121 PosArguments
= (ArrayList
)args
[0];
122 NamedArguments
= (ArrayList
)args
[1];
125 ExplicitTarget
= target
;
126 this.nameEscaped
= nameEscaped
;
134 public static void Reset ()
136 usage_attr_cache
= new PtrHashtable ();
137 att_cache
= new PtrHashtable ();
140 public void AttachTo (Attributable owner
)
142 if (this.owners
== null) {
143 this.owners
= new Attributable
[1] { owner }
;
147 // When the same attribute is attached to multiple fiels
148 // we use this extra_owners as a list of owners. The attribute
149 // then can be removed because will be emitted when first owner
151 Attributable
[] new_array
= new Attributable
[this.owners
.Length
+ 1];
152 owners
.CopyTo (new_array
, 0);
153 new_array
[owners
.Length
] = owner
;
154 this.owners
= new_array
;
155 owner
.OptAttributes
= null;
158 void Error_InvalidNamedArgument (string name
)
160 Report
.Error (617, Location
, "`{0}' is not a valid named attribute argument. Named attribute arguments " +
161 "must be fields which are not readonly, static, const or read-write properties which are " +
162 "public and not static",
166 void Error_InvalidNamedAgrumentType (string name
)
168 Report
.Error (655, Location
, "`{0}' is not a valid named attribute argument because it is not a valid " +
169 "attribute parameter type", name
);
172 public static void Error_AttributeArgumentNotValid (Location loc
)
174 Report
.Error (182, loc
,
175 "An attribute argument must be a constant expression, typeof " +
176 "expression or array creation expression");
179 static void Error_TypeParameterInAttribute (Location loc
)
182 -202, loc
, "Can not use a type parameter in an attribute");
185 public void Error_MissingGuidAttribute ()
187 Report
.Error (596, Location
, "The Guid attribute must be specified with the ComImport attribute");
191 /// This is rather hack. We report many emit attribute error with same error to be compatible with
192 /// csc. But because csc has to report them this way because error came from ilasm we needn't.
194 public void Error_AttributeEmitError (string inner
)
196 Report
.Error (647, Location
, "Error during emitting `{0}' attribute. The reason is `{1}'",
197 TypeManager
.CSharpName (Type
), inner
);
200 public void Error_InvalidSecurityParent ()
202 Error_AttributeEmitError ("it is attached to invalid parent");
211 protected virtual TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
213 return expr
.ResolveAsTypeTerminal (ec
, silent
);
216 Type
ResolvePossibleAttributeType (string name
, bool silent
, ref bool is_attr
)
218 IResolveContext rc
= Owner
.ResolveContext
;
221 if (LeftExpr
== null) {
222 te
= ResolveAsTypeTerminal (new SimpleName (name
, Location
), rc
, silent
);
224 te
= ResolveAsTypeTerminal (new MemberAccess (LeftExpr
, name
), rc
, silent
);
231 if (TypeManager
.IsSubclassOf (t
, TypeManager
.attribute_type
)) {
233 } else if (!silent
) {
234 Report
.SymbolRelatedToPreviousError (t
);
235 Report
.Error (616, Location
, "`{0}': is not an attribute class", TypeManager
.CSharpName (t
));
241 /// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
243 void ResolveAttributeType ()
245 bool t1_is_attr
= false;
246 Type t1
= ResolvePossibleAttributeType (Identifier
, true, ref t1_is_attr
);
248 bool t2_is_attr
= false;
249 Type t2
= nameEscaped
? null :
250 ResolvePossibleAttributeType (Identifier
+ "Attribute", true, ref t2_is_attr
);
252 if (t1_is_attr
&& t2_is_attr
) {
253 Report
.Error (1614, Location
, "`{0}' is ambiguous between `{0}' and `{0}Attribute'. " +
254 "Use either `@{0}' or `{0}Attribute'", GetSignatureForError ());
255 resolve_error
= true;
269 if (t1
== null && t2
== null)
270 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
272 ResolvePossibleAttributeType (Identifier
, false, ref t1_is_attr
);
274 ResolvePossibleAttributeType (Identifier
+ "Attribute", false, ref t2_is_attr
);
276 resolve_error
= true;
279 public virtual Type
ResolveType ()
281 if (Type
== null && !resolve_error
)
282 ResolveAttributeType ();
286 public string GetSignatureForError ()
289 return TypeManager
.CSharpName (Type
);
291 return LeftExpr
== null ? Identifier
: LeftExpr
.GetSignatureForError () + "." + Identifier
;
294 bool IsValidArgumentType (Type t
)
297 t
= t
.GetElementType ();
299 return TypeManager
.IsPrimitiveType (t
) ||
300 TypeManager
.IsEnumType (t
) ||
301 t
== TypeManager
.string_type
||
302 t
== TypeManager
.object_type
||
303 t
== TypeManager
.type_type
;
306 public CustomAttributeBuilder
Resolve ()
311 resolve_error
= true;
314 ResolveAttributeType ();
319 if (Type
.IsAbstract
) {
320 Report
.Error (653, Location
, "Cannot apply attribute class `{0}' because it is abstract", GetSignatureForError ());
324 ObsoleteAttribute obsolete_attr
= AttributeTester
.GetObsoleteAttribute (Type
);
325 if (obsolete_attr
!= null) {
326 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, TypeManager
.CSharpName (Type
), Location
);
329 if (PosArguments
== null && NamedArguments
== null) {
330 object o
= att_cache
[Type
];
332 resolve_error
= false;
333 return (CustomAttributeBuilder
)o
;
337 Attributable owner
= Owner
;
338 EmitContext ec
= new EmitContext (owner
.ResolveContext
, owner
.ResolveContext
.DeclContainer
, owner
.ResolveContext
.DeclContainer
,
339 Location
, null, null, owner
.ResolveContext
.DeclContainer
.ModFlags
, false);
340 ec
.IsAnonymousMethodAllowed
= false;
342 ConstructorInfo ctor
= ResolveConstructor (ec
);
344 if (Type
is TypeBuilder
&&
345 TypeManager
.LookupDeclSpace (Type
).MemberCache
== null)
346 // The attribute type has been DefineType'd, but not Defined. Let's not treat it as an error.
347 // It'll be resolved again when the attached-to entity is emitted.
348 resolve_error
= false;
352 CustomAttributeBuilder cb
;
355 if (NamedArguments
== null) {
356 cb
= new CustomAttributeBuilder (ctor
, pos_values
);
358 if (pos_values
.Length
== 0)
359 att_cache
.Add (Type
, cb
);
361 resolve_error
= false;
365 if (!ResolveNamedArguments (ec
)) {
369 cb
= new CustomAttributeBuilder (ctor
, pos_values
,
370 prop_info_arr
, prop_values_arr
,
371 field_info_arr
, field_values_arr
);
373 resolve_error
= false;
377 Error_AttributeArgumentNotValid (Location
);
382 protected virtual ConstructorInfo
ResolveConstructor (EmitContext ec
)
384 if (PosArguments
!= null) {
385 for (int i
= 0; i
< PosArguments
.Count
; i
++) {
386 Argument a
= (Argument
) PosArguments
[i
];
388 if (!a
.Resolve (ec
, Location
))
393 Expression mg
= Expression
.MemberLookup (ec
.ContainerType
,
394 Type
, ".ctor", MemberTypes
.Constructor
,
395 BindingFlags
.Public
| BindingFlags
.Instance
| BindingFlags
.DeclaredOnly
,
401 MethodBase constructor
= Invocation
.OverloadResolve (
402 ec
, (MethodGroupExpr
) mg
, PosArguments
, false, Location
);
404 if (constructor
== null)
407 ObsoleteAttribute oa
= AttributeTester
.GetMethodObsoleteAttribute (constructor
);
408 if (oa
!= null && !Owner
.ResolveContext
.IsInObsoleteScope
) {
409 AttributeTester
.Report_ObsoleteMessage (oa
, mg
.GetSignatureForError (), mg
.Location
);
412 if (PosArguments
== null) {
413 pos_values
= EmptyObject
;
414 return (ConstructorInfo
)constructor
;
417 ParameterData pd
= TypeManager
.GetParameterData (constructor
);
419 int pos_arg_count
= PosArguments
.Count
;
420 int last_real_param
= pd
.Count
;
422 pos_values
= new object [pos_arg_count
];
425 // When the params is not filled we need to put one
426 if (last_real_param
> pos_arg_count
) {
427 object [] new_pos_values
= new object [pos_arg_count
+ 1];
428 pos_values
.CopyTo (new_pos_values
, 0);
429 new_pos_values
[pos_arg_count
] = new object [] {} ;
430 pos_values
= new_pos_values
;
435 for (int j
= 0; j
< pos_arg_count
; ++j
) {
436 Argument a
= (Argument
) PosArguments
[j
];
438 if (!a
.Expr
.GetAttributableValue (a
.Type
, out pos_values
[j
]))
441 if (j
< last_real_param
)
444 if (j
== last_real_param
) {
445 object [] array
= new object [pos_arg_count
- last_real_param
];
446 array
[0] = pos_values
[j
];
447 pos_values
[j
] = array
;
451 object [] params_array
= (object []) pos_values
[last_real_param
];
452 params_array
[j
- last_real_param
] = pos_values
[j
];
455 // Adjust the size of the pos_values if it had params
456 if (last_real_param
!= pos_arg_count
) {
457 object [] new_pos_values
= new object [last_real_param
+ 1];
458 Array
.Copy (pos_values
, new_pos_values
, last_real_param
+ 1);
459 pos_values
= new_pos_values
;
462 // Here we do the checks which should be done by corlib or by runtime.
463 // However Zoltan doesn't like it and every Mono compiler has to do it again.
465 if (Type
== TypeManager
.guid_attr_type
) {
467 new Guid ((string)pos_values
[0]);
469 catch (Exception e
) {
470 Error_AttributeEmitError (e
.Message
);
475 if (Type
== TypeManager
.attribute_usage_type
&& (int)pos_values
[0] == 0) {
476 Report
.Error (591, Location
, "Invalid value for argument to `System.AttributeUsage' attribute");
480 if (Type
== TypeManager
.indexer_name_type
|| Type
== TypeManager
.conditional_attribute_type
) {
481 if (!Tokenizer
.IsValidIdentifier ((string)pos_values
[0])) {
482 Report
.Error (633, ((Argument
)PosArguments
[0]).Expr
.Location
,
483 "The argument to the `{0}' attribute must be a valid identifier", GetSignatureForError ());
488 if (Type
== TypeManager
.methodimpl_attr_type
&& pos_values
.Length
== 1 &&
489 pd
.ParameterType (0) == TypeManager
.short_type
&&
490 !System
.Enum
.IsDefined (typeof (MethodImplOptions
), pos_values
[0].ToString ())) {
491 Error_AttributeEmitError ("Incorrect argument value.");
495 return (ConstructorInfo
)constructor
;
498 protected virtual bool ResolveNamedArguments (EmitContext ec
)
500 int named_arg_count
= NamedArguments
.Count
;
502 ArrayList field_infos
= new ArrayList (named_arg_count
);
503 ArrayList prop_infos
= new ArrayList (named_arg_count
);
504 ArrayList field_values
= new ArrayList (named_arg_count
);
505 ArrayList prop_values
= new ArrayList (named_arg_count
);
507 ArrayList seen_names
= new ArrayList(named_arg_count
);
509 foreach (DictionaryEntry de
in NamedArguments
) {
510 string member_name
= (string) de
.Key
;
512 if (seen_names
.Contains(member_name
)) {
513 Report
.Error(643, Location
, "'" + member_name
+ "' duplicate named attribute argument");
516 seen_names
.Add(member_name
);
518 Argument a
= (Argument
) de
.Value
;
519 if (!a
.Resolve (ec
, Location
))
522 Expression member
= Expression
.MemberLookup (
523 ec
.ContainerType
, Type
, member_name
,
524 MemberTypes
.Field
| MemberTypes
.Property
,
525 BindingFlags
.Public
| BindingFlags
.Instance
,
528 if (member
== null) {
529 member
= Expression
.MemberLookup (ec
.ContainerType
, Type
, member_name
,
530 MemberTypes
.Field
| MemberTypes
.Property
, BindingFlags
.NonPublic
| BindingFlags
.Instance
,
533 if (member
!= null) {
534 Expression
.ErrorIsInaccesible (Location
, member
.GetSignatureForError ());
540 Report
.Error (117, Location
, "`{0}' does not contain a definition for `{1}'",
541 TypeManager
.CSharpName (Type
), member_name
);
545 if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
546 Error_InvalidNamedArgument (member_name
);
550 if (a
.Expr
is TypeParameterExpr
){
551 Error_TypeParameterInAttribute (Location
);
555 ObsoleteAttribute obsolete_attr
;
557 if (member
is PropertyExpr
) {
558 PropertyInfo pi
= ((PropertyExpr
) member
).PropertyInfo
;
560 if (!pi
.CanWrite
|| !pi
.CanRead
) {
561 Report
.SymbolRelatedToPreviousError (pi
);
562 Error_InvalidNamedArgument (member_name
);
566 if (!IsValidArgumentType (pi
.PropertyType
)) {
567 Report
.SymbolRelatedToPreviousError (pi
);
568 Error_InvalidNamedAgrumentType (member_name
);
573 if (!a
.Expr
.GetAttributableValue (pi
.PropertyType
, out value))
576 PropertyBase pb
= TypeManager
.GetProperty (pi
);
578 obsolete_attr
= pb
.GetObsoleteAttribute ();
580 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (pi
);
582 prop_values
.Add (value);
586 FieldInfo fi
= ((FieldExpr
) member
).FieldInfo
;
589 Error_InvalidNamedArgument (member_name
);
593 if (!IsValidArgumentType (fi
.FieldType
)) {
594 Report
.SymbolRelatedToPreviousError (fi
);
595 Error_InvalidNamedAgrumentType (member_name
);
600 if (!a
.Expr
.GetAttributableValue (fi
.FieldType
, out value))
603 FieldBase fb
= TypeManager
.GetField (fi
);
605 obsolete_attr
= fb
.GetObsoleteAttribute ();
607 obsolete_attr
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
609 field_values
.Add (value);
610 field_infos
.Add (fi
);
613 if (obsolete_attr
!= null && !Owner
.ResolveContext
.IsInObsoleteScope
)
614 AttributeTester
.Report_ObsoleteMessage (obsolete_attr
, member
.GetSignatureForError (), member
.Location
);
617 prop_info_arr
= new PropertyInfo
[prop_infos
.Count
];
618 field_info_arr
= new FieldInfo
[field_infos
.Count
];
619 field_values_arr
= new object [field_values
.Count
];
620 prop_values_arr
= new object [prop_values
.Count
];
622 field_infos
.CopyTo (field_info_arr
, 0);
623 field_values
.CopyTo (field_values_arr
, 0);
625 prop_values
.CopyTo (prop_values_arr
, 0);
626 prop_infos
.CopyTo (prop_info_arr
, 0);
632 /// Get a string containing a list of valid targets for the attribute 'attr'
634 public string GetValidTargets ()
636 StringBuilder sb
= new StringBuilder ();
637 AttributeTargets targets
= GetAttributeUsage ().ValidOn
;
639 if ((targets
& AttributeTargets
.Assembly
) != 0)
640 sb
.Append ("assembly, ");
642 if ((targets
& AttributeTargets
.Module
) != 0)
643 sb
.Append ("module, ");
645 if ((targets
& AttributeTargets
.Class
) != 0)
646 sb
.Append ("class, ");
648 if ((targets
& AttributeTargets
.Struct
) != 0)
649 sb
.Append ("struct, ");
651 if ((targets
& AttributeTargets
.Enum
) != 0)
652 sb
.Append ("enum, ");
654 if ((targets
& AttributeTargets
.Constructor
) != 0)
655 sb
.Append ("constructor, ");
657 if ((targets
& AttributeTargets
.Method
) != 0)
658 sb
.Append ("method, ");
660 if ((targets
& AttributeTargets
.Property
) != 0)
661 sb
.Append ("property, indexer, ");
663 if ((targets
& AttributeTargets
.Field
) != 0)
664 sb
.Append ("field, ");
666 if ((targets
& AttributeTargets
.Event
) != 0)
667 sb
.Append ("event, ");
669 if ((targets
& AttributeTargets
.Interface
) != 0)
670 sb
.Append ("interface, ");
672 if ((targets
& AttributeTargets
.Parameter
) != 0)
673 sb
.Append ("parameter, ");
675 if ((targets
& AttributeTargets
.Delegate
) != 0)
676 sb
.Append ("delegate, ");
678 if ((targets
& AttributeTargets
.ReturnValue
) != 0)
679 sb
.Append ("return, ");
681 if ((targets
& AttributeTargets
.GenericParameter
) != 0)
682 sb
.Append ("type parameter, ");
683 return sb
.Remove (sb
.Length
- 2, 2).ToString ();
687 /// Returns AttributeUsage attribute for this type
689 AttributeUsageAttribute
GetAttributeUsage ()
691 AttributeUsageAttribute ua
= usage_attr_cache
[Type
] as AttributeUsageAttribute
;
695 Class attr_class
= TypeManager
.LookupClass (Type
);
697 if (attr_class
== null) {
698 object[] usage_attr
= Type
.GetCustomAttributes (TypeManager
.attribute_usage_type
, true);
699 ua
= (AttributeUsageAttribute
)usage_attr
[0];
700 usage_attr_cache
.Add (Type
, ua
);
704 Attribute a
= attr_class
.OptAttributes
== null
706 : attr_class
.OptAttributes
.Search (TypeManager
.attribute_usage_type
);
709 ? DefaultUsageAttribute
710 : a
.GetAttributeUsageAttribute ();
712 usage_attr_cache
.Add (Type
, ua
);
716 AttributeUsageAttribute
GetAttributeUsageAttribute ()
718 if (pos_values
== null)
719 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
720 // But because a lot of attribute class code must be rewritten will be better to wait...
724 return DefaultUsageAttribute
;
726 AttributeUsageAttribute usage_attribute
= new AttributeUsageAttribute ((AttributeTargets
)pos_values
[0]);
728 object field
= GetPropertyValue ("AllowMultiple");
730 usage_attribute
.AllowMultiple
= (bool)field
;
732 field
= GetPropertyValue ("Inherited");
734 usage_attribute
.Inherited
= (bool)field
;
736 return usage_attribute
;
740 /// Returns custom name of indexer
742 public string GetIndexerAttributeValue ()
744 if (pos_values
== null)
745 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
746 // But because a lot of attribute class code must be rewritten will be better to wait...
752 return pos_values
[0] as string;
756 /// Returns condition of ConditionalAttribute
758 public string GetConditionalAttributeValue ()
760 if (pos_values
== null)
761 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
762 // But because a lot of attribute class code must be rewritten will be better to wait...
768 return (string)pos_values
[0];
772 /// Creates the instance of ObsoleteAttribute from this attribute instance
774 public ObsoleteAttribute
GetObsoleteAttribute ()
776 if (pos_values
== null)
777 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
778 // But because a lot of attribute class code must be rewritten will be better to wait...
784 if (pos_values
== null || pos_values
.Length
== 0)
785 return new ObsoleteAttribute ();
787 if (pos_values
.Length
== 1)
788 return new ObsoleteAttribute ((string)pos_values
[0]);
790 return new ObsoleteAttribute ((string)pos_values
[0], (bool)pos_values
[1]);
794 /// Returns value of CLSCompliantAttribute contructor parameter but because the method can be called
795 /// before ApplyAttribute. We need to resolve the arguments.
796 /// This situation occurs when class deps is differs from Emit order.
798 public bool GetClsCompliantAttributeValue ()
800 if (pos_values
== null)
801 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
802 // But because a lot of attribute class code must be rewritten will be better to wait...
808 return (bool)pos_values
[0];
811 public Type
GetCoClassAttributeValue ()
813 if (pos_values
== null)
819 return (Type
)pos_values
[0];
822 public bool CheckTarget ()
824 string[] valid_targets
= Owner
.ValidAttributeTargets
;
825 if (ExplicitTarget
== null || ExplicitTarget
== valid_targets
[0]) {
826 Target
= Owner
.AttributeTargets
;
830 // TODO: we can skip the first item
831 if (((IList
) valid_targets
).Contains (ExplicitTarget
)) {
832 switch (ExplicitTarget
) {
833 case "return": Target
= AttributeTargets
.ReturnValue
; return true;
834 case "param": Target
= AttributeTargets
.Parameter
; return true;
835 case "field": Target
= AttributeTargets
.Field
; return true;
836 case "method": Target
= AttributeTargets
.Method
; return true;
837 case "property": Target
= AttributeTargets
.Property
; return true;
839 throw new InternalErrorException ("Unknown explicit target: " + ExplicitTarget
);
842 StringBuilder sb
= new StringBuilder ();
843 foreach (string s
in valid_targets
) {
847 sb
.Remove (sb
.Length
- 2, 2);
848 Report
.Error (657, Location
, "`{0}' is not a valid attribute location for this declaration. " +
849 "Valid attribute locations for this declaration are `{1}'", ExplicitTarget
, sb
.ToString ());
854 /// Tests permitted SecurityAction for assembly or other types
856 public bool CheckSecurityActionValidity (bool for_assembly
)
858 SecurityAction action
= GetSecurityActionValue ();
861 case SecurityAction
.Demand
:
862 case SecurityAction
.Assert
:
863 case SecurityAction
.Deny
:
864 case SecurityAction
.PermitOnly
:
865 case SecurityAction
.LinkDemand
:
866 case SecurityAction
.InheritanceDemand
:
871 case SecurityAction
.RequestMinimum
:
872 case SecurityAction
.RequestOptional
:
873 case SecurityAction
.RequestRefuse
:
879 Error_AttributeEmitError ("SecurityAction is out of range");
883 Error_AttributeEmitError (String
.Concat ("SecurityAction `", action
, "' is not valid for this declaration"));
887 System
.Security
.Permissions
.SecurityAction
GetSecurityActionValue ()
889 return (SecurityAction
)pos_values
[0];
893 /// Creates instance of SecurityAttribute class and add result of CreatePermission method to permission table.
895 /// <returns></returns>
896 public void ExtractSecurityPermissionSet (ListDictionary permissions
)
898 Type orig_assembly_type
= null;
900 if (TypeManager
.LookupDeclSpace (Type
) != null) {
901 if (!RootContext
.StdLib
) {
902 orig_assembly_type
= Type
.GetType (Type
.FullName
);
904 string orig_version_path
= Environment
.GetEnvironmentVariable ("__SECURITY_BOOTSTRAP_DB");
905 if (orig_version_path
== null) {
906 Error_AttributeEmitError ("security custom attributes can not be referenced from defining assembly");
910 if (orig_sec_assembly
== null) {
911 string file
= Path
.Combine (orig_version_path
, Driver
.OutputFile
);
912 orig_sec_assembly
= Assembly
.LoadFile (file
);
915 orig_assembly_type
= orig_sec_assembly
.GetType (Type
.FullName
, true);
916 if (orig_assembly_type
== null) {
917 Report
.Warning (-112, 1, Location
, "Self-referenced security attribute `{0}' " +
918 "was not found in previous version of assembly");
924 SecurityAttribute sa
;
925 // For all non-selfreferencing security attributes we can avoid all hacks
926 if (orig_assembly_type
== null) {
927 sa
= (SecurityAttribute
) Activator
.CreateInstance (Type
, pos_values
);
929 if (prop_info_arr
!= null) {
930 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
931 PropertyInfo pi
= prop_info_arr
[i
];
932 pi
.SetValue (sa
, prop_values_arr
[i
], null);
936 // HACK: All security attributes have same ctor syntax
937 sa
= (SecurityAttribute
) Activator
.CreateInstance (orig_assembly_type
, new object[] { GetSecurityActionValue () }
);
939 // All types are from newly created assembly but for invocation with old one we need to convert them
940 if (prop_info_arr
!= null) {
941 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
942 PropertyInfo emited_pi
= prop_info_arr
[i
];
943 PropertyInfo pi
= orig_assembly_type
.GetProperty (emited_pi
.Name
, emited_pi
.PropertyType
);
945 object old_instance
= pi
.PropertyType
.IsEnum
?
946 System
.Enum
.ToObject (pi
.PropertyType
, prop_values_arr
[i
]) :
949 pi
.SetValue (sa
, old_instance
, null);
955 perm
= sa
.CreatePermission ();
956 SecurityAction action
= GetSecurityActionValue ();
958 // IS is correct because for corlib we are using an instance from old corlib
959 if (!(perm
is System
.Security
.CodeAccessPermission
)) {
961 case SecurityAction
.Demand
:
962 action
= (SecurityAction
)13;
964 case SecurityAction
.LinkDemand
:
965 action
= (SecurityAction
)14;
967 case SecurityAction
.InheritanceDemand
:
968 action
= (SecurityAction
)15;
973 PermissionSet ps
= (PermissionSet
)permissions
[action
];
975 if (sa
is PermissionSetAttribute
)
976 ps
= new PermissionSet (sa
.Unrestricted
? PermissionState
.Unrestricted
: PermissionState
.None
);
978 ps
= new PermissionSet (PermissionState
.None
);
980 permissions
.Add (action
, ps
);
981 } else if (!ps
.IsUnrestricted () && (sa
is PermissionSetAttribute
) && sa
.Unrestricted
) {
982 ps
= ps
.Union (new PermissionSet (PermissionState
.Unrestricted
));
983 permissions
[action
] = ps
;
985 ps
.AddPermission (perm
);
988 static object GetValue (object value)
990 if (value is EnumConstant
)
991 return ((EnumConstant
) value).GetValue ();
996 public object GetPropertyValue (string name
)
998 if (prop_info_arr
== null)
1001 for (int i
= 0; i
< prop_info_arr
.Length
; ++i
) {
1002 if (prop_info_arr
[i
].Name
== name
)
1003 return prop_values_arr
[i
];
1009 object GetFieldValue (string name
)
1012 if (field_info_arr
== null)
1015 foreach (FieldInfo fi
in field_info_arr
) {
1016 if (fi
.Name
== name
)
1017 return GetValue (field_values_arr
[i
]);
1024 // Theoretically, we can get rid of this, since FieldBuilder.SetCustomAttribute()
1025 // and ParameterBuilder.SetCustomAttribute() are supposed to handle this attribute.
1026 // 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 FieldMember fm
= attr
as FieldMember
;
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 public CharSet
GetCharSetValue ()
1103 return (CharSet
)System
.Enum
.Parse (typeof (CharSet
), pos_values
[0].ToString ());
1106 public MethodImplOptions
GetMethodImplOptions ()
1108 if (pos_values
[0].GetType () != typeof (MethodImplOptions
))
1109 return (MethodImplOptions
)System
.Enum
.ToObject (typeof (MethodImplOptions
), pos_values
[0]);
1110 return (MethodImplOptions
)pos_values
[0];
1113 public LayoutKind
GetLayoutKindValue ()
1115 if (!RootContext
.StdLib
|| pos_values
[0].GetType () != typeof (LayoutKind
))
1116 return (LayoutKind
)System
.Enum
.ToObject (typeof (LayoutKind
), pos_values
[0]);
1118 return (LayoutKind
)pos_values
[0];
1121 public object GetParameterDefaultValue ()
1123 return pos_values
[0];
1126 public override bool Equals (object obj
)
1128 Attribute a
= obj
as Attribute
;
1132 return Type
== a
.Type
&& Target
== a
.Target
;
1135 public override int GetHashCode ()
1137 return base.GetHashCode ();
1141 /// Emit attribute for Attributable symbol
1143 public void Emit (ListDictionary allEmitted
)
1145 CustomAttributeBuilder cb
= Resolve ();
1149 AttributeUsageAttribute usage_attr
= GetAttributeUsage ();
1150 if ((usage_attr
.ValidOn
& Target
) == 0) {
1151 Report
.Error (592, Location
, "The attribute `{0}' is not valid on this declaration type. " +
1152 "It is valid on `{1}' declarations only",
1153 GetSignatureForError (), GetValidTargets ());
1158 foreach (Attributable owner
in owners
)
1159 owner
.ApplyAttributeBuilder (this, cb
);
1161 catch (Exception e
) {
1162 Error_AttributeEmitError (e
.Message
);
1166 if (!usage_attr
.AllowMultiple
&& allEmitted
!= null) {
1167 if (allEmitted
.Contains (this)) {
1168 ArrayList a
= allEmitted
[this] as ArrayList
;
1170 a
= new ArrayList (2);
1171 allEmitted
[this] = a
;
1175 allEmitted
.Add (this, null);
1179 if (!RootContext
.VerifyClsCompliance
)
1182 // Here we are testing attribute arguments for array usage (error 3016)
1183 if (Owner
.IsClsComplianceRequired ()) {
1184 if (PosArguments
!= null) {
1185 foreach (Argument arg
in PosArguments
) {
1186 // Type is undefined (was error 246)
1187 if (arg
.Type
== null)
1190 if (arg
.Type
.IsArray
) {
1191 Report
.Error (3016, Location
, "Arrays as attribute arguments are not CLS-compliant");
1197 if (NamedArguments
== null)
1200 foreach (DictionaryEntry de
in NamedArguments
) {
1201 Argument arg
= (Argument
) de
.Value
;
1203 // Type is undefined (was error 246)
1204 if (arg
.Type
== null)
1207 if (arg
.Type
.IsArray
) {
1208 Report
.Error (3016, Location
, "Arrays as attribute arguments are not CLS-compliant");
1215 public MethodBuilder
DefinePInvokeMethod (TypeBuilder builder
, string name
,
1216 MethodAttributes flags
, Type ret_type
, Type
[] param_types
)
1218 if (pos_values
== null)
1219 // TODO: It is not neccessary to call whole Resolve (ApplyAttribute does it now) we need only ctor args.
1220 // But because a lot of attribute class code must be rewritten will be better to wait...
1226 string dll_name
= (string)pos_values
[0];
1229 CallingConvention cc
= CallingConvention
.Winapi
;
1230 CharSet charset
= CodeGen
.Module
.DefaultCharSet
;
1231 bool preserve_sig
= true;
1232 string entry_point
= name
;
1233 bool best_fit_mapping
= false;
1234 bool throw_on_unmappable
= false;
1235 bool exact_spelling
= false;
1236 bool set_last_error
= false;
1238 bool best_fit_mapping_set
= false;
1239 bool throw_on_unmappable_set
= false;
1240 bool exact_spelling_set
= false;
1241 bool set_last_error_set
= false;
1243 MethodInfo set_best_fit
= null;
1244 MethodInfo set_throw_on
= null;
1245 MethodInfo set_exact_spelling
= null;
1246 MethodInfo set_set_last_error
= null;
1248 if (field_info_arr
!= null) {
1250 for (int i
= 0; i
< field_info_arr
.Length
; i
++) {
1251 switch (field_info_arr
[i
].Name
) {
1252 case "BestFitMapping":
1253 best_fit_mapping
= (bool) field_values_arr
[i
];
1254 best_fit_mapping_set
= true;
1256 case "CallingConvention":
1257 cc
= (CallingConvention
) field_values_arr
[i
];
1260 charset
= (CharSet
) field_values_arr
[i
];
1263 entry_point
= (string) field_values_arr
[i
];
1265 case "ExactSpelling":
1266 exact_spelling
= (bool) field_values_arr
[i
];
1267 exact_spelling_set
= true;
1270 preserve_sig
= (bool) field_values_arr
[i
];
1272 case "SetLastError":
1273 set_last_error
= (bool) field_values_arr
[i
];
1274 set_last_error_set
= true;
1276 case "ThrowOnUnmappableChar":
1277 throw_on_unmappable
= (bool) field_values_arr
[i
];
1278 throw_on_unmappable_set
= true;
1281 throw new InternalErrorException (field_info_arr
[i
].ToString ());
1286 if (throw_on_unmappable_set
|| best_fit_mapping_set
|| exact_spelling_set
|| set_last_error_set
) {
1287 set_best_fit
= typeof (MethodBuilder
).
1288 GetMethod ("set_BestFitMapping", BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1289 set_throw_on
= typeof (MethodBuilder
).
1290 GetMethod ("set_ThrowOnUnmappableChar", BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1291 set_exact_spelling
= typeof (MethodBuilder
).
1292 GetMethod ("set_ExactSpelling", BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1293 set_set_last_error
= typeof (MethodBuilder
).
1294 GetMethod ("set_SetLastError", BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
);
1296 if ((set_best_fit
== null) || (set_throw_on
== null) ||
1297 (set_exact_spelling
== null) || (set_set_last_error
== null)) {
1298 Report
.Error (-1, Location
,
1299 "The ThrowOnUnmappableChar, BestFitMapping, SetLastError, " +
1300 "and ExactSpelling attributes can only be emitted when running on the mono runtime.");
1306 MethodBuilder mb
= builder
.DefinePInvokeMethod (
1307 name
, dll_name
, entry_point
, flags
| MethodAttributes
.HideBySig
| MethodAttributes
.PinvokeImpl
,
1308 CallingConventions
.Standard
, ret_type
, param_types
, cc
, charset
);
1311 mb
.SetImplementationFlags (MethodImplAttributes
.PreserveSig
);
1313 if (throw_on_unmappable_set
)
1314 set_throw_on
.Invoke (mb
, 0, null, new object [] { throw_on_unmappable }
, null);
1315 if (best_fit_mapping_set
)
1316 set_best_fit
.Invoke (mb
, 0, null, new object [] { best_fit_mapping }
, null);
1317 if (exact_spelling_set
)
1318 set_exact_spelling
.Invoke (mb
, 0, null, new object [] { exact_spelling }
, null);
1319 if (set_last_error_set
)
1320 set_set_last_error
.Invoke (mb
, 0, null, new object [] { set_last_error }
, null);
1324 catch (ArgumentException e
) {
1325 Error_AttributeEmitError (e
.Message
);
1330 private Expression
GetValue ()
1332 if (PosArguments
== null || PosArguments
.Count
< 1)
1335 return ((Argument
) PosArguments
[0]).Expr
;
1338 public string GetString ()
1340 Expression e
= GetValue ();
1341 if (e
is StringLiteral
)
1342 return (e
as StringLiteral
).Value
;
1346 public bool GetBoolean ()
1348 Expression e
= GetValue ();
1349 if (e
is BoolLiteral
)
1350 return (e
as BoolLiteral
).Value
;
1357 /// For global attributes (assembly, module) we need special handling.
1358 /// Attributes can be located in the several files
1360 public class GlobalAttribute
: Attribute
1362 public readonly NamespaceEntry ns
;
1364 public GlobalAttribute (NamespaceEntry ns
, string target
,
1365 Expression left_expr
, string identifier
, object[] args
, Location loc
, bool nameEscaped
):
1366 base (target
, left_expr
, identifier
, args
, loc
, nameEscaped
)
1373 // RootContext.Tree.Types has a single NamespaceEntry which gets overwritten
1374 // each time a new file is parsed. However, we need to use the NamespaceEntry
1375 // in effect where the attribute was used. Since code elsewhere cannot assume
1376 // that the NamespaceEntry is right, just overwrite it.
1378 // Precondition: RootContext.Tree.Types == null
1380 if (RootContext
.Tree
.Types
.NamespaceEntry
!= null)
1381 throw new InternalErrorException (Location
+ " non-null NamespaceEntry");
1383 RootContext
.Tree
.Types
.NamespaceEntry
= ns
;
1388 RootContext
.Tree
.Types
.NamespaceEntry
= null;
1391 protected override TypeExpr
ResolveAsTypeTerminal (Expression expr
, IResolveContext ec
, bool silent
)
1395 return base.ResolveAsTypeTerminal (expr
, ec
, silent
);
1402 protected override ConstructorInfo
ResolveConstructor (EmitContext ec
)
1406 return base.ResolveConstructor (ec
);
1413 protected override bool ResolveNamedArguments (EmitContext ec
)
1417 return base.ResolveNamedArguments (ec
);
1425 public class Attributes
{
1426 public readonly ArrayList Attrs
;
1428 public Attributes (Attribute a
)
1430 Attrs
= new ArrayList ();
1434 public Attributes (ArrayList attrs
)
1439 public void AddAttributes (ArrayList attrs
)
1441 Attrs
.AddRange (attrs
);
1444 public void AttachTo (Attributable attributable
)
1446 foreach (Attribute a
in Attrs
)
1447 a
.AttachTo (attributable
);
1451 /// Checks whether attribute target is valid for the current element
1453 public bool CheckTargets ()
1455 foreach (Attribute a
in Attrs
) {
1456 if (!a
.CheckTarget ())
1462 public Attribute
Search (Type t
)
1464 foreach (Attribute a
in Attrs
) {
1465 if (a
.ResolveType () == t
)
1472 /// Returns all attributes of type 't'. Use it when attribute is AllowMultiple = true
1474 public Attribute
[] SearchMulti (Type t
)
1476 ArrayList ar
= null;
1478 foreach (Attribute a
in Attrs
) {
1479 if (a
.ResolveType () == t
) {
1481 ar
= new ArrayList ();
1486 return ar
== null ? null : ar
.ToArray (typeof (Attribute
)) as Attribute
[];
1493 ListDictionary ld
= Attrs
.Count
> 1 ? new ListDictionary () : null;
1495 foreach (Attribute a
in Attrs
)
1498 if (ld
== null || ld
.Count
== 0)
1501 foreach (DictionaryEntry d
in ld
) {
1502 if (d
.Value
== null)
1505 foreach (Attribute collision
in (ArrayList
)d
.Value
)
1506 Report
.SymbolRelatedToPreviousError (collision
.Location
, "");
1508 Attribute a
= (Attribute
)d
.Key
;
1509 Report
.Error (579, a
.Location
, "The attribute `{0}' cannot be applied multiple times", a
.GetSignatureForError ());
1513 public bool Contains (Type t
)
1515 return Search (t
) != null;
1520 /// Helper class for attribute verification routine.
1522 sealed class AttributeTester
1524 static PtrHashtable analyzed_types
;
1525 static PtrHashtable analyzed_types_obsolete
;
1526 static PtrHashtable analyzed_member_obsolete
;
1527 static PtrHashtable analyzed_method_excluded
;
1530 static PtrHashtable fixed_buffer_cache
;
1533 static object TRUE
= new object ();
1534 static object FALSE
= new object ();
1536 static AttributeTester ()
1541 private AttributeTester ()
1545 public static void Reset ()
1547 analyzed_types
= new PtrHashtable ();
1548 analyzed_types_obsolete
= new PtrHashtable ();
1549 analyzed_member_obsolete
= new PtrHashtable ();
1550 analyzed_method_excluded
= new PtrHashtable ();
1552 fixed_buffer_cache
= new PtrHashtable ();
1556 public enum Result
{
1563 /// Returns true if parameters of two compared methods are CLS-Compliant.
1564 /// It tests differing only in ref or out, or in array rank.
1566 public static Result
AreOverloadedMethodParamsClsCompliant (Type
[] types_a
, Type
[] types_b
)
1568 if (types_a
== null || types_b
== null)
1571 if (types_a
.Length
!= types_b
.Length
)
1574 Result result
= Result
.Ok
;
1575 for (int i
= 0; i
< types_b
.Length
; ++i
) {
1576 Type aType
= types_a
[i
];
1577 Type bType
= types_b
[i
];
1579 if (aType
.IsArray
&& bType
.IsArray
) {
1580 Type a_el_type
= aType
.GetElementType ();
1581 Type b_el_type
= bType
.GetElementType ();
1582 if (aType
.GetArrayRank () != bType
.GetArrayRank () && a_el_type
== b_el_type
) {
1583 result
= Result
.RefOutArrayError
;
1587 if (a_el_type
.IsArray
|| b_el_type
.IsArray
) {
1588 result
= Result
.ArrayArrayError
;
1593 Type aBaseType
= aType
;
1594 bool is_either_ref_or_out
= false;
1596 if (aType
.IsByRef
|| aType
.IsPointer
) {
1597 aBaseType
= aType
.GetElementType ();
1598 is_either_ref_or_out
= true;
1601 Type bBaseType
= bType
;
1602 if (bType
.IsByRef
|| bType
.IsPointer
)
1604 bBaseType
= bType
.GetElementType ();
1605 is_either_ref_or_out
= !is_either_ref_or_out
;
1608 if (aBaseType
!= bBaseType
)
1611 if (is_either_ref_or_out
)
1612 result
= Result
.RefOutArrayError
;
1618 /// This method tests the CLS compliance of external types. It doesn't test type visibility.
1620 public static bool IsClsCompliant (Type type
)
1625 object type_compliance
= analyzed_types
[type
];
1626 if (type_compliance
!= null)
1627 return type_compliance
== TRUE
;
1629 if (type
.IsPointer
) {
1630 analyzed_types
.Add (type
, null);
1635 if (type
.IsArray
|| type
.IsByRef
) {
1636 result
= IsClsCompliant (TypeManager
.GetElementType (type
));
1638 result
= AnalyzeTypeCompliance (type
);
1640 analyzed_types
.Add (type
, result
? TRUE
: FALSE
);
1645 /// Returns IFixedBuffer implementation if field is fixed buffer else null.
1647 public static IFixedBuffer
GetFixedBuffer (FieldInfo fi
)
1649 FieldBase fb
= TypeManager
.GetField (fi
);
1651 return fb
as IFixedBuffer
;
1655 object o
= fixed_buffer_cache
[fi
];
1657 if (System
.Attribute
.GetCustomAttribute (fi
, TypeManager
.fixed_buffer_attr_type
) == null) {
1658 fixed_buffer_cache
.Add (fi
, FALSE
);
1662 IFixedBuffer iff
= new FixedFieldExternal (fi
);
1663 fixed_buffer_cache
.Add (fi
, iff
);
1670 return (IFixedBuffer
)o
;
1676 public static void VerifyModulesClsCompliance ()
1678 Module
[] modules
= RootNamespace
.Global
.Modules
;
1679 if (modules
== null)
1682 // The first module is generated assembly
1683 for (int i
= 1; i
< modules
.Length
; ++i
) {
1684 Module module
= modules
[i
];
1685 if (!IsClsCompliant (module
)) {
1686 Report
.Error (3013, "Added modules must be marked with the CLSCompliant attribute " +
1687 "to match the assembly", module
.Name
);
1693 public static Type
GetImportedIgnoreCaseClsType (string name
)
1695 foreach (Assembly a
in RootNamespace
.Global
.Assemblies
) {
1696 Type t
= a
.GetType (name
, false, true);
1700 if (IsClsCompliant (t
))
1706 static bool IsClsCompliant (ICustomAttributeProvider attribute_provider
)
1708 object[] CompliantAttribute
= attribute_provider
.GetCustomAttributes (TypeManager
.cls_compliant_attribute_type
, false);
1709 if (CompliantAttribute
.Length
== 0)
1712 return ((CLSCompliantAttribute
)CompliantAttribute
[0]).IsCompliant
;
1715 static bool AnalyzeTypeCompliance (Type type
)
1717 type
= TypeManager
.DropGenericTypeArguments (type
);
1718 DeclSpace ds
= TypeManager
.LookupDeclSpace (type
);
1720 return ds
.IsClsComplianceRequired ();
1723 if (type
.IsGenericParameter
)
1726 object[] CompliantAttribute
= type
.GetCustomAttributes (TypeManager
.cls_compliant_attribute_type
, false);
1727 if (CompliantAttribute
.Length
== 0)
1728 return IsClsCompliant (type
.Assembly
);
1730 return ((CLSCompliantAttribute
)CompliantAttribute
[0]).IsCompliant
;
1734 /// Returns instance of ObsoleteAttribute when type is obsolete
1736 public static ObsoleteAttribute
GetObsoleteAttribute (Type type
)
1738 object type_obsolete
= analyzed_types_obsolete
[type
];
1739 if (type_obsolete
== FALSE
)
1742 if (type_obsolete
!= null)
1743 return (ObsoleteAttribute
)type_obsolete
;
1745 ObsoleteAttribute result
= null;
1746 if (type
.IsByRef
|| type
.IsArray
|| type
.IsPointer
) {
1747 result
= GetObsoleteAttribute (TypeManager
.GetElementType (type
));
1748 } else if (type
.IsGenericParameter
|| type
.IsGenericType
)
1751 DeclSpace type_ds
= TypeManager
.LookupDeclSpace (type
);
1753 // Type is external, we can get attribute directly
1754 if (type_ds
== null) {
1755 object[] attribute
= type
.GetCustomAttributes (TypeManager
.obsolete_attribute_type
, false);
1756 if (attribute
.Length
== 1)
1757 result
= (ObsoleteAttribute
)attribute
[0];
1759 // Is null during corlib bootstrap
1760 if (TypeManager
.obsolete_attribute_type
!= null)
1761 result
= type_ds
.GetObsoleteAttribute ();
1765 // Cannot use .Add because of corlib bootstrap
1766 analyzed_types_obsolete
[type
] = result
== null ? FALSE
: result
;
1771 /// Returns instance of ObsoleteAttribute when method is obsolete
1773 public static ObsoleteAttribute
GetMethodObsoleteAttribute (MethodBase mb
)
1775 IMethodData mc
= TypeManager
.GetMethod (mb
);
1777 return mc
.GetObsoleteAttribute ();
1779 // compiler generated methods are not registered by AddMethod
1780 if (mb
.DeclaringType
is TypeBuilder
)
1783 if (mb
.IsSpecialName
) {
1784 PropertyInfo pi
= PropertyExpr
.AccessorTable
[mb
] as PropertyInfo
;
1786 // FIXME: This is buggy as properties from this assembly are included as well
1788 //return GetMemberObsoleteAttribute (pi);
1792 return GetMemberObsoleteAttribute (mb
);
1796 /// Returns instance of ObsoleteAttribute when member is obsolete
1798 public static ObsoleteAttribute
GetMemberObsoleteAttribute (MemberInfo mi
)
1800 object type_obsolete
= analyzed_member_obsolete
[mi
];
1801 if (type_obsolete
== FALSE
)
1804 if (type_obsolete
!= null)
1805 return (ObsoleteAttribute
)type_obsolete
;
1807 if ((mi
.DeclaringType
is TypeBuilder
) || mi
.DeclaringType
.IsGenericType
)
1810 ObsoleteAttribute oa
= System
.Attribute
.GetCustomAttribute (mi
, TypeManager
.obsolete_attribute_type
, false)
1811 as ObsoleteAttribute
;
1812 analyzed_member_obsolete
.Add (mi
, oa
== null ? FALSE
: oa
);
1817 /// Common method for Obsolete error/warning reporting.
1819 public static void Report_ObsoleteMessage (ObsoleteAttribute oa
, string member
, Location loc
)
1822 Report
.Error (619, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1826 if (oa
.Message
== null) {
1827 Report
.Warning (612, 1, loc
, "`{0}' is obsolete", member
);
1830 Report
.Warning (618, 2, loc
, "`{0}' is obsolete: `{1}'", member
, oa
.Message
);
1833 public static bool IsConditionalMethodExcluded (MethodBase mb
)
1835 mb
= TypeManager
.DropGenericMethodArguments (mb
);
1836 if ((mb
is MethodBuilder
) || (mb
is ConstructorBuilder
))
1839 object excluded
= analyzed_method_excluded
[mb
];
1840 if (excluded
!= null)
1841 return excluded
== TRUE
? true : false;
1843 ConditionalAttribute
[] attrs
= mb
.GetCustomAttributes (TypeManager
.conditional_attribute_type
, true)
1844 as ConditionalAttribute
[];
1845 if (attrs
.Length
== 0) {
1846 analyzed_method_excluded
.Add (mb
, FALSE
);
1850 foreach (ConditionalAttribute a
in attrs
) {
1851 if (RootContext
.AllDefines
.Contains (a
.ConditionString
)) {
1852 analyzed_method_excluded
.Add (mb
, FALSE
);
1856 analyzed_method_excluded
.Add (mb
, TRUE
);
1861 /// Analyzes class whether it has attribute which has ConditionalAttribute
1862 /// and its condition is not defined.
1864 public static bool IsAttributeExcluded (Type type
)
1869 Class class_decl
= TypeManager
.LookupDeclSpace (type
) as Class
;
1871 // TODO: add caching
1872 // TODO: merge all Type bases attribute caching to one cache to save memory
1873 if (class_decl
== null) {
1874 object[] attributes
= type
.GetCustomAttributes (TypeManager
.conditional_attribute_type
, false);
1875 foreach (ConditionalAttribute ca
in attributes
) {
1876 if (RootContext
.AllDefines
.Contains (ca
.ConditionString
))
1879 return attributes
.Length
> 0;
1882 return class_decl
.IsExcluded ();
1885 public static Type
GetCoClassAttribute (Type type
)
1887 TypeContainer tc
= TypeManager
.LookupInterface (type
);
1889 object[] o
= type
.GetCustomAttributes (TypeManager
.coclass_attr_type
, false);
1892 return ((System
.Runtime
.InteropServices
.CoClassAttribute
)o
[0]).CoClass
;
1895 if (tc
.OptAttributes
== null)
1898 Attribute a
= tc
.OptAttributes
.Search (TypeManager
.coclass_attr_type
);
1902 return a
.GetCoClassAttributeValue ();