3 // attribute.cs: Attribute Handler
\r
5 // Author: Ravi Pratap (ravi@ximian.com)
\r
7 // Licensed under the terms of the GNU GPL
\r
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
\r
14 using System.Diagnostics;
\r
15 using System.Collections;
\r
16 using System.Reflection;
\r
17 using System.Reflection.Emit;
\r
18 using System.Runtime.InteropServices;
\r
19 using System.Runtime.CompilerServices;
\r
22 namespace Mono.CSharp {
\r
24 public class Attribute {
\r
25 public readonly string Name;
\r
26 public readonly ArrayList Arguments;
\r
33 // The following are only meaningful when the attribute
\r
34 // being emitted is an AttributeUsage attribute
\r
36 AttributeTargets Targets;
\r
40 bool UsageAttr = false;
\r
42 MethodImplOptions ImplOptions;
\r
43 UnmanagedType UnmanagedType;
\r
44 CustomAttributeBuilder cb;
\r
46 // non-null if named args present after Resolve () is called
\r
47 PropertyInfo [] prop_info_arr;
\r
48 FieldInfo [] field_info_arr;
\r
49 object [] field_values_arr;
\r
50 object [] prop_values_arr;
\r
52 public Attribute (string name, ArrayList args, Location loc)
\r
59 void Error_InvalidNamedArgument (string name)
\r
61 Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
\r
62 "argument. Named attribute arguments must be fields which are not " +
\r
63 "readonly, static or const, or properties with a set accessor which "+
\r
67 static void Error_AttributeArgumentNotValid (Location loc)
\r
69 Report.Error (182, loc,
\r
70 "An attribute argument must be a constant expression, typeof " +
\r
71 "expression or array creation expression");
\r
74 static void Error_AttributeConstructorMismatch (Location loc)
\r
76 Report.Error (-6, loc,
\r
77 "Could not find a constructor for this argument list.");
\r
80 static void Error_TypeParameterInAttribute (Location loc)
\r
83 -202, loc, "Can not use a type parameter in an attribute");
\r
87 /// Tries to resolve the type of the attribute. Flags an error if it can't.
\r
89 private Type CheckAttributeType (EmitContext ec) {
\r
91 bool isattributeclass = true;
\r
93 t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
\r
95 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
\r
96 if (isattributeclass)
\r
99 t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
\r
101 if (t.IsSubclassOf (TypeManager.attribute_type))
\r
104 if (!isattributeclass) {
\r
105 Report.Error (616, Location, "'" + Name + "': is not an attribute class");
\r
109 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
\r
113 246, Location, "Could not find attribute '" + Name + "' (are you" +
\r
114 " missing a using directive or an assembly reference ?)");
\r
118 public Type ResolveType (EmitContext ec)
\r
120 Type = CheckAttributeType (ec);
\r
125 /// Validates the guid string
\r
127 bool ValidateGuid (string guid)
\r
133 Report.Error (647, Location, "Format of GUID is invalid: " + guid);
\r
139 // Given an expression, if the expression is a valid attribute-argument-expression
\r
140 // returns an object that can be used to encode it, or null on failure.
\r
142 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)
\r
144 if (e is Constant) {
\r
145 result = ((Constant) e).GetValue ();
\r
147 } else if (e is TypeOf) {
\r
148 result = ((TypeOf) e).TypeArg;
\r
150 } else if (e is ArrayCreation){
\r
151 result = ((ArrayCreation) e).EncodeAsAttribute ();
\r
152 if (result != null)
\r
154 } else if (e is EmptyCast) {
\r
156 if (((EmptyCast) e).Child is Constant) {
\r
157 result = ((Constant) ((EmptyCast)e).Child).GetValue();
\r
163 Error_AttributeArgumentNotValid (loc);
\r
167 public CustomAttributeBuilder Resolve (EmitContext ec)
\r
170 Type = CheckAttributeType (ec);
\r
174 bool MethodImplAttr = false;
\r
175 bool MarshalAsAttr = false;
\r
176 bool GuidAttr = false;
\r
179 bool DoCompares = true;
\r
182 // If we are a certain special attribute, we
\r
183 // set the information accordingly
\r
186 if (Type == TypeManager.attribute_usage_type)
\r
188 else if (Type == TypeManager.methodimpl_attr_type)
\r
189 MethodImplAttr = true;
\r
190 else if (Type == TypeManager.marshal_as_attr_type)
\r
191 MarshalAsAttr = true;
\r
192 else if (Type == TypeManager.guid_attr_type)
\r
195 DoCompares = false;
\r
197 // Now we extract the positional and named arguments
\r
199 ArrayList pos_args = new ArrayList ();
\r
200 ArrayList named_args = new ArrayList ();
\r
201 int pos_arg_count = 0;
\r
203 if (Arguments != null) {
\r
204 pos_args = (ArrayList) Arguments [0];
\r
205 if (pos_args != null)
\r
206 pos_arg_count = pos_args.Count;
\r
207 if (Arguments.Count > 1)
\r
208 named_args = (ArrayList) Arguments [1];
\r
211 object [] pos_values = new object [pos_arg_count];
\r
214 // First process positional arguments
\r
218 for (i = 0; i < pos_arg_count; i++) {
\r
219 Argument a = (Argument) pos_args [i];
\r
222 if (!a.Resolve (ec, Location))
\r
228 if (!GetAttributeArgumentExpression (e, Location, out val))
\r
231 pos_values [i] = val;
\r
234 this.Targets = (AttributeTargets) pos_values [0];
\r
235 else if (MethodImplAttr)
\r
236 this.ImplOptions = (MethodImplOptions) pos_values [0];
\r
237 else if (GuidAttr){
\r
239 // we will later check the validity of the type
\r
241 if (pos_values [0] is string){
\r
242 if (!ValidateGuid ((string) pos_values [0]))
\r
246 } else if (MarshalAsAttr)
\r
247 this.UnmanagedType =
\r
248 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
\r
253 // Now process named arguments
\r
256 ArrayList field_infos = null;
\r
257 ArrayList prop_infos = null;
\r
258 ArrayList field_values = null;
\r
259 ArrayList prop_values = null;
\r
261 if (named_args.Count > 0) {
\r
262 field_infos = new ArrayList ();
\r
263 prop_infos = new ArrayList ();
\r
264 field_values = new ArrayList ();
\r
265 prop_values = new ArrayList ();
\r
268 for (i = 0; i < named_args.Count; i++) {
\r
269 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
270 string member_name = (string) de.Key;
\r
271 Argument a = (Argument) de.Value;
\r
274 if (!a.Resolve (ec, Location))
\r
277 Expression member = Expression.MemberLookup (
\r
278 ec, Type, member_name,
\r
279 MemberTypes.Field | MemberTypes.Property,
\r
280 BindingFlags.Public | BindingFlags.Instance,
\r
283 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
\r
284 Error_InvalidNamedArgument (member_name);
\r
289 if (e is TypeParameterExpr){
\r
290 Error_TypeParameterInAttribute (Location);
\r
294 if (member is PropertyExpr) {
\r
295 PropertyExpr pe = (PropertyExpr) member;
\r
296 PropertyInfo pi = pe.PropertyInfo;
\r
298 if (!pi.CanWrite) {
\r
299 Error_InvalidNamedArgument (member_name);
\r
303 if (e is Constant) {
\r
304 object o = ((Constant) e).GetValue ();
\r
305 prop_values.Add (o);
\r
308 if (member_name == "AllowMultiple")
\r
309 this.AllowMultiple = (bool) o;
\r
310 if (member_name == "Inherited")
\r
311 this.Inherited = (bool) o;
\r
314 } else if (e is TypeOf) {
\r
315 prop_values.Add (((TypeOf) e).TypeArg);
\r
316 } else if (e is ArrayCreation) {
\r
317 prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());
\r
319 Error_AttributeArgumentNotValid (Location);
\r
323 prop_infos.Add (pi);
\r
325 } else if (member is FieldExpr) {
\r
326 FieldExpr fe = (FieldExpr) member;
\r
327 FieldInfo fi = fe.FieldInfo;
\r
329 if (fi.IsInitOnly) {
\r
330 Error_InvalidNamedArgument (member_name);
\r
335 // Handle charset here, and set the TypeAttributes
\r
337 if (e is Constant){
\r
338 object value = ((Constant) e).GetValue ();
\r
340 field_values.Add (value);
\r
341 } else if (e is TypeOf) {
\r
342 field_values.Add (((TypeOf) e).TypeArg);
\r
344 Error_AttributeArgumentNotValid (Location);
\r
348 field_infos.Add (fi);
\r
352 Expression mg = Expression.MemberLookup (
\r
353 ec, Type, ".ctor", MemberTypes.Constructor,
\r
354 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
\r
358 Error_AttributeConstructorMismatch (Location);
\r
362 MethodBase constructor = Invocation.OverloadResolve (
\r
363 ec, (MethodGroupExpr) mg, pos_args, false, Location);
\r
365 if (constructor == null) {
\r
366 Error_AttributeConstructorMismatch (Location);
\r
371 // Now we perform some checks on the positional args as they
\r
372 // cannot be null for a constructor which expects a parameter
\r
376 ParameterData pd = Invocation.GetParameterData (constructor);
\r
378 int group_in_params_array = Int32.MaxValue;
\r
380 if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)
\r
381 group_in_params_array = pc-1;
\r
383 for (int j = 0; j < pos_arg_count; ++j) {
\r
384 Argument a = (Argument) pos_args [j];
\r
386 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
\r
387 Error_AttributeArgumentNotValid (Location);
\r
391 if (j < group_in_params_array)
\r
394 if (j == group_in_params_array){
\r
395 object v = pos_values [j];
\r
396 int count = pos_arg_count - j;
\r
398 object [] array = new object [count];
\r
399 pos_values [j] = array;
\r
402 object [] array = (object []) pos_values [group_in_params_array];
\r
404 array [j - group_in_params_array] = pos_values [j];
\r
409 // Adjust the size of the pos_values if it had params
\r
411 if (group_in_params_array != Int32.MaxValue){
\r
412 int argc = group_in_params_array+1;
\r
413 object [] new_pos_values = new object [argc];
\r
415 for (int p = 0; p < argc; p++)
\r
416 new_pos_values [p] = pos_values [p];
\r
417 pos_values = new_pos_values;
\r
421 if (named_args.Count > 0) {
\r
422 prop_info_arr = new PropertyInfo [prop_infos.Count];
\r
423 field_info_arr = new FieldInfo [field_infos.Count];
\r
424 field_values_arr = new object [field_values.Count];
\r
425 prop_values_arr = new object [prop_values.Count];
\r
427 field_infos.CopyTo (field_info_arr, 0);
\r
428 field_values.CopyTo (field_values_arr, 0);
\r
430 prop_values.CopyTo (prop_values_arr, 0);
\r
431 prop_infos.CopyTo (prop_info_arr, 0);
\r
433 cb = new CustomAttributeBuilder (
\r
434 (ConstructorInfo) constructor, pos_values,
\r
435 prop_info_arr, prop_values_arr,
\r
436 field_info_arr, field_values_arr);
\r
439 cb = new CustomAttributeBuilder (
\r
440 (ConstructorInfo) constructor, pos_values);
\r
441 } catch (NullReferenceException) {
\r
443 // Don't know what to do here
\r
446 -101, Location, "NullReferenceException while trying to create attribute." +
\r
447 "Something's wrong!");
\r
448 } catch (Exception e) {
\r
451 // using System.ComponentModel;
\r
452 // [DefaultValue (CollectionChangeAction.Add)]
\r
453 // class X { static void Main () {} }
\r
457 "The compiler can not encode this attribute in .NET due to\n" +
\r
458 "\ta bug in the .NET runtime. Try the Mono runtime.\nThe error was: " + e.Message);
\r
465 /// Get a string containing a list of valid targets for the attribute 'attr'
\r
467 static string GetValidTargets (Attribute attr)
\r
469 StringBuilder sb = new StringBuilder ();
\r
470 AttributeTargets targets = 0;
\r
472 TypeContainer a = TypeManager.LookupAttr (attr.Type);
\r
476 System.Attribute [] attrs = null;
\r
479 attrs = System.Attribute.GetCustomAttributes (attr.Type);
\r
482 Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
\r
483 " (maybe you forgot to set the usage using the" +
\r
484 " AttributeUsage attribute ?).");
\r
488 foreach (System.Attribute tmp in attrs)
\r
489 if (tmp is AttributeUsageAttribute) {
\r
490 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
494 targets = a.Targets;
\r
497 if ((targets & AttributeTargets.Assembly) != 0)
\r
498 sb.Append ("'assembly' ");
\r
500 if ((targets & AttributeTargets.Class) != 0)
\r
501 sb.Append ("'class' ");
\r
503 if ((targets & AttributeTargets.Constructor) != 0)
\r
504 sb.Append ("'constructor' ");
\r
506 if ((targets & AttributeTargets.Delegate) != 0)
\r
507 sb.Append ("'delegate' ");
\r
509 if ((targets & AttributeTargets.Enum) != 0)
\r
510 sb.Append ("'enum' ");
\r
512 if ((targets & AttributeTargets.Event) != 0)
\r
513 sb.Append ("'event' ");
\r
515 if ((targets & AttributeTargets.Field) != 0)
\r
516 sb.Append ("'field' ");
\r
518 if ((targets & AttributeTargets.Interface) != 0)
\r
519 sb.Append ("'interface' ");
\r
521 if ((targets & AttributeTargets.Method) != 0)
\r
522 sb.Append ("'method' ");
\r
524 if ((targets & AttributeTargets.Module) != 0)
\r
525 sb.Append ("'module' ");
\r
527 if ((targets & AttributeTargets.Parameter) != 0)
\r
528 sb.Append ("'parameter' ");
\r
530 if ((targets & AttributeTargets.Property) != 0)
\r
531 sb.Append ("'property' ");
\r
533 if ((targets & AttributeTargets.ReturnValue) != 0)
\r
534 sb.Append ("'return value' ");
\r
536 if ((targets & AttributeTargets.Struct) != 0)
\r
537 sb.Append ("'struct' ");
\r
539 return sb.ToString ();
\r
543 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
\r
546 592, loc, "Attribute '" + a.Name +
\r
547 "' is not valid on this declaration type. " +
\r
548 "It is valid on " + GetValidTargets (a) + "declarations only.");
\r
552 /// Ensure that Attribute 'a' is being applied to the right language element (target)
\r
554 public static bool CheckAttributeTarget (Attribute a, object element)
\r
556 TypeContainer attr = TypeManager.LookupAttr (a.Type);
\r
557 AttributeTargets targets = 0;
\r
559 if (attr == null) {
\r
560 System.Attribute [] attrs = null;
\r
563 attrs = System.Attribute.GetCustomAttributes (a.Type);
\r
566 Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
\r
567 " (maybe you forgot to set the usage using the" +
\r
568 " AttributeUsage attribute ?).");
\r
572 foreach (System.Attribute tmp in attrs)
\r
573 if (tmp is AttributeUsageAttribute) {
\r
574 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
578 targets = attr.Targets;
\r
581 if (element is Class) {
\r
582 if ((targets & AttributeTargets.Class) != 0)
\r
587 } else if (element is Struct) {
\r
588 if ((targets & AttributeTargets.Struct) != 0)
\r
592 } else if (element is Constructor) {
\r
593 if ((targets & AttributeTargets.Constructor) != 0)
\r
597 } else if (element is Delegate) {
\r
598 if ((targets & AttributeTargets.Delegate) != 0)
\r
602 } else if (element is Enum) {
\r
603 if ((targets & AttributeTargets.Enum) != 0)
\r
607 } else if (element is Event) {
\r
608 if ((targets & AttributeTargets.Event) != 0)
\r
612 } else if (element is Field || element is FieldBuilder) {
\r
613 if ((targets & AttributeTargets.Field) != 0)
\r
617 } else if (element is Interface) {
\r
618 if ((targets & AttributeTargets.Interface) != 0)
\r
622 } else if (element is Method || element is Operator ||
\r
623 element is Accessor) {
\r
624 if ((targets & AttributeTargets.Method) != 0)
\r
628 } else if (element is ParameterBuilder) {
\r
629 if ((targets & AttributeTargets.Parameter) != 0 ||
\r
630 (targets & AttributeTargets.ReturnValue) != 0)
\r
634 } else if (element is Property || element is Indexer ||
\r
635 element is Accessor) {
636 if ((targets & AttributeTargets.Property) != 0)
\r
640 } else if (element is AssemblyClass){
641 if ((targets & AttributeTargets.Assembly) != 0)
\r
645 } else if (element is ModuleClass){
646 if ((targets & AttributeTargets.Module) != 0)
656 // This method should be invoked to pull the IndexerName attribute from an
\r
657 // Indexer if it exists.
\r
659 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
\r
661 if (opt_attrs == null)
\r
663 if (opt_attrs.AttributeSections == null)
\r
666 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
667 if (asec.Attributes == null)
\r
670 foreach (Attribute a in asec.Attributes){
\r
671 if (a.ResolveType (ec) == null)
\r
674 if (a.Type != TypeManager.indexer_name_type)
\r
678 // So we have found an IndexerName, pull the data out.
\r
680 if (a.Arguments == null || a.Arguments [0] == null){
\r
681 Error_AttributeConstructorMismatch (a.Location);
\r
684 ArrayList pos_args = (ArrayList) a.Arguments [0];
\r
685 if (pos_args.Count == 0){
\r
686 Error_AttributeConstructorMismatch (a.Location);
\r
690 Argument arg = (Argument) pos_args [0];
\r
691 if (!arg.Resolve (ec, a.Location))
\r
694 Expression e = arg.Expr;
\r
695 if (!(e is StringConstant)){
\r
696 Error_AttributeConstructorMismatch (a.Location);
\r
701 // Remove the attribute from the list
\r
703 asec.Attributes.Remove (a);
\r
705 return (((StringConstant) e).Value);
\r
712 // This pulls the condition name out of a Conditional attribute
\r
714 public string Conditional_GetConditionName ()
\r
717 // So we have a Conditional, pull the data out.
\r
719 if (Arguments == null || Arguments [0] == null){
\r
720 Error_AttributeConstructorMismatch (Location);
\r
724 ArrayList pos_args = (ArrayList) Arguments [0];
\r
725 if (pos_args.Count != 1){
\r
726 Error_AttributeConstructorMismatch (Location);
\r
730 Argument arg = (Argument) pos_args [0];
\r
731 if (!(arg.Expr is StringConstant)){
\r
732 Error_AttributeConstructorMismatch (Location);
\r
736 return ((StringConstant) arg.Expr).Value;
\r
740 // This pulls the obsolete message and error flag out of an Obsolete attribute
\r
742 public string Obsolete_GetObsoleteMessage (out bool is_error)
\r
746 // So we have an Obsolete, pull the data out.
\r
748 if (Arguments == null || Arguments [0] == null)
\r
751 ArrayList pos_args = (ArrayList) Arguments [0];
\r
752 if (pos_args.Count == 0)
\r
754 else if (pos_args.Count > 2){
\r
755 Error_AttributeConstructorMismatch (Location);
\r
759 Argument arg = (Argument) pos_args [0];
\r
760 if (!(arg.Expr is StringConstant)){
\r
761 Error_AttributeConstructorMismatch (Location);
\r
765 if (pos_args.Count == 2){
\r
766 Argument arg2 = (Argument) pos_args [1];
\r
767 if (!(arg2.Expr is BoolConstant)){
\r
768 Error_AttributeConstructorMismatch (Location);
\r
771 is_error = ((BoolConstant) arg2.Expr).Value;
\r
774 return ((StringConstant) arg.Expr).Value;
\r
777 static object GetFieldValue (Attribute a, string name)
\r
780 if (a.field_info_arr == null)
\r
783 foreach (FieldInfo fi in a.field_info_arr) {
\r
784 if (fi.Name == name)
\r
785 return a.field_values_arr [i];
\r
791 static UnmanagedMarshal GetMarshal (Attribute a)
\r
793 object o = GetFieldValue (a, "ArraySubType");
\r
794 UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;
\r
795 switch (a.UnmanagedType) {
\r
796 case UnmanagedType.CustomMarshaler:
\r
797 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
\r
798 BindingFlags.Static | BindingFlags.Public);
\r
799 if (define_custom == null)
\r
802 object [] args = new object [4];
\r
803 args [0] = GetFieldValue (a, "MarshalTypeRef");
\r
804 args [1] = GetFieldValue (a, "MarshalCookie");
\r
805 args [2] = GetFieldValue (a, "MarshalType");
\r
806 args [3] = Guid.Empty;
\r
807 return (UnmanagedMarshal) define_custom.Invoke (null, args);
\r
809 case UnmanagedType.LPArray:
\r
810 return UnmanagedMarshal.DefineLPArray (array_sub_type);
\r
812 case UnmanagedType.SafeArray:
\r
813 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
\r
815 case UnmanagedType.ByValArray:
\r
816 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));
\r
818 case UnmanagedType.ByValTStr:
\r
819 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));
\r
822 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
\r
827 /// Applies the attributes specified on target 'kind' to the `builder'.
\r
829 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
\r
830 Attributes opt_attrs)
\r
832 Type attr_type = null;
\r
834 if (opt_attrs == null)
\r
836 if (opt_attrs.AttributeSections == null)
\r
839 ArrayList emitted_attrs = new ArrayList ();
\r
840 ArrayList emitted_targets = new ArrayList ();
\r
842 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
843 string attr_target = asec.Target;
\r
845 if (asec.Attributes == null)
\r
848 if (attr_target == "return" && !(builder is ParameterBuilder))
\r
851 foreach (Attribute a in asec.Attributes) {
\r
852 Location loc = a.Location;
\r
853 CustomAttributeBuilder cb = a.Resolve (ec);
\r
854 attr_type = a.Type;
\r
859 if (!(kind is TypeContainer))
\r
860 if (!CheckAttributeTarget (a, kind)) {
\r
861 Error_AttributeNotValidForElement (a, loc);
\r
866 // Perform the check for duplicate attributes
\r
868 if (emitted_attrs.Contains (attr_type) &&
\r
869 emitted_targets.Contains (attr_target) &&
\r
870 !TypeManager.AreMultipleAllowed (attr_type)) {
\r
871 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
\r
875 if (kind is IAttributeSupport) {
876 if (attr_type == TypeManager.methodimpl_attr_type && a.ImplOptions == MethodImplOptions.InternalCall) {
877 ((MethodBuilder) builder).SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime);
880 IAttributeSupport attributeSupport = kind as IAttributeSupport;
881 attributeSupport.SetCustomAttribute (cb);
884 else if (kind is Method || kind is Operator || kind is Accessor) {
\r
885 if (attr_type == TypeManager.methodimpl_attr_type) {
\r
886 if (a.ImplOptions == MethodImplOptions.InternalCall)
\r
887 ((MethodBuilder) builder).
\r
888 SetImplementationFlags (
\r
889 MethodImplAttributes.InternalCall |
\r
890 MethodImplAttributes.Runtime);
\r
892 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
893 } else if (attr_type != TypeManager.dllimport_type){
\r
894 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
896 } else if (kind is Constructor) {
\r
897 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
\r
898 } else if (kind is Field) {
\r
899 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
900 UnmanagedMarshal marshal = GetMarshal (a);
\r
901 if (marshal == null) {
\r
902 Report.Warning (-24, loc,
\r
903 "The Microsoft Runtime cannot set this marshal info. " +
\r
904 "Please use the Mono runtime instead.");
\r
906 ((FieldBuilder) builder).SetMarshal (marshal);
\r
909 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
911 } else if (kind is Property || kind is Indexer) {
\r
913 if (builder is PropertyBuilder)
914 ((PropertyBuilder) builder).SetCustomAttribute (cb);
\r
916 // This is for the case we are setting attributes on
917 // the get and set accessors
919 else if (builder is MethodBuilder)
920 ((MethodBuilder) builder).SetCustomAttribute (cb);
921 } else if (kind is Event) {
\r
922 ((MyEventBuilder) builder).SetCustomAttribute (cb);
\r
923 } else if (kind is ParameterBuilder) {
\r
925 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
926 UnmanagedMarshal marshal = GetMarshal (a);
\r
927 if (marshal == null) {
\r
928 Report.Warning (-24, loc,
\r
929 "The Microsoft Runtime cannot set this marshal info. " +
\r
930 "Please use the Mono runtime instead.");
\r
932 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
937 ((ParameterBuilder) builder).SetCustomAttribute (cb);
\r
938 } catch (System.ArgumentException) {
\r
939 Report.Warning (-24, loc,
\r
940 "The Microsoft Runtime cannot set attributes \n" +
\r
941 "on the return type of a method. Please use the \n" +
\r
942 "Mono runtime instead.");
\r
946 } else if (kind is Enum) {
\r
947 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
949 } else if (kind is TypeContainer) {
\r
950 TypeContainer tc = (TypeContainer) kind;
\r
953 tc.Targets = a.Targets;
\r
954 tc.AllowMultiple = a.AllowMultiple;
\r
955 tc.Inherited = a.Inherited;
\r
957 TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
\r
960 } else if (attr_type == TypeManager.default_member_type) {
\r
961 if (tc.Indexers != null) {
\r
962 Report.Error (646, loc,
\r
963 "Cannot specify the DefaultMember attribute on" +
\r
964 " a type containing an indexer");
\r
969 if (!CheckAttributeTarget (a, kind)) {
\r
970 Error_AttributeNotValidForElement (a, loc);
\r
976 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
977 } catch (System.ArgumentException) {
\r
980 "The CharSet named property on StructLayout\n"+
\r
981 "\tdoes not work correctly on Microsoft.NET\n"+
\r
982 "\tYou might want to remove the CharSet declaration\n"+
\r
983 "\tor compile using the Mono runtime instead of the\n"+
\r
984 "\tMicrosoft .NET runtime");
\r
986 } else if (kind is Delegate){
\r
987 if (!CheckAttributeTarget (a, kind)) {
\r
988 Error_AttributeNotValidForElement (a, loc);
\r
992 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
993 } catch (System.ArgumentException) {
\r
996 "The CharSet named property on StructLayout\n"+
\r
997 "\tdoes not work correctly on Microsoft.NET\n"+
\r
998 "\tYou might want to remove the CharSet declaration\n"+
\r
999 "\tor compile using the Mono runtime instead of the\n"+
\r
1000 "\tMicrosoft .NET runtime");
\r
1002 } else if (kind is Interface) {
\r
1003 Interface iface = (Interface) kind;
\r
1005 if ((attr_type == TypeManager.default_member_type) &&
\r
1006 (iface.Indexers != null)) {
\r
1009 "Cannot specify the DefaultMember attribute on" +
\r
1010 " a type containing an indexer");
\r
1014 if (!CheckAttributeTarget (a, kind)) {
\r
1015 Error_AttributeNotValidForElement (a, loc);
\r
1019 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
1020 } else if (kind is AssemblyBuilder){
\r
1021 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
\r
1022 } else if (kind is ModuleBuilder) {
\r
1023 ((ModuleBuilder) builder).SetCustomAttribute (cb);
\r
1024 } else if (kind is FieldBuilder) {
\r
1025 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
1026 UnmanagedMarshal marshal = GetMarshal (a);
\r
1027 if (marshal == null) {
\r
1028 Report.Warning (-24, loc,
\r
1029 "The Microsoft Runtime cannot set this marshal info. " +
\r
1030 "Please use the Mono runtime instead.");
\r
1032 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
1035 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
1038 throw new Exception ("Unknown kind: " + kind);
\r
1041 // Once an attribute type has been emitted once we
\r
1042 // keep track of the info to prevent multiple occurences
\r
1043 // for attributes which do not explicitly allow it
\r
1045 if (!emitted_attrs.Contains (attr_type))
\r
1046 emitted_attrs.Add (attr_type);
\r
1049 // We keep of this target-wise and so emitted targets
\r
1050 // are tracked too
\r
1052 if (!emitted_targets.Contains (attr_target))
\r
1053 emitted_targets.Add (attr_target);
\r
1060 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
\r
1061 MethodAttributes flags, Type ret_type, Type [] param_types)
\r
1064 // We extract from the attribute the information we need
\r
1067 if (Arguments == null) {
\r
1068 Console.WriteLine ("Internal error : this is not supposed to happen !");
\r
1072 Type = CheckAttributeType (ec);
\r
1076 ArrayList named_args = new ArrayList ();
\r
1078 ArrayList pos_args = (ArrayList) Arguments [0];
\r
1079 if (Arguments.Count > 1)
\r
1080 named_args = (ArrayList) Arguments [1];
\r
1083 string dll_name = null;
\r
1085 Argument tmp = (Argument) pos_args [0];
\r
1087 if (!tmp.Resolve (ec, Location))
\r
1090 if (tmp.Expr is Constant)
\r
1091 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
\r
1093 Error_AttributeArgumentNotValid (Location);
\r
1097 // Now we process the named arguments
\r
1098 CallingConvention cc = CallingConvention.Winapi;
\r
1099 CharSet charset = CharSet.Ansi;
\r
1100 bool preserve_sig = true;
\r
1102 bool exact_spelling = false;
\r
1104 bool set_last_err = false;
\r
1105 string entry_point = null;
\r
1107 for (int i = 0; i < named_args.Count; i++) {
\r
1109 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
1111 string member_name = (string) de.Key;
\r
1112 Argument a = (Argument) de.Value;
\r
1114 if (!a.Resolve (ec, Location))
\r
1117 Expression member = Expression.MemberLookup (
\r
1118 ec, Type, member_name,
\r
1119 MemberTypes.Field | MemberTypes.Property,
\r
1120 BindingFlags.Public | BindingFlags.Instance,
\r
1123 if (member == null || !(member is FieldExpr)) {
\r
1124 Error_InvalidNamedArgument (member_name);
\r
1128 if (member is FieldExpr) {
\r
1129 FieldExpr fe = (FieldExpr) member;
\r
1130 FieldInfo fi = fe.FieldInfo;
\r
1132 if (fi.IsInitOnly) {
\r
1133 Error_InvalidNamedArgument (member_name);
\r
1137 if (a.Expr is Constant) {
\r
1138 Constant c = (Constant) a.Expr;
\r
1140 if (member_name == "CallingConvention")
\r
1141 cc = (CallingConvention) c.GetValue ();
\r
1142 else if (member_name == "CharSet")
\r
1143 charset = (CharSet) c.GetValue ();
\r
1144 else if (member_name == "EntryPoint")
\r
1145 entry_point = (string) c.GetValue ();
\r
1146 else if (member_name == "SetLastError")
\r
1147 set_last_err = (bool) c.GetValue ();
\r
1149 else if (member_name == "ExactSpelling")
\r
1150 exact_spelling = (bool) c.GetValue ();
\r
1152 else if (member_name == "PreserveSig")
\r
1153 preserve_sig = (bool) c.GetValue ();
\r
1155 Error_AttributeArgumentNotValid (Location);
\r
1162 if (entry_point == null)
\r
1163 entry_point = name;
\r
1165 charset = (CharSet)((int)charset | 0x40);
\r
1167 MethodBuilder mb = builder.DefinePInvokeMethod (
\r
1168 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
\r
1169 CallingConventions.Standard,
\r
1176 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
\r
1183 public class AttributeSection {
\r
1184 public readonly string Target;
\r
1185 public readonly ArrayList Attributes;
\r
1187 public AttributeSection (string target, ArrayList attrs)
\r
1190 Attributes = attrs;
\r
1195 public class Attributes {
\r
1196 public ArrayList AttributeSections;
\r
1198 public Attributes (AttributeSection a)
\r
1200 AttributeSections = new ArrayList ();
\r
1201 AttributeSections.Add (a);
\r
1205 public void AddAttributeSection (AttributeSection a)
\r
1207 if (a != null && !AttributeSections.Contains (a))
\r
1208 AttributeSections.Add (a);
\r
1211 public bool Contains (Type t)
\r
1213 foreach (AttributeSection attr_section in AttributeSections){
\r
1214 foreach (Attribute a in attr_section.Attributes){
\r
1224 public interface IAttributeSupport {
1225 void SetCustomAttribute (CustomAttributeBuilder customBuilder);