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
156 Error_AttributeArgumentNotValid (loc);
\r
160 public CustomAttributeBuilder Resolve (EmitContext ec)
\r
163 Type = CheckAttributeType (ec);
\r
167 bool MethodImplAttr = false;
\r
168 bool MarshalAsAttr = false;
\r
169 bool GuidAttr = false;
\r
172 bool DoCompares = true;
\r
175 // If we are a certain special attribute, we
\r
176 // set the information accordingly
\r
179 if (Type == TypeManager.attribute_usage_type)
\r
181 else if (Type == TypeManager.methodimpl_attr_type)
\r
182 MethodImplAttr = true;
\r
183 else if (Type == TypeManager.marshal_as_attr_type)
\r
184 MarshalAsAttr = true;
\r
185 else if (Type == TypeManager.guid_attr_type)
\r
188 DoCompares = false;
\r
190 // Now we extract the positional and named arguments
\r
192 ArrayList pos_args = new ArrayList ();
\r
193 ArrayList named_args = new ArrayList ();
\r
194 int pos_arg_count = 0;
\r
196 if (Arguments != null) {
\r
197 pos_args = (ArrayList) Arguments [0];
\r
198 if (pos_args != null)
\r
199 pos_arg_count = pos_args.Count;
\r
200 if (Arguments.Count > 1)
\r
201 named_args = (ArrayList) Arguments [1];
\r
204 object [] pos_values = new object [pos_arg_count];
\r
207 // First process positional arguments
\r
211 for (i = 0; i < pos_arg_count; i++) {
\r
212 Argument a = (Argument) pos_args [i];
\r
215 if (!a.Resolve (ec, Location))
\r
221 if (!GetAttributeArgumentExpression (e, Location, out val))
\r
224 pos_values [i] = val;
\r
227 this.Targets = (AttributeTargets) pos_values [0];
\r
228 else if (MethodImplAttr)
\r
229 this.ImplOptions = (MethodImplOptions) pos_values [0];
\r
230 else if (GuidAttr){
\r
232 // we will later check the validity of the type
\r
234 if (pos_values [0] is string){
\r
235 if (!ValidateGuid ((string) pos_values [0]))
\r
239 } else if (MarshalAsAttr)
\r
240 this.UnmanagedType =
\r
241 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
\r
246 // Now process named arguments
\r
249 ArrayList field_infos = null;
\r
250 ArrayList prop_infos = null;
\r
251 ArrayList field_values = null;
\r
252 ArrayList prop_values = null;
\r
254 if (named_args.Count > 0) {
\r
255 field_infos = new ArrayList ();
\r
256 prop_infos = new ArrayList ();
\r
257 field_values = new ArrayList ();
\r
258 prop_values = new ArrayList ();
\r
261 for (i = 0; i < named_args.Count; i++) {
\r
262 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
263 string member_name = (string) de.Key;
\r
264 Argument a = (Argument) de.Value;
\r
267 if (!a.Resolve (ec, Location))
\r
270 Expression member = Expression.MemberLookup (
\r
271 ec, Type, member_name,
\r
272 MemberTypes.Field | MemberTypes.Property,
\r
273 BindingFlags.Public | BindingFlags.Instance,
\r
276 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
\r
277 Error_InvalidNamedArgument (member_name);
\r
282 if (e is TypeParameterExpr){
\r
283 Error_TypeParameterInAttribute (Location);
\r
287 if (member is PropertyExpr) {
\r
288 PropertyExpr pe = (PropertyExpr) member;
\r
289 PropertyInfo pi = pe.PropertyInfo;
\r
291 if (!pi.CanWrite) {
\r
292 Error_InvalidNamedArgument (member_name);
\r
296 if (e is Constant) {
\r
297 object o = ((Constant) e).GetValue ();
\r
298 prop_values.Add (o);
\r
301 if (member_name == "AllowMultiple")
\r
302 this.AllowMultiple = (bool) o;
\r
303 if (member_name == "Inherited")
\r
304 this.Inherited = (bool) o;
\r
307 } else if (e is TypeOf) {
\r
308 prop_values.Add (((TypeOf) e).TypeArg);
\r
310 Error_AttributeArgumentNotValid (Location);
\r
314 prop_infos.Add (pi);
\r
316 } else if (member is FieldExpr) {
\r
317 FieldExpr fe = (FieldExpr) member;
\r
318 FieldInfo fi = fe.FieldInfo;
\r
320 if (fi.IsInitOnly) {
\r
321 Error_InvalidNamedArgument (member_name);
\r
326 // Handle charset here, and set the TypeAttributes
\r
328 if (e is Constant){
\r
329 object value = ((Constant) e).GetValue ();
\r
331 field_values.Add (value);
\r
332 } else if (e is TypeOf) {
\r
333 field_values.Add (((TypeOf) e).TypeArg);
\r
335 Error_AttributeArgumentNotValid (Location);
\r
339 field_infos.Add (fi);
\r
343 Expression mg = Expression.MemberLookup (
\r
344 ec, Type, ".ctor", MemberTypes.Constructor,
\r
345 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
\r
349 Error_AttributeConstructorMismatch (Location);
\r
353 MethodBase constructor = Invocation.OverloadResolve (
\r
354 ec, (MethodGroupExpr) mg, pos_args, Location);
\r
356 if (constructor == null) {
\r
357 Error_AttributeConstructorMismatch (Location);
\r
362 // Now we perform some checks on the positional args as they
\r
363 // cannot be null for a constructor which expects a parameter
\r
367 ParameterData pd = Invocation.GetParameterData (constructor);
\r
369 int group_in_params_array = Int32.MaxValue;
\r
371 if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)
\r
372 group_in_params_array = pc-1;
\r
374 for (int j = 0; j < pos_arg_count; ++j) {
\r
375 Argument a = (Argument) pos_args [j];
\r
377 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
\r
378 Error_AttributeArgumentNotValid (Location);
\r
382 if (j < group_in_params_array)
\r
385 if (j == group_in_params_array){
\r
386 object v = pos_values [j];
\r
387 int count = pos_arg_count - j;
\r
389 object [] array = new object [count];
\r
390 pos_values [j] = array;
\r
393 object [] array = (object []) pos_values [group_in_params_array];
\r
395 array [j - group_in_params_array] = pos_values [j];
\r
400 // Adjust the size of the pos_values if it had params
\r
402 if (group_in_params_array != Int32.MaxValue){
\r
403 int argc = group_in_params_array+1;
\r
404 object [] new_pos_values = new object [argc];
\r
406 for (int p = 0; p < argc; p++)
\r
407 new_pos_values [p] = pos_values [p];
\r
408 pos_values = new_pos_values;
\r
412 if (named_args.Count > 0) {
\r
413 prop_info_arr = new PropertyInfo [prop_infos.Count];
\r
414 field_info_arr = new FieldInfo [field_infos.Count];
\r
415 field_values_arr = new object [field_values.Count];
\r
416 prop_values_arr = new object [prop_values.Count];
\r
418 field_infos.CopyTo (field_info_arr, 0);
\r
419 field_values.CopyTo (field_values_arr, 0);
\r
421 prop_values.CopyTo (prop_values_arr, 0);
\r
422 prop_infos.CopyTo (prop_info_arr, 0);
\r
424 cb = new CustomAttributeBuilder (
\r
425 (ConstructorInfo) constructor, pos_values,
\r
426 prop_info_arr, prop_values_arr,
\r
427 field_info_arr, field_values_arr);
\r
430 cb = new CustomAttributeBuilder (
\r
431 (ConstructorInfo) constructor, pos_values);
\r
432 } catch (NullReferenceException) {
\r
434 // Don't know what to do here
\r
437 -101, Location, "NullReferenceException while trying to create attribute." +
\r
438 "Something's wrong!");
\r
439 } catch (Exception e) {
\r
442 // using System.ComponentModel;
\r
443 // [DefaultValue (CollectionChangeAction.Add)]
\r
444 // class X { static void Main () {} }
\r
448 "The compiler can not encode this attribute in .NET due to\n" +
\r
449 "\ta bug in the .NET runtime. Try the Mono runtime.\nThe error was: " + e.Message);
\r
456 /// Get a string containing a list of valid targets for the attribute 'attr'
\r
458 static string GetValidTargets (Attribute attr)
\r
460 StringBuilder sb = new StringBuilder ();
\r
461 AttributeTargets targets = 0;
\r
463 TypeContainer a = TypeManager.LookupAttr (attr.Type);
\r
467 System.Attribute [] attrs = null;
\r
470 attrs = System.Attribute.GetCustomAttributes (attr.Type);
\r
473 Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
\r
474 " (maybe you forgot to set the usage using the" +
\r
475 " AttributeUsage attribute ?).");
\r
479 foreach (System.Attribute tmp in attrs)
\r
480 if (tmp is AttributeUsageAttribute) {
\r
481 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
485 targets = a.Targets;
\r
488 if ((targets & AttributeTargets.Assembly) != 0)
\r
489 sb.Append ("'assembly' ");
\r
491 if ((targets & AttributeTargets.Class) != 0)
\r
492 sb.Append ("'class' ");
\r
494 if ((targets & AttributeTargets.Constructor) != 0)
\r
495 sb.Append ("'constructor' ");
\r
497 if ((targets & AttributeTargets.Delegate) != 0)
\r
498 sb.Append ("'delegate' ");
\r
500 if ((targets & AttributeTargets.Enum) != 0)
\r
501 sb.Append ("'enum' ");
\r
503 if ((targets & AttributeTargets.Event) != 0)
\r
504 sb.Append ("'event' ");
\r
506 if ((targets & AttributeTargets.Field) != 0)
\r
507 sb.Append ("'field' ");
\r
509 if ((targets & AttributeTargets.Interface) != 0)
\r
510 sb.Append ("'interface' ");
\r
512 if ((targets & AttributeTargets.Method) != 0)
\r
513 sb.Append ("'method' ");
\r
515 if ((targets & AttributeTargets.Module) != 0)
\r
516 sb.Append ("'module' ");
\r
518 if ((targets & AttributeTargets.Parameter) != 0)
\r
519 sb.Append ("'parameter' ");
\r
521 if ((targets & AttributeTargets.Property) != 0)
\r
522 sb.Append ("'property' ");
\r
524 if ((targets & AttributeTargets.ReturnValue) != 0)
\r
525 sb.Append ("'return value' ");
\r
527 if ((targets & AttributeTargets.Struct) != 0)
\r
528 sb.Append ("'struct' ");
\r
530 return sb.ToString ();
\r
534 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
\r
537 592, loc, "Attribute '" + a.Name +
\r
538 "' is not valid on this declaration type. " +
\r
539 "It is valid on " + GetValidTargets (a) + "declarations only.");
\r
543 /// Ensure that Attribute 'a' is being applied to the right language element (target)
\r
545 public static bool CheckAttributeTarget (Attribute a, object element)
\r
547 TypeContainer attr = TypeManager.LookupAttr (a.Type);
\r
548 AttributeTargets targets = 0;
\r
550 if (attr == null) {
\r
551 System.Attribute [] attrs = null;
\r
554 attrs = System.Attribute.GetCustomAttributes (a.Type);
\r
557 Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
\r
558 " (maybe you forgot to set the usage using the" +
\r
559 " AttributeUsage attribute ?).");
\r
563 foreach (System.Attribute tmp in attrs)
\r
564 if (tmp is AttributeUsageAttribute) {
\r
565 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
569 targets = attr.Targets;
\r
572 if (element is Class) {
\r
573 if ((targets & AttributeTargets.Class) != 0)
\r
578 } else if (element is Struct) {
\r
579 if ((targets & AttributeTargets.Struct) != 0)
\r
583 } else if (element is Constructor) {
\r
584 if ((targets & AttributeTargets.Constructor) != 0)
\r
588 } else if (element is Delegate) {
\r
589 if ((targets & AttributeTargets.Delegate) != 0)
\r
593 } else if (element is Enum) {
\r
594 if ((targets & AttributeTargets.Enum) != 0)
\r
598 } else if (element is Event || element is InterfaceEvent) {
\r
599 if ((targets & AttributeTargets.Event) != 0)
\r
603 } else if (element is Field || element is FieldBuilder) {
\r
604 if ((targets & AttributeTargets.Field) != 0)
\r
608 } else if (element is Interface) {
\r
609 if ((targets & AttributeTargets.Interface) != 0)
\r
613 } else if (element is Method || element is Operator ||
\r
614 element is InterfaceMethod || element is Accessor) {
\r
615 if ((targets & AttributeTargets.Method) != 0)
\r
619 } else if (element is ParameterBuilder) {
\r
620 if ((targets & AttributeTargets.Parameter) != 0 ||
\r
621 (targets & AttributeTargets.ReturnValue) != 0)
\r
625 } else if (element is Property || element is Indexer ||
\r
626 element is InterfaceProperty || element is InterfaceIndexer) {
\r
627 if ((targets & AttributeTargets.Property) != 0)
\r
631 } else if (element is AssemblyBuilder){
\r
632 if ((targets & AttributeTargets.Assembly) != 0)
\r
642 // This method should be invoked to pull the IndexerName attribute from an
\r
643 // Indexer if it exists.
\r
645 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
\r
647 if (opt_attrs == null)
\r
649 if (opt_attrs.AttributeSections == null)
\r
652 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
653 if (asec.Attributes == null)
\r
656 foreach (Attribute a in asec.Attributes){
\r
657 if (a.ResolveType (ec) == null)
\r
660 if (a.Type != TypeManager.indexer_name_type)
\r
664 // So we have found an IndexerName, pull the data out.
\r
666 if (a.Arguments == null || a.Arguments [0] == null){
\r
667 Error_AttributeConstructorMismatch (a.Location);
\r
670 ArrayList pos_args = (ArrayList) a.Arguments [0];
\r
671 if (pos_args.Count == 0){
\r
672 Error_AttributeConstructorMismatch (a.Location);
\r
676 Argument arg = (Argument) pos_args [0];
\r
677 if (!arg.Resolve (ec, a.Location))
\r
680 Expression e = arg.Expr;
\r
681 if (!(e is StringConstant)){
\r
682 Error_AttributeConstructorMismatch (a.Location);
\r
687 // Remove the attribute from the list
\r
689 asec.Attributes.Remove (a);
\r
691 return (((StringConstant) e).Value);
\r
698 // This pulls the condition name out of a Conditional attribute
\r
700 public string Conditional_GetConditionName ()
\r
703 // So we have a Conditional, pull the data out.
\r
705 if (Arguments == null || Arguments [0] == null){
\r
706 Error_AttributeConstructorMismatch (Location);
\r
710 ArrayList pos_args = (ArrayList) Arguments [0];
\r
711 if (pos_args.Count != 1){
\r
712 Error_AttributeConstructorMismatch (Location);
\r
716 Argument arg = (Argument) pos_args [0];
\r
717 if (!(arg.Expr is StringConstant)){
\r
718 Error_AttributeConstructorMismatch (Location);
\r
722 return ((StringConstant) arg.Expr).Value;
\r
726 // This pulls the obsolete message and error flag out of an Obsolete attribute
\r
728 public string Obsolete_GetObsoleteMessage (out bool is_error)
\r
732 // So we have an Obsolete, pull the data out.
\r
734 if (Arguments == null || Arguments [0] == null)
\r
737 ArrayList pos_args = (ArrayList) Arguments [0];
\r
738 if (pos_args.Count == 0)
\r
740 else if (pos_args.Count > 2){
\r
741 Error_AttributeConstructorMismatch (Location);
\r
745 Argument arg = (Argument) pos_args [0];
\r
746 if (!(arg.Expr is StringConstant)){
\r
747 Error_AttributeConstructorMismatch (Location);
\r
751 if (pos_args.Count == 2){
\r
752 Argument arg2 = (Argument) pos_args [1];
\r
753 if (!(arg2.Expr is BoolConstant)){
\r
754 Error_AttributeConstructorMismatch (Location);
\r
757 is_error = ((BoolConstant) arg2.Expr).Value;
\r
760 return ((StringConstant) arg.Expr).Value;
\r
763 static object GetFieldValue (Attribute a, string name)
\r
766 if (a.field_info_arr == null)
\r
769 foreach (FieldInfo fi in a.field_info_arr) {
\r
770 if (fi.Name == name)
\r
771 return a.field_values_arr [i];
\r
777 static UnmanagedMarshal GetMarshal (Attribute a)
\r
779 UnmanagedMarshal marshal;
\r
781 if (a.UnmanagedType == UnmanagedType.CustomMarshaler) {
\r
782 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
\r
783 BindingFlags.Static | BindingFlags.Public);
\r
784 if (define_custom == null) {
\r
787 object[] args = new object [4];
\r
788 args [0] = GetFieldValue (a, "MarshalTypeRef");
\r
789 args [1] = GetFieldValue (a, "MarshalCookie");
\r
790 args [2] = GetFieldValue (a, "MarshalType");
\r
791 args [3] = Guid.Empty;
\r
792 marshal = (UnmanagedMarshal) define_custom.Invoke (null, args);
\r
794 * need to special case other special marshal types
\r
797 marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
\r
803 /// Applies the attributes specified on target 'kind' to the `builder'.
\r
805 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
\r
806 Attributes opt_attrs)
\r
808 Type attr_type = null;
\r
810 if (opt_attrs == null)
\r
812 if (opt_attrs.AttributeSections == null)
\r
815 ArrayList emitted_attrs = new ArrayList ();
\r
816 ArrayList emitted_targets = new ArrayList ();
\r
818 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
819 string attr_target = asec.Target;
\r
821 if (asec.Attributes == null)
\r
824 if (attr_target == "assembly" && !(builder is AssemblyBuilder))
\r
827 if (attr_target == "return" && !(builder is ParameterBuilder))
\r
830 foreach (Attribute a in asec.Attributes) {
\r
831 Location loc = a.Location;
\r
832 CustomAttributeBuilder cb = a.Resolve (ec);
\r
833 attr_type = a.Type;
\r
838 if (!(kind is TypeContainer))
\r
839 if (!CheckAttributeTarget (a, kind)) {
\r
840 Error_AttributeNotValidForElement (a, loc);
\r
845 // Perform the check for duplicate attributes
\r
847 if (emitted_attrs.Contains (attr_type) &&
\r
848 emitted_targets.Contains (attr_target) &&
\r
849 !TypeManager.AreMultipleAllowed (attr_type)) {
\r
850 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
\r
854 if (kind is Method || kind is Operator || kind is InterfaceMethod ||
\r
855 kind is Accessor) {
\r
856 if (attr_type == TypeManager.methodimpl_attr_type) {
\r
857 if (a.ImplOptions == MethodImplOptions.InternalCall)
\r
858 ((MethodBuilder) builder).
\r
859 SetImplementationFlags (
\r
860 MethodImplAttributes.InternalCall |
\r
861 MethodImplAttributes.Runtime);
\r
863 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
864 } else if (attr_type != TypeManager.dllimport_type){
\r
865 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
867 } else if (kind is Constructor) {
\r
868 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
\r
869 } else if (kind is Field) {
\r
870 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
871 } else if (kind is Property || kind is Indexer ||
\r
872 kind is InterfaceProperty || kind is InterfaceIndexer) {
\r
873 ((PropertyBuilder) builder).SetCustomAttribute (cb);
\r
874 } else if (kind is Event || kind is InterfaceEvent) {
\r
875 ((MyEventBuilder) builder).SetCustomAttribute (cb);
\r
876 } else if (kind is ParameterBuilder) {
\r
878 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
879 UnmanagedMarshal marshal = GetMarshal (a);
\r
880 if (marshal == null) {
\r
881 Report.Warning (-24, loc,
\r
882 "The Microsoft Runtime cannot set this marshal info. " +
\r
883 "Please use the Mono runtime instead.");
\r
885 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
890 ((ParameterBuilder) builder).SetCustomAttribute (cb);
\r
891 } catch (System.ArgumentException) {
\r
892 Report.Warning (-24, loc,
\r
893 "The Microsoft Runtime cannot set attributes \n" +
\r
894 "on the return type of a method. Please use the \n" +
\r
895 "Mono runtime instead.");
\r
899 } else if (kind is Enum) {
\r
900 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
902 } else if (kind is TypeContainer) {
\r
903 TypeContainer tc = (TypeContainer) kind;
\r
906 tc.Targets = a.Targets;
\r
907 tc.AllowMultiple = a.AllowMultiple;
\r
908 tc.Inherited = a.Inherited;
\r
910 TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
\r
913 } else if (attr_type == TypeManager.default_member_type) {
\r
914 if (tc.Indexers != null) {
\r
915 Report.Error (646, loc,
\r
916 "Cannot specify the DefaultMember attribute on" +
\r
917 " a type containing an indexer");
\r
922 if (!CheckAttributeTarget (a, kind)) {
\r
923 Error_AttributeNotValidForElement (a, loc);
\r
929 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
930 } catch (System.ArgumentException e) {
\r
933 "The CharSet named property on StructLayout\n"+
\r
934 "\tdoes not work correctly on Microsoft.NET\n"+
\r
935 "\tYou might want to remove the CharSet declaration\n"+
\r
936 "\tor compile using the Mono runtime instead of the\n"+
\r
937 "\tMicrosoft .NET runtime");
\r
940 } else if (kind is Interface) {
\r
941 Interface iface = (Interface) kind;
\r
943 if ((attr_type == TypeManager.default_member_type) &&
\r
944 (iface.InterfaceIndexers != null)) {
\r
947 "Cannot specify the DefaultMember attribute on" +
\r
948 " a type containing an indexer");
\r
952 if (!CheckAttributeTarget (a, kind)) {
\r
953 Error_AttributeNotValidForElement (a, loc);
\r
957 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
958 } else if (kind is AssemblyBuilder){
\r
959 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
\r
960 } else if (kind is ModuleBuilder) {
\r
961 ((ModuleBuilder) builder).SetCustomAttribute (cb);
\r
962 } else if (kind is FieldBuilder) {
\r
963 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
964 UnmanagedMarshal marshal = GetMarshal (a);
\r
965 if (marshal == null) {
\r
966 Report.Warning (-24, loc,
\r
967 "The Microsoft Runtime cannot set this marshal info. " +
\r
968 "Please use the Mono runtime instead.");
\r
970 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
973 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
976 throw new Exception ("Unknown kind: " + kind);
\r
979 // Once an attribute type has been emitted once we
\r
980 // keep track of the info to prevent multiple occurences
\r
981 // for attributes which do not explicitly allow it
\r
983 if (!emitted_attrs.Contains (attr_type))
\r
984 emitted_attrs.Add (attr_type);
\r
987 // We keep of this target-wise and so emitted targets
\r
990 if (!emitted_targets.Contains (attr_target))
\r
991 emitted_targets.Add (attr_target);
\r
998 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
\r
999 MethodAttributes flags, Type ret_type, Type [] param_types)
\r
1002 // We extract from the attribute the information we need
\r
1005 if (Arguments == null) {
\r
1006 Console.WriteLine ("Internal error : this is not supposed to happen !");
\r
1010 Type = CheckAttributeType (ec);
\r
1014 ArrayList named_args = new ArrayList ();
\r
1016 ArrayList pos_args = (ArrayList) Arguments [0];
\r
1017 if (Arguments.Count > 1)
\r
1018 named_args = (ArrayList) Arguments [1];
\r
1021 string dll_name = null;
\r
1023 Argument tmp = (Argument) pos_args [0];
\r
1025 if (!tmp.Resolve (ec, Location))
\r
1028 if (tmp.Expr is Constant)
\r
1029 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
\r
1031 Error_AttributeArgumentNotValid (Location);
\r
1035 // Now we process the named arguments
\r
1036 CallingConvention cc = CallingConvention.Winapi;
\r
1037 CharSet charset = CharSet.Ansi;
\r
1038 bool preserve_sig = true;
\r
1039 bool exact_spelling = false;
\r
1040 bool set_last_err = false;
\r
1041 string entry_point = null;
\r
1043 for (int i = 0; i < named_args.Count; i++) {
\r
1045 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
1047 string member_name = (string) de.Key;
\r
1048 Argument a = (Argument) de.Value;
\r
1050 if (!a.Resolve (ec, Location))
\r
1053 Expression member = Expression.MemberLookup (
\r
1054 ec, Type, member_name,
\r
1055 MemberTypes.Field | MemberTypes.Property,
\r
1056 BindingFlags.Public | BindingFlags.Instance,
\r
1059 if (member == null || !(member is FieldExpr)) {
\r
1060 Error_InvalidNamedArgument (member_name);
\r
1064 if (member is FieldExpr) {
\r
1065 FieldExpr fe = (FieldExpr) member;
\r
1066 FieldInfo fi = fe.FieldInfo;
\r
1068 if (fi.IsInitOnly) {
\r
1069 Error_InvalidNamedArgument (member_name);
\r
1073 if (a.Expr is Constant) {
\r
1074 Constant c = (Constant) a.Expr;
\r
1076 if (member_name == "CallingConvention")
\r
1077 cc = (CallingConvention) c.GetValue ();
\r
1078 else if (member_name == "CharSet")
\r
1079 charset = (CharSet) c.GetValue ();
\r
1080 else if (member_name == "EntryPoint")
\r
1081 entry_point = (string) c.GetValue ();
\r
1082 else if (member_name == "SetLastError")
\r
1083 set_last_err = (bool) c.GetValue ();
\r
1084 else if (member_name == "ExactSpelling")
\r
1085 exact_spelling = (bool) c.GetValue ();
\r
1086 else if (member_name == "PreserveSig")
\r
1087 preserve_sig = (bool) c.GetValue ();
\r
1089 Error_AttributeArgumentNotValid (Location);
\r
1096 if (entry_point == null)
\r
1097 entry_point = name;
\r
1099 charset = (CharSet)((int)charset | 0x40);
\r
1101 MethodBuilder mb = builder.DefinePInvokeMethod (
\r
1102 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
\r
1103 CallingConventions.Standard,
\r
1110 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
\r
1117 public class AttributeSection {
\r
1118 public readonly string Target;
\r
1119 public readonly ArrayList Attributes;
\r
1121 public AttributeSection (string target, ArrayList attrs)
\r
1124 Attributes = attrs;
\r
1129 public class Attributes {
\r
1130 public ArrayList AttributeSections;
\r
1132 public Attributes (AttributeSection a)
\r
1134 AttributeSections = new ArrayList ();
\r
1135 AttributeSections.Add (a);
\r
1139 public void AddAttributeSection (AttributeSection a)
\r
1141 if (a != null && !AttributeSections.Contains (a))
\r
1142 AttributeSections.Add (a);
\r
1145 public bool Contains (Type t)
\r
1147 foreach (AttributeSection attr_section in AttributeSections){
\r
1148 foreach (Attribute a in attr_section.Attributes){
\r