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, 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 || element is InterfaceEvent) {
\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 InterfaceMethod || 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 InterfaceProperty || element is InterfaceIndexer) {
\r
635 if ((targets & AttributeTargets.Property) != 0)
\r
639 } else if (element is AssemblyBuilder){
\r
640 if ((targets & AttributeTargets.Assembly) != 0)
\r
650 // This method should be invoked to pull the IndexerName attribute from an
\r
651 // Indexer if it exists.
\r
653 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
\r
655 if (opt_attrs == null)
\r
657 if (opt_attrs.AttributeSections == null)
\r
660 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
661 if (asec.Attributes == null)
\r
664 foreach (Attribute a in asec.Attributes){
\r
665 if (a.ResolveType (ec) == null)
\r
668 if (a.Type != TypeManager.indexer_name_type)
\r
672 // So we have found an IndexerName, pull the data out.
\r
674 if (a.Arguments == null || a.Arguments [0] == null){
\r
675 Error_AttributeConstructorMismatch (a.Location);
\r
678 ArrayList pos_args = (ArrayList) a.Arguments [0];
\r
679 if (pos_args.Count == 0){
\r
680 Error_AttributeConstructorMismatch (a.Location);
\r
684 Argument arg = (Argument) pos_args [0];
\r
685 if (!arg.Resolve (ec, a.Location))
\r
688 Expression e = arg.Expr;
\r
689 if (!(e is StringConstant)){
\r
690 Error_AttributeConstructorMismatch (a.Location);
\r
695 // Remove the attribute from the list
\r
697 asec.Attributes.Remove (a);
\r
699 return (((StringConstant) e).Value);
\r
706 // This pulls the condition name out of a Conditional attribute
\r
708 public string Conditional_GetConditionName ()
\r
711 // So we have a Conditional, pull the data out.
\r
713 if (Arguments == null || Arguments [0] == null){
\r
714 Error_AttributeConstructorMismatch (Location);
\r
718 ArrayList pos_args = (ArrayList) Arguments [0];
\r
719 if (pos_args.Count != 1){
\r
720 Error_AttributeConstructorMismatch (Location);
\r
724 Argument arg = (Argument) pos_args [0];
\r
725 if (!(arg.Expr is StringConstant)){
\r
726 Error_AttributeConstructorMismatch (Location);
\r
730 return ((StringConstant) arg.Expr).Value;
\r
734 // This pulls the obsolete message and error flag out of an Obsolete attribute
\r
736 public string Obsolete_GetObsoleteMessage (out bool is_error)
\r
740 // So we have an Obsolete, pull the data out.
\r
742 if (Arguments == null || Arguments [0] == null)
\r
745 ArrayList pos_args = (ArrayList) Arguments [0];
\r
746 if (pos_args.Count == 0)
\r
748 else if (pos_args.Count > 2){
\r
749 Error_AttributeConstructorMismatch (Location);
\r
753 Argument arg = (Argument) pos_args [0];
\r
754 if (!(arg.Expr is StringConstant)){
\r
755 Error_AttributeConstructorMismatch (Location);
\r
759 if (pos_args.Count == 2){
\r
760 Argument arg2 = (Argument) pos_args [1];
\r
761 if (!(arg2.Expr is BoolConstant)){
\r
762 Error_AttributeConstructorMismatch (Location);
\r
765 is_error = ((BoolConstant) arg2.Expr).Value;
\r
768 return ((StringConstant) arg.Expr).Value;
\r
771 static object GetFieldValue (Attribute a, string name)
\r
774 if (a.field_info_arr == null)
\r
777 foreach (FieldInfo fi in a.field_info_arr) {
\r
778 if (fi.Name == name)
\r
779 return a.field_values_arr [i];
\r
785 static UnmanagedMarshal GetMarshal (Attribute a)
\r
787 object o = GetFieldValue (a, "ArraySubType");
\r
788 UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;
\r
789 switch (a.UnmanagedType) {
\r
790 case UnmanagedType.CustomMarshaler:
\r
791 MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",
\r
792 BindingFlags.Static | BindingFlags.Public);
\r
793 if (define_custom == null)
\r
796 object [] args = new object [4];
\r
797 args [0] = GetFieldValue (a, "MarshalTypeRef");
\r
798 args [1] = GetFieldValue (a, "MarshalCookie");
\r
799 args [2] = GetFieldValue (a, "MarshalType");
\r
800 args [3] = Guid.Empty;
\r
801 return (UnmanagedMarshal) define_custom.Invoke (null, args);
\r
803 case UnmanagedType.LPArray:
\r
804 return UnmanagedMarshal.DefineLPArray (array_sub_type);
\r
806 case UnmanagedType.SafeArray:
\r
807 return UnmanagedMarshal.DefineSafeArray (array_sub_type);
\r
809 case UnmanagedType.ByValArray:
\r
810 return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));
\r
812 case UnmanagedType.ByValTStr:
\r
813 return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));
\r
816 return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
\r
821 /// Applies the attributes specified on target 'kind' to the `builder'.
\r
823 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
\r
824 Attributes opt_attrs)
\r
826 Type attr_type = null;
\r
828 if (opt_attrs == null)
\r
830 if (opt_attrs.AttributeSections == null)
\r
833 ArrayList emitted_attrs = new ArrayList ();
\r
834 ArrayList emitted_targets = new ArrayList ();
\r
836 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
837 string attr_target = asec.Target;
\r
839 if (asec.Attributes == null)
\r
842 if (attr_target == "assembly" && !(builder is AssemblyBuilder))
\r
845 if (attr_target == "return" && !(builder is ParameterBuilder))
\r
848 foreach (Attribute a in asec.Attributes) {
\r
849 Location loc = a.Location;
\r
850 CustomAttributeBuilder cb = a.Resolve (ec);
\r
851 attr_type = a.Type;
\r
856 if (!(kind is TypeContainer))
\r
857 if (!CheckAttributeTarget (a, kind)) {
\r
858 Error_AttributeNotValidForElement (a, loc);
\r
863 // Perform the check for duplicate attributes
\r
865 if (emitted_attrs.Contains (attr_type) &&
\r
866 emitted_targets.Contains (attr_target) &&
\r
867 !TypeManager.AreMultipleAllowed (attr_type)) {
\r
868 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
\r
872 if (kind is Method || kind is Operator || kind is InterfaceMethod ||
\r
873 kind is Accessor) {
\r
874 if (attr_type == TypeManager.methodimpl_attr_type) {
\r
875 if (a.ImplOptions == MethodImplOptions.InternalCall)
\r
876 ((MethodBuilder) builder).
\r
877 SetImplementationFlags (
\r
878 MethodImplAttributes.InternalCall |
\r
879 MethodImplAttributes.Runtime);
\r
881 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
882 } else if (attr_type != TypeManager.dllimport_type){
\r
883 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
885 } else if (kind is Constructor) {
\r
886 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
\r
887 } else if (kind is Field) {
\r
888 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
889 UnmanagedMarshal marshal = GetMarshal (a);
\r
890 if (marshal == null) {
\r
891 Report.Warning (-24, loc,
\r
892 "The Microsoft Runtime cannot set this marshal info. " +
\r
893 "Please use the Mono runtime instead.");
\r
895 ((FieldBuilder) builder).SetMarshal (marshal);
\r
898 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
900 } else if (kind is Property || kind is Indexer ||
\r
901 kind is InterfaceProperty || kind is InterfaceIndexer) {
\r
902 ((PropertyBuilder) builder).SetCustomAttribute (cb);
\r
903 } else if (kind is Event || kind is InterfaceEvent) {
\r
904 ((MyEventBuilder) builder).SetCustomAttribute (cb);
\r
905 } else if (kind is ParameterBuilder) {
\r
907 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
908 UnmanagedMarshal marshal = GetMarshal (a);
\r
909 if (marshal == null) {
\r
910 Report.Warning (-24, loc,
\r
911 "The Microsoft Runtime cannot set this marshal info. " +
\r
912 "Please use the Mono runtime instead.");
\r
914 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
919 ((ParameterBuilder) builder).SetCustomAttribute (cb);
\r
920 } catch (System.ArgumentException) {
\r
921 Report.Warning (-24, loc,
\r
922 "The Microsoft Runtime cannot set attributes \n" +
\r
923 "on the return type of a method. Please use the \n" +
\r
924 "Mono runtime instead.");
\r
928 } else if (kind is Enum) {
\r
929 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
931 } else if (kind is TypeContainer) {
\r
932 TypeContainer tc = (TypeContainer) kind;
\r
935 tc.Targets = a.Targets;
\r
936 tc.AllowMultiple = a.AllowMultiple;
\r
937 tc.Inherited = a.Inherited;
\r
939 TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
\r
942 } else if (attr_type == TypeManager.default_member_type) {
\r
943 if (tc.Indexers != null) {
\r
944 Report.Error (646, loc,
\r
945 "Cannot specify the DefaultMember attribute on" +
\r
946 " a type containing an indexer");
\r
951 if (!CheckAttributeTarget (a, kind)) {
\r
952 Error_AttributeNotValidForElement (a, loc);
\r
958 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
959 } catch (System.ArgumentException) {
\r
962 "The CharSet named property on StructLayout\n"+
\r
963 "\tdoes not work correctly on Microsoft.NET\n"+
\r
964 "\tYou might want to remove the CharSet declaration\n"+
\r
965 "\tor compile using the Mono runtime instead of the\n"+
\r
966 "\tMicrosoft .NET runtime");
\r
968 } else if (kind is Delegate){
\r
969 if (!CheckAttributeTarget (a, kind)) {
\r
970 Error_AttributeNotValidForElement (a, loc);
\r
974 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
975 } catch (System.ArgumentException) {
\r
978 "The CharSet named property on StructLayout\n"+
\r
979 "\tdoes not work correctly on Microsoft.NET\n"+
\r
980 "\tYou might want to remove the CharSet declaration\n"+
\r
981 "\tor compile using the Mono runtime instead of the\n"+
\r
982 "\tMicrosoft .NET runtime");
\r
984 } else if (kind is Interface) {
\r
985 Interface iface = (Interface) kind;
\r
987 if ((attr_type == TypeManager.default_member_type) &&
\r
988 (iface.InterfaceIndexers != null)) {
\r
991 "Cannot specify the DefaultMember attribute on" +
\r
992 " a type containing an indexer");
\r
996 if (!CheckAttributeTarget (a, kind)) {
\r
997 Error_AttributeNotValidForElement (a, loc);
\r
1001 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
1002 } else if (kind is AssemblyBuilder){
\r
1003 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
\r
1004 } else if (kind is ModuleBuilder) {
\r
1005 ((ModuleBuilder) builder).SetCustomAttribute (cb);
\r
1006 } else if (kind is FieldBuilder) {
\r
1007 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
1008 UnmanagedMarshal marshal = GetMarshal (a);
\r
1009 if (marshal == null) {
\r
1010 Report.Warning (-24, loc,
\r
1011 "The Microsoft Runtime cannot set this marshal info. " +
\r
1012 "Please use the Mono runtime instead.");
\r
1014 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
1017 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
1020 throw new Exception ("Unknown kind: " + kind);
\r
1023 // Once an attribute type has been emitted once we
\r
1024 // keep track of the info to prevent multiple occurences
\r
1025 // for attributes which do not explicitly allow it
\r
1027 if (!emitted_attrs.Contains (attr_type))
\r
1028 emitted_attrs.Add (attr_type);
\r
1031 // We keep of this target-wise and so emitted targets
\r
1032 // are tracked too
\r
1034 if (!emitted_targets.Contains (attr_target))
\r
1035 emitted_targets.Add (attr_target);
\r
1042 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
\r
1043 MethodAttributes flags, Type ret_type, Type [] param_types)
\r
1046 // We extract from the attribute the information we need
\r
1049 if (Arguments == null) {
\r
1050 Console.WriteLine ("Internal error : this is not supposed to happen !");
\r
1054 Type = CheckAttributeType (ec);
\r
1058 ArrayList named_args = new ArrayList ();
\r
1060 ArrayList pos_args = (ArrayList) Arguments [0];
\r
1061 if (Arguments.Count > 1)
\r
1062 named_args = (ArrayList) Arguments [1];
\r
1065 string dll_name = null;
\r
1067 Argument tmp = (Argument) pos_args [0];
\r
1069 if (!tmp.Resolve (ec, Location))
\r
1072 if (tmp.Expr is Constant)
\r
1073 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
\r
1075 Error_AttributeArgumentNotValid (Location);
\r
1079 // Now we process the named arguments
\r
1080 CallingConvention cc = CallingConvention.Winapi;
\r
1081 CharSet charset = CharSet.Ansi;
\r
1082 bool preserve_sig = true;
\r
1084 bool exact_spelling = false;
\r
1086 bool set_last_err = false;
\r
1087 string entry_point = null;
\r
1089 for (int i = 0; i < named_args.Count; i++) {
\r
1091 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
1093 string member_name = (string) de.Key;
\r
1094 Argument a = (Argument) de.Value;
\r
1096 if (!a.Resolve (ec, Location))
\r
1099 Expression member = Expression.MemberLookup (
\r
1100 ec, Type, member_name,
\r
1101 MemberTypes.Field | MemberTypes.Property,
\r
1102 BindingFlags.Public | BindingFlags.Instance,
\r
1105 if (member == null || !(member is FieldExpr)) {
\r
1106 Error_InvalidNamedArgument (member_name);
\r
1110 if (member is FieldExpr) {
\r
1111 FieldExpr fe = (FieldExpr) member;
\r
1112 FieldInfo fi = fe.FieldInfo;
\r
1114 if (fi.IsInitOnly) {
\r
1115 Error_InvalidNamedArgument (member_name);
\r
1119 if (a.Expr is Constant) {
\r
1120 Constant c = (Constant) a.Expr;
\r
1122 if (member_name == "CallingConvention")
\r
1123 cc = (CallingConvention) c.GetValue ();
\r
1124 else if (member_name == "CharSet")
\r
1125 charset = (CharSet) c.GetValue ();
\r
1126 else if (member_name == "EntryPoint")
\r
1127 entry_point = (string) c.GetValue ();
\r
1128 else if (member_name == "SetLastError")
\r
1129 set_last_err = (bool) c.GetValue ();
\r
1131 else if (member_name == "ExactSpelling")
\r
1132 exact_spelling = (bool) c.GetValue ();
\r
1134 else if (member_name == "PreserveSig")
\r
1135 preserve_sig = (bool) c.GetValue ();
\r
1137 Error_AttributeArgumentNotValid (Location);
\r
1144 if (entry_point == null)
\r
1145 entry_point = name;
\r
1147 charset = (CharSet)((int)charset | 0x40);
\r
1149 MethodBuilder mb = builder.DefinePInvokeMethod (
\r
1150 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
\r
1151 CallingConventions.Standard,
\r
1158 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
\r
1165 public class AttributeSection {
\r
1166 public readonly string Target;
\r
1167 public readonly ArrayList Attributes;
\r
1169 public AttributeSection (string target, ArrayList attrs)
\r
1172 Attributes = attrs;
\r
1177 public class Attributes {
\r
1178 public ArrayList AttributeSections;
\r
1180 public Attributes (AttributeSection a)
\r
1182 AttributeSections = new ArrayList ();
\r
1183 AttributeSections.Add (a);
\r
1187 public void AddAttributeSection (AttributeSection a)
\r
1189 if (a != null && !AttributeSections.Contains (a))
\r
1190 AttributeSections.Add (a);
\r
1193 public bool Contains (Type t)
\r
1195 foreach (AttributeSection attr_section in AttributeSections){
\r
1196 foreach (Attribute a in attr_section.Attributes){
\r