2 // attribute.cs: Attribute Handler
\r
4 // Author: Ravi Pratap (ravi@ximian.com)
\r
6 // Licensed under the terms of the GNU GPL
\r
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
\r
13 using System.Diagnostics;
\r
14 using System.Collections;
\r
15 using System.Reflection;
\r
16 using System.Reflection.Emit;
\r
17 using System.Runtime.InteropServices;
\r
18 using System.Runtime.CompilerServices;
\r
21 namespace Mono.CSharp {
\r
23 public class Attribute {
\r
24 public readonly string Name;
\r
25 public readonly ArrayList Arguments;
\r
32 // The following are only meaningful when the attribute
\r
33 // being emitted is an AttributeUsage attribute
\r
35 AttributeTargets Targets;
\r
39 bool UsageAttr = false;
\r
41 MethodImplOptions ImplOptions;
\r
42 UnmanagedType UnmanagedType;
\r
43 CustomAttributeBuilder cb;
\r
45 // non-null if named args present after Resolve () is called
\r
46 PropertyInfo [] prop_info_arr;
\r
47 FieldInfo [] field_info_arr;
\r
48 object [] field_values_arr;
\r
49 object [] prop_values_arr;
\r
51 public Attribute (string name, ArrayList args, Location loc)
\r
58 void Error_InvalidNamedArgument (string name)
\r
60 Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
\r
61 "argument. Named attribute arguments must be fields which are not " +
\r
62 "readonly, static or const, or properties with a set accessor which "+
\r
66 static void Error_AttributeArgumentNotValid (Location loc)
\r
68 Report.Error (182, loc,
\r
69 "An attribute argument must be a constant expression, typeof " +
\r
70 "expression or array creation expression");
\r
73 static void Error_AttributeConstructorMismatch (Location loc)
\r
75 Report.Error (-6, loc,
\r
76 "Could not find a constructor for this argument list.");
\r
79 static void Error_TypeParameterInAttribute (Location loc)
\r
82 -202, loc, "Can not use a type parameter in an attribute");
\r
86 /// Tries to resolve the type of the attribute. Flags an error if it can't.
\r
88 private Type CheckAttributeType (EmitContext ec) {
\r
90 bool isattributeclass = true;
\r
92 t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
\r
94 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
\r
95 if (isattributeclass)
\r
98 t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
\r
100 if (t.IsSubclassOf (TypeManager.attribute_type))
\r
103 if (!isattributeclass) {
\r
104 Report.Error (616, Location, "'" + Name + "': is not an attribute class");
\r
108 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
\r
112 246, Location, "Could not find attribute '" + Name + "' (are you" +
\r
113 " missing a using directive or an assembly reference ?)");
\r
117 public Type ResolveType (EmitContext ec)
\r
119 Type = CheckAttributeType (ec);
\r
124 /// Validates the guid string
\r
126 bool ValidateGuid (string guid)
\r
132 Report.Error (647, Location, "Format of GUID is invalid: " + guid);
\r
138 // Given an expression, if the expression is a valid attribute-argument-expression
\r
139 // returns an object that can be used to encode it, or null on failure.
\r
141 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)
\r
143 if (e is Constant) {
\r
144 result = ((Constant) e).GetValue ();
\r
146 } else if (e is TypeOf) {
\r
147 result = ((TypeOf) e).TypeArg;
\r
149 } else if (e is ArrayCreation){
\r
150 result = ((ArrayCreation) e).EncodeAsAttribute ();
\r
151 if (result != null)
\r
153 } else if (e is EmptyCast) {
\r
155 if (((EmptyCast) e).Child is Constant) {
\r
156 result = ((Constant) ((EmptyCast)e).Child).GetValue();
\r
162 Error_AttributeArgumentNotValid (loc);
\r
166 public CustomAttributeBuilder Resolve (EmitContext ec)
\r
169 Type = CheckAttributeType (ec);
\r
173 bool MethodImplAttr = false;
\r
174 bool MarshalAsAttr = false;
\r
175 bool GuidAttr = false;
\r
178 bool DoCompares = true;
\r
181 // If we are a certain special attribute, we
\r
182 // set the information accordingly
\r
185 if (Type == TypeManager.attribute_usage_type)
\r
187 else if (Type == TypeManager.methodimpl_attr_type)
\r
188 MethodImplAttr = true;
\r
189 else if (Type == TypeManager.marshal_as_attr_type)
\r
190 MarshalAsAttr = true;
\r
191 else if (Type == TypeManager.guid_attr_type)
\r
194 DoCompares = false;
\r
196 // Now we extract the positional and named arguments
\r
198 ArrayList pos_args = new ArrayList ();
\r
199 ArrayList named_args = new ArrayList ();
\r
200 int pos_arg_count = 0;
\r
202 if (Arguments != null) {
\r
203 pos_args = (ArrayList) Arguments [0];
\r
204 if (pos_args != null)
\r
205 pos_arg_count = pos_args.Count;
\r
206 if (Arguments.Count > 1)
\r
207 named_args = (ArrayList) Arguments [1];
\r
210 object [] pos_values = new object [pos_arg_count];
\r
213 // First process positional arguments
\r
217 for (i = 0; i < pos_arg_count; i++) {
\r
218 Argument a = (Argument) pos_args [i];
\r
221 if (!a.Resolve (ec, Location))
\r
227 if (!GetAttributeArgumentExpression (e, Location, out val))
\r
230 pos_values [i] = val;
\r
233 this.Targets = (AttributeTargets) pos_values [0];
\r
234 else if (MethodImplAttr)
\r
235 this.ImplOptions = (MethodImplOptions) pos_values [0];
\r
236 else if (GuidAttr){
\r
238 // we will later check the validity of the type
\r
240 if (pos_values [0] is string){
\r
241 if (!ValidateGuid ((string) pos_values [0]))
\r
245 } else if (MarshalAsAttr)
\r
246 this.UnmanagedType =
\r
247 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
\r
252 // Now process named arguments
\r
255 ArrayList field_infos = null;
\r
256 ArrayList prop_infos = null;
\r
257 ArrayList field_values = null;
\r
258 ArrayList prop_values = null;
\r
260 if (named_args.Count > 0) {
\r
261 field_infos = new ArrayList ();
\r
262 prop_infos = new ArrayList ();
\r
263 field_values = new ArrayList ();
\r
264 prop_values = new ArrayList ();
\r
267 for (i = 0; i < named_args.Count; i++) {
\r
268 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
269 string member_name = (string) de.Key;
\r
270 Argument a = (Argument) de.Value;
\r
273 if (!a.Resolve (ec, Location))
\r
276 Expression member = Expression.MemberLookup (
\r
277 ec, Type, member_name,
\r
278 MemberTypes.Field | MemberTypes.Property,
\r
279 BindingFlags.Public | BindingFlags.Instance,
\r
282 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
\r
283 Error_InvalidNamedArgument (member_name);
\r
288 if (e is TypeParameterExpr){
\r
289 Error_TypeParameterInAttribute (Location);
\r
293 if (member is PropertyExpr) {
\r
294 PropertyExpr pe = (PropertyExpr) member;
\r
295 PropertyInfo pi = pe.PropertyInfo;
\r
297 if (!pi.CanWrite) {
\r
298 Error_InvalidNamedArgument (member_name);
\r
302 if (e is Constant) {
\r
303 object o = ((Constant) e).GetValue ();
\r
304 prop_values.Add (o);
\r
307 if (member_name == "AllowMultiple")
\r
308 this.AllowMultiple = (bool) o;
\r
309 if (member_name == "Inherited")
\r
310 this.Inherited = (bool) o;
\r
313 } else if (e is TypeOf) {
\r
314 prop_values.Add (((TypeOf) e).TypeArg);
\r
315 } else if (e is ArrayCreation) {
\r
316 prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());
\r
318 Error_AttributeArgumentNotValid (Location);
\r
322 prop_infos.Add (pi);
\r
324 } else if (member is FieldExpr) {
\r
325 FieldExpr fe = (FieldExpr) member;
\r
326 FieldInfo fi = fe.FieldInfo;
\r
328 if (fi.IsInitOnly) {
\r
329 Error_InvalidNamedArgument (member_name);
\r
334 // Handle charset here, and set the TypeAttributes
\r
336 if (e is Constant){
\r
337 object value = ((Constant) e).GetValue ();
\r
339 field_values.Add (value);
\r
340 } else if (e is TypeOf) {
\r
341 field_values.Add (((TypeOf) e).TypeArg);
\r
343 Error_AttributeArgumentNotValid (Location);
\r
347 field_infos.Add (fi);
\r
351 Expression mg = Expression.MemberLookup (
\r
352 ec, Type, ".ctor", MemberTypes.Constructor,
\r
353 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
\r
357 Error_AttributeConstructorMismatch (Location);
\r
361 MethodBase constructor = Invocation.OverloadResolve (
\r
362 ec, (MethodGroupExpr) mg, pos_args, false, Location);
\r
364 if (constructor == null) {
\r
365 Error_AttributeConstructorMismatch (Location);
\r
370 // Now we perform some checks on the positional args as they
\r
371 // cannot be null for a constructor which expects a parameter
\r
375 ParameterData pd = Invocation.GetParameterData (constructor);
\r
377 int group_in_params_array = Int32.MaxValue;
\r
379 if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)
\r
380 group_in_params_array = pc-1;
\r
382 for (int j = 0; j < pos_arg_count; ++j) {
\r
383 Argument a = (Argument) pos_args [j];
\r
385 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
\r
386 Error_AttributeArgumentNotValid (Location);
\r
390 if (j < group_in_params_array)
\r
393 if (j == group_in_params_array){
\r
394 object v = pos_values [j];
\r
395 int count = pos_arg_count - j;
\r
397 object [] array = new object [count];
\r
398 pos_values [j] = array;
\r
401 object [] array = (object []) pos_values [group_in_params_array];
\r
403 array [j - group_in_params_array] = pos_values [j];
\r
408 // Adjust the size of the pos_values if it had params
\r
410 if (group_in_params_array != Int32.MaxValue){
\r
411 int argc = group_in_params_array+1;
\r
412 object [] new_pos_values = new object [argc];
\r
414 for (int p = 0; p < argc; p++)
\r
415 new_pos_values [p] = pos_values [p];
\r
416 pos_values = new_pos_values;
\r
420 if (named_args.Count > 0) {
\r
421 prop_info_arr = new PropertyInfo [prop_infos.Count];
\r
422 field_info_arr = new FieldInfo [field_infos.Count];
\r
423 field_values_arr = new object [field_values.Count];
\r
424 prop_values_arr = new object [prop_values.Count];
\r
426 field_infos.CopyTo (field_info_arr, 0);
\r
427 field_values.CopyTo (field_values_arr, 0);
\r
429 prop_values.CopyTo (prop_values_arr, 0);
\r
430 prop_infos.CopyTo (prop_info_arr, 0);
\r
432 cb = new CustomAttributeBuilder (
\r
433 (ConstructorInfo) constructor, pos_values,
\r
434 prop_info_arr, prop_values_arr,
\r
435 field_info_arr, field_values_arr);
\r
438 cb = new CustomAttributeBuilder (
\r
439 (ConstructorInfo) constructor, pos_values);
\r
440 } catch (NullReferenceException) {
\r
442 // Don't know what to do here
\r
445 -101, Location, "NullReferenceException while trying to create attribute." +
\r
446 "Something's wrong!");
\r
447 } catch (Exception e) {
\r
450 // using System.ComponentModel;
\r
451 // [DefaultValue (CollectionChangeAction.Add)]
\r
452 // class X { static void Main () {} }
\r
456 "The compiler can not encode this attribute in .NET due to\n" +
\r
457 "\ta bug in the .NET runtime. Try the Mono runtime.\nThe error was: " + e.Message);
\r
464 /// Get a string containing a list of valid targets for the attribute 'attr'
\r
466 static string GetValidTargets (Attribute attr)
\r
468 StringBuilder sb = new StringBuilder ();
\r
469 AttributeTargets targets = 0;
\r
471 TypeContainer a = TypeManager.LookupAttr (attr.Type);
\r
475 System.Attribute [] attrs = null;
\r
478 attrs = System.Attribute.GetCustomAttributes (attr.Type);
\r
481 Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
\r
482 " (maybe you forgot to set the usage using the" +
\r
483 " AttributeUsage attribute ?).");
\r
487 foreach (System.Attribute tmp in attrs)
\r
488 if (tmp is AttributeUsageAttribute) {
\r
489 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
493 targets = a.Targets;
\r
496 if ((targets & AttributeTargets.Assembly) != 0)
\r
497 sb.Append ("'assembly' ");
\r
499 if ((targets & AttributeTargets.Class) != 0)
\r
500 sb.Append ("'class' ");
\r
502 if ((targets & AttributeTargets.Constructor) != 0)
\r
503 sb.Append ("'constructor' ");
\r
505 if ((targets & AttributeTargets.Delegate) != 0)
\r
506 sb.Append ("'delegate' ");
\r
508 if ((targets & AttributeTargets.Enum) != 0)
\r
509 sb.Append ("'enum' ");
\r
511 if ((targets & AttributeTargets.Event) != 0)
\r
512 sb.Append ("'event' ");
\r
514 if ((targets & AttributeTargets.Field) != 0)
\r
515 sb.Append ("'field' ");
\r
517 if ((targets & AttributeTargets.Interface) != 0)
\r
518 sb.Append ("'interface' ");
\r
520 if ((targets & AttributeTargets.Method) != 0)
\r
521 sb.Append ("'method' ");
\r
523 if ((targets & AttributeTargets.Module) != 0)
\r
524 sb.Append ("'module' ");
\r
526 if ((targets & AttributeTargets.Parameter) != 0)
\r
527 sb.Append ("'parameter' ");
\r
529 if ((targets & AttributeTargets.Property) != 0)
\r
530 sb.Append ("'property' ");
\r
532 if ((targets & AttributeTargets.ReturnValue) != 0)
\r
533 sb.Append ("'return value' ");
\r
535 if ((targets & AttributeTargets.Struct) != 0)
\r
536 sb.Append ("'struct' ");
\r
538 return sb.ToString ();
\r
542 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
\r
545 592, loc, "Attribute '" + a.Name +
\r
546 "' is not valid on this declaration type. " +
\r
547 "It is valid on " + GetValidTargets (a) + "declarations only.");
\r
551 /// Ensure that Attribute 'a' is being applied to the right language element (target)
\r
553 public static bool CheckAttributeTarget (Attribute a, object element)
\r
555 TypeContainer attr = TypeManager.LookupAttr (a.Type);
\r
556 AttributeTargets targets = 0;
\r
558 if (attr == null) {
\r
559 System.Attribute [] attrs = null;
\r
562 attrs = System.Attribute.GetCustomAttributes (a.Type);
\r
565 Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
\r
566 " (maybe you forgot to set the usage using the" +
\r
567 " AttributeUsage attribute ?).");
\r
571 foreach (System.Attribute tmp in attrs)
\r
572 if (tmp is AttributeUsageAttribute) {
\r
573 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
577 targets = attr.Targets;
\r
580 if (element is Class) {
\r
581 if ((targets & AttributeTargets.Class) != 0)
\r
586 } else if (element is Struct) {
\r
587 if ((targets & AttributeTargets.Struct) != 0)
\r
591 } else if (element is Constructor) {
\r
592 if ((targets & AttributeTargets.Constructor) != 0)
\r
596 } else if (element is Delegate) {
\r
597 if ((targets & AttributeTargets.Delegate) != 0)
\r
601 } else if (element is Enum) {
\r
602 if ((targets & AttributeTargets.Enum) != 0)
\r
606 } else if (element is Event) {
\r
607 if ((targets & AttributeTargets.Event) != 0)
\r
611 } else if (element is Field || element is FieldBuilder) {
\r
612 if ((targets & AttributeTargets.Field) != 0)
\r
616 } else if (element is Interface) {
\r
617 if ((targets & AttributeTargets.Interface) != 0)
\r
621 } else if (element is Method || element is Operator ||
\r
622 element is Accessor) {
\r
623 if ((targets & AttributeTargets.Method) != 0)
\r
627 } else if (element is ParameterBuilder) {
\r
628 if ((targets & AttributeTargets.Parameter) != 0 ||
\r
629 (targets & AttributeTargets.ReturnValue) != 0)
\r
633 } else if (element is Property || element is Indexer ||
\r
634 element is Accessor) {
635 if ((targets & AttributeTargets.Property) != 0)
\r
639 } else if (element is AssemblyClass){
640 if ((targets & AttributeTargets.Assembly) != 0)
\r
644 } else if (element is ModuleClass){
645 if ((targets & AttributeTargets.Module) != 0)
655 // This method should be invoked to pull the IndexerName attribute from an
\r
656 // Indexer if it exists.
\r
658 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
\r
660 if (opt_attrs == null)
\r
662 if (opt_attrs.AttributeSections == null)
\r
665 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
666 if (asec.Attributes == null)
\r
669 foreach (Attribute a in asec.Attributes){
\r
670 if (a.ResolveType (ec) == null)
\r
673 if (a.Type != TypeManager.indexer_name_type)
\r
677 // So we have found an IndexerName, pull the data out.
\r
679 if (a.Arguments == null || a.Arguments [0] == null){
\r
680 Error_AttributeConstructorMismatch (a.Location);
\r
683 ArrayList pos_args = (ArrayList) a.Arguments [0];
\r
684 if (pos_args.Count == 0){
\r
685 Error_AttributeConstructorMismatch (a.Location);
\r
689 Argument arg = (Argument) pos_args [0];
\r
690 if (!arg.Resolve (ec, a.Location))
\r
693 Expression e = arg.Expr;
\r
694 if (!(e is StringConstant)){
\r
695 Error_AttributeConstructorMismatch (a.Location);
\r
700 // Remove the attribute from the list
\r
702 asec.Attributes.Remove (a);
\r
704 return (((StringConstant) e).Value);
\r
711 // This pulls the condition name out of a Conditional attribute
\r
713 public string Conditional_GetConditionName ()
\r
716 // So we have a Conditional, pull the data out.
\r
718 if (Arguments == null || Arguments [0] == null){
\r
719 Error_AttributeConstructorMismatch (Location);
\r
723 ArrayList pos_args = (ArrayList) Arguments [0];
\r
724 if (pos_args.Count != 1){
\r
725 Error_AttributeConstructorMismatch (Location);
\r
729 Argument arg = (Argument) pos_args [0];
\r
730 if (!(arg.Expr is StringConstant)){
\r
731 Error_AttributeConstructorMismatch (Location);
\r
735 return ((StringConstant) arg.Expr).Value;
\r
739 // This pulls the obsolete message and error flag out of an Obsolete attribute
\r
741 public string Obsolete_GetObsoleteMessage (out bool is_error)
\r
745 // So we have an Obsolete, pull the data out.
\r
747 if (Arguments == null || Arguments [0] == null)
\r
750 ArrayList pos_args = (ArrayList) Arguments [0];
\r
751 if (pos_args.Count == 0)
\r
753 else if (pos_args.Count > 2){
\r
754 Error_AttributeConstructorMismatch (Location);
\r
758 Argument arg = (Argument) pos_args [0];
\r
759 if (!(arg.Expr is StringConstant)){
\r
760 Error_AttributeConstructorMismatch (Location);
\r
764 if (pos_args.Count == 2){
\r
765 Argument arg2 = (Argument) pos_args [1];
\r
766 if (!(arg2.Expr is BoolConstant)){
\r
767 Error_AttributeConstructorMismatch (Location);
\r
770 is_error = ((BoolConstant) arg2.Expr).Value;
\r
773 return ((StringConstant) arg.Expr).Value;
\r
776 static object GetFieldValue (Attribute a, string name)
\r
779 if (a.field_info_arr == null)
\r
782 foreach (FieldInfo fi in a.field_info_arr) {
\r
783 if (fi.Name == name)
\r
784 return a.field_values_arr [i];
\r
790 static UnmanagedMarshal GetMarshal (Attribute a)
\r
792 object o = GetFieldValue (a, "ArraySubType");
\r
793 UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;
\r
794 switch (a.UnmanagedType) {
\r
795 case UnmanagedType.CustomMarshaler:
\r
796 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
\r
797 BindingFlags.Static | BindingFlags.Public);
\r
798 if (define_custom == null)
\r
801 object [] args = new object [4];
\r
802 args [0] = GetFieldValue (a, "MarshalTypeRef");
\r
803 args [1] = GetFieldValue (a, "MarshalCookie");
\r
804 args [2] = GetFieldValue (a, "MarshalType");
\r
805 args [3] = Guid.Empty;
\r
806 return (UnmanagedMarshal) define_custom.Invoke (null, args);
\r
808 case UnmanagedType.LPArray:
\r
809 return UnmanagedMarshal.DefineLPArray (array_sub_type);
\r
811 case UnmanagedType.SafeArray:
\r
812 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
\r
814 case UnmanagedType.ByValArray:
\r
815 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));
\r
817 case UnmanagedType.ByValTStr:
\r
818 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));
\r
821 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
\r
826 /// Applies the attributes specified on target 'kind' to the `builder'.
\r
828 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
\r
829 Attributes opt_attrs)
\r
831 Type attr_type = null;
\r
833 if (opt_attrs == null)
\r
835 if (opt_attrs.AttributeSections == null)
\r
838 ArrayList emitted_attrs = new ArrayList ();
\r
839 ArrayList emitted_targets = new ArrayList ();
\r
841 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
842 string attr_target = asec.Target;
\r
844 if (asec.Attributes == null)
\r
847 if (attr_target == "return" && !(builder is ParameterBuilder))
\r
850 foreach (Attribute a in asec.Attributes) {
\r
851 Location loc = a.Location;
\r
852 CustomAttributeBuilder cb = a.Resolve (ec);
\r
853 attr_type = a.Type;
\r
858 if (!(kind is TypeContainer))
\r
859 if (!CheckAttributeTarget (a, kind)) {
\r
860 Error_AttributeNotValidForElement (a, loc);
\r
865 // Perform the check for duplicate attributes
\r
867 if (emitted_attrs.Contains (attr_type) &&
\r
868 emitted_targets.Contains (attr_target) &&
\r
869 !TypeManager.AreMultipleAllowed (attr_type)) {
\r
870 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
\r
874 if (kind is IAttributeSupport) {
875 if (attr_type == TypeManager.methodimpl_attr_type && a.ImplOptions == MethodImplOptions.InternalCall) {
876 ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime);
879 IAttributeSupport attributeSupport = kind as IAttributeSupport;
880 attributeSupport.SetCustomAttribute (cb);
883 else if (kind is Method || kind is Operator || kind is Accessor) {
\r
884 if (attr_type == TypeManager.methodimpl_attr_type) {
\r
885 if (a.ImplOptions == MethodImplOptions.InternalCall)
\r
886 ((MethodBuilder) builder).
\r
887 SetImplementationFlags (
\r
888 MethodImplAttributes.InternalCall |
\r
889 MethodImplAttributes.Runtime);
\r
891 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
892 } else if (attr_type != TypeManager.dllimport_type){
\r
893 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
895 } else if (kind is Constructor) {
\r
896 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
\r
897 } else if (kind is Field) {
\r
898 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
899 UnmanagedMarshal marshal = GetMarshal (a);
\r
900 if (marshal == null) {
\r
901 Report.Warning (-24, loc,
\r
902 "The Microsoft Runtime cannot set this marshal info. " +
\r
903 "Please use the Mono runtime instead.");
\r
905 ((FieldBuilder) builder).SetMarshal (marshal);
\r
908 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
910 } else if (kind is Property || kind is Indexer) {
\r
912 if (builder is PropertyBuilder)
913 ((PropertyBuilder) builder).SetCustomAttribute (cb);
\r
915 // This is for the case we are setting attributes on
916 // the get and set accessors
918 else if (builder is MethodBuilder)
919 ((MethodBuilder) builder).SetCustomAttribute (cb);
920 } else if (kind is Event) {
\r
921 ((MyEventBuilder) builder).SetCustomAttribute (cb);
\r
922 } else if (kind is ParameterBuilder) {
\r
924 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
925 UnmanagedMarshal marshal = GetMarshal (a);
\r
926 if (marshal == null) {
\r
927 Report.Warning (-24, loc,
\r
928 "The Microsoft Runtime cannot set this marshal info. " +
\r
929 "Please use the Mono runtime instead.");
\r
931 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
936 ((ParameterBuilder) builder).SetCustomAttribute (cb);
\r
937 } catch (System.ArgumentException) {
\r
938 Report.Warning (-24, loc,
\r
939 "The Microsoft Runtime cannot set attributes \n" +
\r
940 "on the return type of a method. Please use the \n" +
\r
941 "Mono runtime instead.");
\r
945 } else if (kind is Enum) {
\r
946 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
948 } else if (kind is TypeContainer) {
\r
949 TypeContainer tc = (TypeContainer) kind;
\r
952 tc.Targets = a.Targets;
\r
953 tc.AllowMultiple = a.AllowMultiple;
\r
954 tc.Inherited = a.Inherited;
\r
956 TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
\r
959 } else if (attr_type == TypeManager.default_member_type) {
\r
960 if (tc.Indexers != null) {
\r
961 Report.Error (646, loc,
\r
962 "Cannot specify the DefaultMember attribute on" +
\r
963 " a type containing an indexer");
\r
968 if (!CheckAttributeTarget (a, kind)) {
\r
969 Error_AttributeNotValidForElement (a, loc);
\r
975 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
976 } catch (System.ArgumentException) {
\r
979 "The CharSet named property on StructLayout\n"+
\r
980 "\tdoes not work correctly on Microsoft.NET\n"+
\r
981 "\tYou might want to remove the CharSet declaration\n"+
\r
982 "\tor compile using the Mono runtime instead of the\n"+
\r
983 "\tMicrosoft .NET runtime");
\r
985 } else if (kind is Delegate){
\r
986 if (!CheckAttributeTarget (a, kind)) {
\r
987 Error_AttributeNotValidForElement (a, loc);
\r
991 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
992 } catch (System.ArgumentException) {
\r
995 "The CharSet named property on StructLayout\n"+
\r
996 "\tdoes not work correctly on Microsoft.NET\n"+
\r
997 "\tYou might want to remove the CharSet declaration\n"+
\r
998 "\tor compile using the Mono runtime instead of the\n"+
\r
999 "\tMicrosoft .NET runtime");
\r
1001 } else if (kind is Interface) {
\r
1002 Interface iface = (Interface) kind;
\r
1004 if ((attr_type == TypeManager.default_member_type) &&
\r
1005 (iface.Indexers != null)) {
\r
1008 "Cannot specify the DefaultMember attribute on" +
\r
1009 " a type containing an indexer");
\r
1013 if (!CheckAttributeTarget (a, kind)) {
\r
1014 Error_AttributeNotValidForElement (a, loc);
\r
1018 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
1019 } else if (kind is AssemblyBuilder){
\r
1020 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
\r
1021 } else if (kind is ModuleBuilder) {
\r
1022 ((ModuleBuilder) builder).SetCustomAttribute (cb);
\r
1023 } else if (kind is FieldBuilder) {
\r
1024 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
1025 UnmanagedMarshal marshal = GetMarshal (a);
\r
1026 if (marshal == null) {
\r
1027 Report.Warning (-24, loc,
\r
1028 "The Microsoft Runtime cannot set this marshal info. " +
\r
1029 "Please use the Mono runtime instead.");
\r
1031 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
1034 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
1037 throw new Exception ("Unknown kind: " + kind);
\r
1040 // Once an attribute type has been emitted once we
\r
1041 // keep track of the info to prevent multiple occurences
\r
1042 // for attributes which do not explicitly allow it
\r
1044 if (!emitted_attrs.Contains (attr_type))
\r
1045 emitted_attrs.Add (attr_type);
\r
1048 // We keep of this target-wise and so emitted targets
\r
1049 // are tracked too
\r
1051 if (!emitted_targets.Contains (attr_target))
\r
1052 emitted_targets.Add (attr_target);
\r
1059 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
\r
1060 MethodAttributes flags, Type ret_type, Type [] param_types)
\r
1063 // We extract from the attribute the information we need
\r
1066 if (Arguments == null) {
\r
1067 Console.WriteLine ("Internal error : this is not supposed to happen !");
\r
1071 Type = CheckAttributeType (ec);
\r
1075 ArrayList named_args = new ArrayList ();
\r
1077 ArrayList pos_args = (ArrayList) Arguments [0];
\r
1078 if (Arguments.Count > 1)
\r
1079 named_args = (ArrayList) Arguments [1];
\r
1082 string dll_name = null;
\r
1084 Argument tmp = (Argument) pos_args [0];
\r
1086 if (!tmp.Resolve (ec, Location))
\r
1089 if (tmp.Expr is Constant)
\r
1090 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
\r
1092 Error_AttributeArgumentNotValid (Location);
\r
1096 // Now we process the named arguments
\r
1097 CallingConvention cc = CallingConvention.Winapi;
\r
1098 CharSet charset = CharSet.Ansi;
\r
1099 bool preserve_sig = true;
\r
1101 bool exact_spelling = false;
\r
1103 bool set_last_err = false;
\r
1104 string entry_point = null;
\r
1106 for (int i = 0; i < named_args.Count; i++) {
\r
1108 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
1110 string member_name = (string) de.Key;
\r
1111 Argument a = (Argument) de.Value;
\r
1113 if (!a.Resolve (ec, Location))
\r
1116 Expression member = Expression.MemberLookup (
\r
1117 ec, Type, member_name,
\r
1118 MemberTypes.Field | MemberTypes.Property,
\r
1119 BindingFlags.Public | BindingFlags.Instance,
\r
1122 if (member == null || !(member is FieldExpr)) {
\r
1123 Error_InvalidNamedArgument (member_name);
\r
1127 if (member is FieldExpr) {
\r
1128 FieldExpr fe = (FieldExpr) member;
\r
1129 FieldInfo fi = fe.FieldInfo;
\r
1131 if (fi.IsInitOnly) {
\r
1132 Error_InvalidNamedArgument (member_name);
\r
1136 if (a.Expr is Constant) {
\r
1137 Constant c = (Constant) a.Expr;
\r
1139 if (member_name == "CallingConvention")
\r
1140 cc = (CallingConvention) c.GetValue ();
\r
1141 else if (member_name == "CharSet")
\r
1142 charset = (CharSet) c.GetValue ();
\r
1143 else if (member_name == "EntryPoint")
\r
1144 entry_point = (string) c.GetValue ();
\r
1145 else if (member_name == "SetLastError")
\r
1146 set_last_err = (bool) c.GetValue ();
\r
1148 else if (member_name == "ExactSpelling")
\r
1149 exact_spelling = (bool) c.GetValue ();
\r
1151 else if (member_name == "PreserveSig")
\r
1152 preserve_sig = (bool) c.GetValue ();
\r
1154 Error_AttributeArgumentNotValid (Location);
\r
1161 if (entry_point == null)
\r
1162 entry_point = name;
\r
1164 charset = (CharSet)((int)charset | 0x40);
\r
1166 MethodBuilder mb = builder.DefinePInvokeMethod (
\r
1167 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
\r
1168 CallingConventions.Standard,
\r
1175 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
\r
1182 public class AttributeSection {
\r
1183 public readonly string Target;
\r
1184 public readonly ArrayList Attributes;
\r
1186 public AttributeSection (string target, ArrayList attrs)
\r
1189 Attributes = attrs;
\r
1194 public class Attributes {
\r
1195 public ArrayList AttributeSections;
\r
1197 public Attributes (AttributeSection a)
\r
1199 AttributeSections = new ArrayList ();
\r
1200 AttributeSections.Add (a);
\r
1204 public void AddAttributeSection (AttributeSection a)
\r
1206 if (a != null && !AttributeSections.Contains (a))
\r
1207 AttributeSections.Add (a);
\r
1210 public bool Contains (Type t)
\r
1212 foreach (AttributeSection attr_section in AttributeSections){
\r
1213 foreach (Attribute a in attr_section.Attributes){
\r
1223 public interface IAttributeSupport {
1224 void SetCustomAttribute (CustomAttributeBuilder customBuilder);