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 one of the builtin ones
\r
35 AttributeTargets Targets;
\r
39 bool UsageAttr = false;
\r
41 MethodImplOptions ImplOptions;
\r
42 UnmanagedType UnmanagedType;
\r
43 CustomAttributeBuilder cb;
\r
45 public Attribute (string name, ArrayList args, Location loc)
\r
52 void Error_InvalidNamedArgument (string name)
\r
54 Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
\r
55 "argument. Named attribute arguments must be fields which are not " +
\r
56 "readonly, static or const, or properties with a set accessor which "+
\r
60 static void Error_AttributeArgumentNotValid (Location loc)
\r
62 Report.Error (182, loc,
\r
63 "An attribute argument must be a constant expression, typeof " +
\r
64 "expression or array creation expression");
\r
67 static void Error_AttributeConstructorMismatch (Location loc)
\r
71 "Could not find a constructor for this argument list.");
\r
74 private Type CheckAttributeType (EmitContext ec) {
\r
76 bool isattributeclass = true;
\r
78 t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
\r
80 isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
\r
81 if (isattributeclass)
\r
84 t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
\r
86 if (t.IsSubclassOf (TypeManager.attribute_type))
\r
89 if (!isattributeclass) {
\r
90 Report.Error (616, Location, "'" + Name + "': is not an attribute class");
\r
94 Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
\r
98 246, Location, "Could not find attribute '" + Name + "' (are you" +
\r
99 " missing a using directive or an assembly reference ?)");
\r
103 public Type ResolveType (EmitContext ec)
\r
105 Type = CheckAttributeType (ec);
\r
110 /// Validates the guid string
\r
112 bool ValidateGuid (string guid)
\r
118 Report.Error (647, Location, "Format of GUID is invalid: " + guid);
\r
124 // Given an expression, if the expression is a valid attribute-argument-expression
\r
125 // returns an object that can be used to encode it, or null on failure.
\r
127 public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)
\r
129 if (e is Constant) {
\r
130 result = ((Constant) e).GetValue ();
\r
132 } else if (e is TypeOf) {
\r
133 result = ((TypeOf) e).TypeArg;
\r
135 } else if (e is ArrayCreation){
\r
136 result = ((ArrayCreation) e).EncodeAsAttribute ();
\r
137 if (result != null)
\r
142 Error_AttributeArgumentNotValid (loc);
\r
146 public CustomAttributeBuilder Resolve (EmitContext ec)
\r
149 Type = CheckAttributeType (ec);
\r
153 bool MethodImplAttr = false;
\r
154 bool MarshalAsAttr = false;
\r
155 bool GuidAttr = false;
\r
158 bool DoCompares = true;
\r
159 if (Type == TypeManager.attribute_usage_type)
\r
161 else if (Type == TypeManager.methodimpl_attr_type)
\r
162 MethodImplAttr = true;
\r
163 else if (Type == TypeManager.marshal_as_attr_type)
\r
164 MarshalAsAttr = true;
\r
165 else if (Type == TypeManager.guid_attr_type)
\r
168 DoCompares = false;
\r
170 // Now we extract the positional and named arguments
\r
172 ArrayList pos_args = new ArrayList ();
\r
173 ArrayList named_args = new ArrayList ();
\r
174 int pos_arg_count = 0;
\r
176 if (Arguments != null) {
\r
177 pos_args = (ArrayList) Arguments [0];
\r
178 if (pos_args != null)
\r
179 pos_arg_count = pos_args.Count;
\r
180 if (Arguments.Count > 1)
\r
181 named_args = (ArrayList) Arguments [1];
\r
184 object [] pos_values = new object [pos_arg_count];
\r
187 // First process positional arguments
\r
191 for (i = 0; i < pos_arg_count; i++) {
\r
192 Argument a = (Argument) pos_args [i];
\r
195 if (!a.Resolve (ec, Location))
\r
201 if (!GetAttributeArgumentExpression (e, Location, out val))
\r
204 pos_values [i] = val;
\r
207 this.Targets = (AttributeTargets) pos_values [0];
\r
208 else if (MethodImplAttr)
\r
209 this.ImplOptions = (MethodImplOptions) pos_values [0];
\r
210 else if (GuidAttr){
\r
212 // we will later check the validity of the type
\r
214 if (pos_values [0] is string){
\r
215 if (!ValidateGuid ((string) pos_values [0]))
\r
219 } else if (MarshalAsAttr)
\r
220 this.UnmanagedType =
\r
221 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
\r
226 // Now process named arguments
\r
229 ArrayList field_infos = null;
\r
230 ArrayList prop_infos = null;
\r
231 ArrayList field_values = null;
\r
232 ArrayList prop_values = null;
\r
234 if (named_args.Count > 0) {
\r
235 field_infos = new ArrayList ();
\r
236 prop_infos = new ArrayList ();
\r
237 field_values = new ArrayList ();
\r
238 prop_values = new ArrayList ();
\r
241 for (i = 0; i < named_args.Count; i++) {
\r
242 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
243 string member_name = (string) de.Key;
\r
244 Argument a = (Argument) de.Value;
\r
247 if (!a.Resolve (ec, Location))
\r
250 Expression member = Expression.MemberLookup (
\r
251 ec, Type, member_name,
\r
252 MemberTypes.Field | MemberTypes.Property,
\r
253 BindingFlags.Public | BindingFlags.Instance,
\r
256 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
\r
257 Error_InvalidNamedArgument (member_name);
\r
262 if (member is PropertyExpr) {
\r
263 PropertyExpr pe = (PropertyExpr) member;
\r
264 PropertyInfo pi = pe.PropertyInfo;
\r
266 if (!pi.CanWrite) {
\r
267 Error_InvalidNamedArgument (member_name);
\r
271 if (e is Constant) {
\r
272 object o = ((Constant) e).GetValue ();
\r
273 prop_values.Add (o);
\r
276 if (member_name == "AllowMultiple")
\r
277 this.AllowMultiple = (bool) o;
\r
278 if (member_name == "Inherited")
\r
279 this.Inherited = (bool) o;
\r
282 } else if (e is TypeOf) {
\r
283 prop_values.Add (((TypeOf) e).TypeArg);
\r
285 Error_AttributeArgumentNotValid (Location);
\r
289 prop_infos.Add (pi);
\r
291 } else if (member is FieldExpr) {
\r
292 FieldExpr fe = (FieldExpr) member;
\r
293 FieldInfo fi = fe.FieldInfo;
\r
295 if (fi.IsInitOnly) {
\r
296 Error_InvalidNamedArgument (member_name);
\r
301 // Handle charset here, and set the TypeAttributes
\r
303 if (e is Constant){
\r
304 object value = ((Constant) e).GetValue ();
\r
306 field_values.Add (value);
\r
307 } else if (e is TypeOf) {
\r
308 field_values.Add (((TypeOf) e).TypeArg);
\r
310 Error_AttributeArgumentNotValid (Location);
\r
314 field_infos.Add (fi);
\r
318 Expression mg = Expression.MemberLookup (
\r
319 ec, Type, ".ctor", MemberTypes.Constructor,
\r
320 BindingFlags.Public | BindingFlags.Instance, Location);
\r
323 Error_AttributeConstructorMismatch (Location);
\r
327 MethodBase constructor = Invocation.OverloadResolve (
\r
328 ec, (MethodGroupExpr) mg, pos_args, Location);
\r
330 if (constructor == null) {
\r
331 Error_AttributeConstructorMismatch (Location);
\r
336 // Now we perform some checks on the positional args as they
\r
337 // cannot be null for a constructor which expects a parameter
\r
341 ParameterData pd = Invocation.GetParameterData (constructor);
\r
343 int group_in_params_array = Int32.MaxValue;
\r
345 if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)
\r
346 group_in_params_array = pc-1;
\r
348 for (int j = 0; j < pos_arg_count; ++j) {
\r
349 Argument a = (Argument) pos_args [j];
\r
351 if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
\r
352 Error_AttributeArgumentNotValid (Location);
\r
356 if (j < group_in_params_array)
\r
359 if (j == group_in_params_array){
\r
360 object v = pos_values [j];
\r
361 int count = pos_arg_count - j;
\r
363 object [] array = new object [count];
\r
364 pos_values [j] = array;
\r
367 object [] array = (object []) pos_values [group_in_params_array];
\r
369 array [j - group_in_params_array] = pos_values [j];
\r
374 // Adjust the size of the pos_values if it had params
\r
376 if (group_in_params_array != Int32.MaxValue){
\r
377 int argc = group_in_params_array+1;
\r
378 object [] new_pos_values = new object [argc];
\r
380 for (int p = 0; p < argc; p++)
\r
381 new_pos_values [p] = pos_values [p];
\r
382 pos_values = new_pos_values;
\r
386 if (named_args.Count > 0) {
\r
387 PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];
\r
388 FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];
\r
389 object [] field_values_arr = new object [field_values.Count];
\r
390 object [] prop_values_arr = new object [prop_values.Count];
\r
392 field_infos.CopyTo (field_info_arr, 0);
\r
393 field_values.CopyTo (field_values_arr, 0);
\r
395 prop_values.CopyTo (prop_values_arr, 0);
\r
396 prop_infos.CopyTo (prop_info_arr, 0);
\r
398 cb = new CustomAttributeBuilder (
\r
399 (ConstructorInfo) constructor, pos_values,
\r
400 prop_info_arr, prop_values_arr,
\r
401 field_info_arr, field_values_arr);
\r
404 cb = new CustomAttributeBuilder (
\r
405 (ConstructorInfo) constructor, pos_values);
\r
406 } catch (NullReferenceException) {
\r
408 // Don't know what to do here
\r
411 -100, Location, "NullReferenceException while trying to create attribute. Something's wrong!");
\r
412 } catch (Exception e) {
\r
415 // using System.ComponentModel;
\r
416 // [DefaultValue (CollectionChangeAction.Add)]
\r
417 // class X { static void Main () {} }
\r
421 "The compiler can not encode this attribute in .NET due to\n" +
\r
422 "\ta bug in the .NET runtime. Try the Mono runtime.\nThe error was: " + e.Message);
\r
428 static string GetValidPlaces (Attribute attr)
\r
430 StringBuilder sb = new StringBuilder ();
\r
431 AttributeTargets targets = 0;
\r
433 TypeContainer a = TypeManager.LookupAttr (attr.Type);
\r
437 System.Attribute [] attrs = null;
\r
440 attrs = System.Attribute.GetCustomAttributes (attr.Type);
\r
443 Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
\r
444 " (maybe you forgot to set the usage using the" +
\r
445 " AttributeUsage attribute ?).");
\r
449 foreach (System.Attribute tmp in attrs)
\r
450 if (tmp is AttributeUsageAttribute) {
\r
451 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
455 targets = a.Targets;
\r
458 if ((targets & AttributeTargets.Assembly) != 0)
\r
459 sb.Append ("'assembly' ");
\r
461 if ((targets & AttributeTargets.Class) != 0)
\r
462 sb.Append ("'class' ");
\r
464 if ((targets & AttributeTargets.Constructor) != 0)
\r
465 sb.Append ("'constructor' ");
\r
467 if ((targets & AttributeTargets.Delegate) != 0)
\r
468 sb.Append ("'delegate' ");
\r
470 if ((targets & AttributeTargets.Enum) != 0)
\r
471 sb.Append ("'enum' ");
\r
473 if ((targets & AttributeTargets.Event) != 0)
\r
474 sb.Append ("'event' ");
\r
476 if ((targets & AttributeTargets.Field) != 0)
\r
477 sb.Append ("'field' ");
\r
479 if ((targets & AttributeTargets.Interface) != 0)
\r
480 sb.Append ("'interface' ");
\r
482 if ((targets & AttributeTargets.Method) != 0)
\r
483 sb.Append ("'method' ");
\r
485 if ((targets & AttributeTargets.Module) != 0)
\r
486 sb.Append ("'module' ");
\r
488 if ((targets & AttributeTargets.Parameter) != 0)
\r
489 sb.Append ("'parameter' ");
\r
491 if ((targets & AttributeTargets.Property) != 0)
\r
492 sb.Append ("'property' ");
\r
494 if ((targets & AttributeTargets.ReturnValue) != 0)
\r
495 sb.Append ("'return value' ");
\r
497 if ((targets & AttributeTargets.Struct) != 0)
\r
498 sb.Append ("'struct' ");
\r
500 return sb.ToString ();
\r
504 public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
\r
507 592, loc, "Attribute '" + a.Name +
\r
508 "' is not valid on this declaration type. " +
\r
509 "It is valid on " + GetValidPlaces (a) + "declarations only.");
\r
512 public static bool CheckAttribute (Attribute a, object element)
\r
514 TypeContainer attr = TypeManager.LookupAttr (a.Type);
\r
515 AttributeTargets targets = 0;
\r
518 if (attr == null) {
\r
519 System.Attribute [] attrs = null;
\r
522 attrs = System.Attribute.GetCustomAttributes (a.Type);
\r
525 Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
\r
526 " (maybe you forgot to set the usage using the" +
\r
527 " AttributeUsage attribute ?).");
\r
531 foreach (System.Attribute tmp in attrs)
\r
532 if (tmp is AttributeUsageAttribute)
\r
533 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
535 targets = attr.Targets;
\r
537 if (element is Class) {
\r
538 if ((targets & AttributeTargets.Class) != 0)
\r
543 } else if (element is Struct) {
\r
544 if ((targets & AttributeTargets.Struct) != 0)
\r
548 } else if (element is Constructor) {
\r
549 if ((targets & AttributeTargets.Constructor) != 0)
\r
553 } else if (element is Delegate) {
\r
554 if ((targets & AttributeTargets.Delegate) != 0)
\r
558 } else if (element is Enum) {
\r
559 if ((targets & AttributeTargets.Enum) != 0)
\r
563 } else if (element is Event || element is InterfaceEvent) {
\r
564 if ((targets & AttributeTargets.Event) != 0)
\r
568 } else if (element is Field || element is FieldBuilder) {
\r
569 if ((targets & AttributeTargets.Field) != 0)
\r
573 } else if (element is Interface) {
\r
574 if ((targets & AttributeTargets.Interface) != 0)
\r
578 } else if (element is Method || element is Operator || element is InterfaceMethod || element is Accessor) {
\r
579 if ((targets & AttributeTargets.Method) != 0)
\r
583 } else if (element is ParameterBuilder) {
\r
584 if ((targets & AttributeTargets.Parameter) != 0)
\r
588 } else if (element is Property || element is Indexer ||
\r
589 element is InterfaceProperty || element is InterfaceIndexer) {
\r
590 if ((targets & AttributeTargets.Property) != 0)
\r
594 } else if (element is AssemblyBuilder){
\r
595 if ((targets & AttributeTargets.Assembly) != 0)
\r
605 // This method should be invoked to pull the IndexerName attribute from an
\r
606 // Indexer if it exists.
\r
608 public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
\r
610 if (opt_attrs == null)
\r
612 if (opt_attrs.AttributeSections == null)
\r
615 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
616 if (asec.Attributes == null)
\r
619 foreach (Attribute a in asec.Attributes){
\r
620 if (a.ResolveType (ec) == null)
\r
623 if (a.Type != TypeManager.indexer_name_type)
\r
627 // So we have found an IndexerName, pull the data out.
\r
629 if (a.Arguments == null || a.Arguments [0] == null){
\r
630 Error_AttributeConstructorMismatch (a.Location);
\r
633 ArrayList pos_args = (ArrayList) a.Arguments [0];
\r
634 if (pos_args.Count == 0){
\r
635 Error_AttributeConstructorMismatch (a.Location);
\r
639 Argument arg = (Argument) pos_args [0];
\r
640 if (!arg.Resolve (ec, a.Location))
\r
643 Expression e = arg.Expr;
\r
644 if (!(e is StringConstant)){
\r
645 Error_AttributeConstructorMismatch (a.Location);
\r
650 // Remove the attribute from the list
\r
652 asec.Attributes.Remove (a);
\r
654 return (((StringConstant) e).Value);
\r
661 // This pulls the condition name out of a Conditional attribute
\r
663 public string Conditional_GetConditionName ()
\r
666 // So we have a Conditional, pull the data out.
\r
668 if (Arguments == null || Arguments [0] == null){
\r
669 Error_AttributeConstructorMismatch (Location);
\r
673 ArrayList pos_args = (ArrayList) Arguments [0];
\r
674 if (pos_args.Count != 1){
\r
675 Error_AttributeConstructorMismatch (Location);
\r
679 Argument arg = (Argument) pos_args [0];
\r
680 if (!(arg.Expr is StringConstant)){
\r
681 Error_AttributeConstructorMismatch (Location);
\r
685 return ((StringConstant) arg.Expr).Value;
\r
689 // This pulls the obsolete message and error flag out of an Obsolete attribute
\r
691 public string Obsolete_GetObsoleteMessage (out bool is_error)
\r
695 // So we have an Obsolete, pull the data out.
\r
697 if (Arguments == null || Arguments [0] == null)
\r
700 ArrayList pos_args = (ArrayList) Arguments [0];
\r
701 if (pos_args.Count == 0)
\r
703 else if (pos_args.Count > 2){
\r
704 Error_AttributeConstructorMismatch (Location);
\r
708 Argument arg = (Argument) pos_args [0];
\r
709 if (!(arg.Expr is StringConstant)){
\r
710 Error_AttributeConstructorMismatch (Location);
\r
714 if (pos_args.Count == 2){
\r
715 Argument arg2 = (Argument) pos_args [1];
\r
716 if (!(arg2.Expr is BoolConstant)){
\r
717 Error_AttributeConstructorMismatch (Location);
\r
720 is_error = ((BoolConstant) arg2.Expr).Value;
\r
723 return ((StringConstant) arg.Expr).Value;
\r
727 // Applies the attributes to the `builder'.
\r
729 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
\r
730 Attributes opt_attrs)
\r
732 Type attr_type = null;
\r
734 if (opt_attrs == null)
\r
736 if (opt_attrs.AttributeSections == null)
\r
739 ArrayList emitted_attrs = new ArrayList ();
\r
740 ArrayList emitted_targets = new ArrayList ();
\r
742 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
743 string attr_target = asec.Target;
\r
745 if (asec.Attributes == null)
\r
748 if (attr_target == "assembly" && !(builder is AssemblyBuilder))
\r
751 if (attr_target == "return" && !(builder is ParameterBuilder))
\r
754 foreach (Attribute a in asec.Attributes) {
\r
755 Location loc = a.Location;
\r
756 CustomAttributeBuilder cb = a.Resolve (ec);
\r
757 attr_type = a.Type;
\r
762 if (!(kind is TypeContainer))
\r
763 if (!CheckAttribute (a, kind)) {
\r
764 Error_AttributeNotValidForElement (a, loc);
\r
769 // Perform the check for duplicate attributes
\r
771 if (emitted_attrs.Contains (attr_type) &&
\r
772 emitted_targets.Contains (attr_target) &&
\r
773 !TypeManager.AreMultipleAllowed (attr_type)) {
\r
774 Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");
\r
778 if (kind is Method || kind is Operator || kind is InterfaceMethod ||
\r
779 kind is Accessor) {
\r
780 if (attr_type == TypeManager.methodimpl_attr_type) {
\r
781 if (a.ImplOptions == MethodImplOptions.InternalCall)
\r
782 ((MethodBuilder) builder).
\r
783 SetImplementationFlags (
\r
784 MethodImplAttributes.InternalCall |
\r
785 MethodImplAttributes.Runtime);
\r
787 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
788 } else if (attr_type != TypeManager.dllimport_type){
\r
789 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
791 } else if (kind is Constructor) {
\r
792 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
\r
793 } else if (kind is Field) {
\r
794 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
795 } else if (kind is Property || kind is Indexer ||
\r
796 kind is InterfaceProperty || kind is InterfaceIndexer) {
\r
797 ((PropertyBuilder) builder).SetCustomAttribute (cb);
\r
798 } else if (kind is Event || kind is InterfaceEvent) {
\r
799 ((MyEventBuilder) builder).SetCustomAttribute (cb);
\r
800 } else if (kind is ParameterBuilder) {
\r
802 if (attr_type == TypeManager.marshal_as_attr_type) {
\r
803 UnmanagedMarshal marshal =
\r
804 UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
\r
806 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
810 ((ParameterBuilder) builder).SetCustomAttribute (cb);
\r
811 } catch (System.ArgumentException) {
\r
812 Report.Warning (-24, loc,
\r
813 "The Microsoft Runtime cannot set attributes \n" +
\r
814 "on the return type of a method. Please use the \n" +
\r
815 "Mono runtime instead.");
\r
819 } else if (kind is Enum) {
\r
820 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
822 } else if (kind is TypeContainer) {
\r
823 TypeContainer tc = (TypeContainer) kind;
\r
826 tc.Targets = a.Targets;
\r
827 tc.AllowMultiple = a.AllowMultiple;
\r
828 tc.Inherited = a.Inherited;
\r
830 TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,
\r
833 } else if (attr_type == TypeManager.default_member_type) {
\r
834 if (tc.Indexers != null) {
\r
835 Report.Error (646, loc,
\r
836 "Cannot specify the DefaultMember attribute on" +
\r
837 " a type containing an indexer");
\r
842 if (!CheckAttribute (a, kind)) {
\r
843 Error_AttributeNotValidForElement (a, loc);
\r
849 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
850 } catch (System.ArgumentException) {
\r
853 "The CharSet named property on StructLayout\n"+
\r
854 "\tdoes not work correctly on Microsoft.NET\n"+
\r
855 "\tYou might want to remove the CharSet declaration\n"+
\r
856 "\tor compile using the Mono runtime instead of the\n"+
\r
857 "\tMicrosoft .NET runtime");
\r
860 } else if (kind is Interface) {
\r
861 Interface iface = (Interface) kind;
\r
863 if ((attr_type == TypeManager.default_member_type) &&
\r
864 (iface.InterfaceIndexers != null)) {
\r
867 "Cannot specify the DefaultMember attribute on" +
\r
868 " a type containing an indexer");
\r
872 if (!CheckAttribute (a, kind)) {
\r
873 Error_AttributeNotValidForElement (a, loc);
\r
877 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
878 } else if (kind is AssemblyBuilder){
\r
879 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
\r
880 } else if (kind is ModuleBuilder) {
\r
881 ((ModuleBuilder) builder).SetCustomAttribute (cb);
\r
882 } else if (kind is FieldBuilder) {
\r
883 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
885 throw new Exception ("Unknown kind: " + kind);
\r
888 // Once an attribute type has been emitted once we
\r
889 // keep track of the info to prevent multiple occurences
\r
890 // for attributes which do not explicitly allow it
\r
892 if (!emitted_attrs.Contains (attr_type))
\r
893 emitted_attrs.Add (attr_type);
\r
896 // We keep of this target-wise and so emitted targets
\r
899 if (!emitted_targets.Contains (attr_target))
\r
900 emitted_targets.Add (attr_target);
\r
907 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
\r
908 MethodAttributes flags, Type ret_type, Type [] param_types)
\r
911 // We extract from the attribute the information we need
\r
914 if (Arguments == null) {
\r
915 Console.WriteLine ("Internal error : this is not supposed to happen !");
\r
919 Type = CheckAttributeType (ec);
\r
923 ArrayList named_args = new ArrayList ();
\r
925 ArrayList pos_args = (ArrayList) Arguments [0];
\r
926 if (Arguments.Count > 1)
\r
927 named_args = (ArrayList) Arguments [1];
\r
930 string dll_name = null;
\r
932 Argument tmp = (Argument) pos_args [0];
\r
934 if (!tmp.Resolve (ec, Location))
\r
937 if (tmp.Expr is Constant)
\r
938 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
\r
940 Error_AttributeArgumentNotValid (Location);
\r
944 // Now we process the named arguments
\r
945 CallingConvention cc = CallingConvention.Winapi;
\r
946 CharSet charset = CharSet.Ansi;
\r
947 bool preserve_sig = true;
\r
948 bool exact_spelling = false;
\r
949 bool set_last_err = false;
\r
950 string entry_point = null;
\r
952 for (int i = 0; i < named_args.Count; i++) {
\r
954 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
956 string member_name = (string) de.Key;
\r
957 Argument a = (Argument) de.Value;
\r
959 if (!a.Resolve (ec, Location))
\r
962 Expression member = Expression.MemberLookup (
\r
963 ec, Type, member_name,
\r
964 MemberTypes.Field | MemberTypes.Property,
\r
965 BindingFlags.Public | BindingFlags.Instance,
\r
968 if (member == null || !(member is FieldExpr)) {
\r
969 Error_InvalidNamedArgument (member_name);
\r
973 if (member is FieldExpr) {
\r
974 FieldExpr fe = (FieldExpr) member;
\r
975 FieldInfo fi = fe.FieldInfo;
\r
977 if (fi.IsInitOnly) {
\r
978 Error_InvalidNamedArgument (member_name);
\r
982 if (a.Expr is Constant) {
\r
983 Constant c = (Constant) a.Expr;
\r
985 if (member_name == "CallingConvention")
\r
986 cc = (CallingConvention) c.GetValue ();
\r
987 else if (member_name == "CharSet")
\r
988 charset = (CharSet) c.GetValue ();
\r
989 else if (member_name == "EntryPoint")
\r
990 entry_point = (string) c.GetValue ();
\r
991 else if (member_name == "SetLastError")
\r
992 set_last_err = (bool) c.GetValue ();
\r
993 else if (member_name == "ExactSpelling")
\r
994 exact_spelling = (bool) c.GetValue ();
\r
995 else if (member_name == "PreserveSig")
\r
996 preserve_sig = (bool) c.GetValue ();
\r
998 Error_AttributeArgumentNotValid (Location);
\r
1005 if (entry_point == null)
\r
1006 entry_point = name;
\r
1008 MethodBuilder mb = builder.DefinePInvokeMethod (
\r
1009 name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
\r
1010 CallingConventions.Standard,
\r
1017 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
\r
1024 public class AttributeSection {
\r
1025 public readonly string Target;
\r
1026 public readonly ArrayList Attributes;
\r
1028 public AttributeSection (string target, ArrayList attrs)
\r
1031 Attributes = attrs;
\r
1036 public class Attributes {
\r
1037 public ArrayList AttributeSections;
\r
1039 public Attributes (AttributeSection a)
\r
1041 AttributeSections = new ArrayList ();
\r
1042 AttributeSections.Add (a);
\r
1046 public void AddAttributeSection (AttributeSection a)
\r
1048 if (a != null && !AttributeSections.Contains (a))
\r
1049 AttributeSections.Add (a);
\r
1052 public bool Contains (Type t)
\r
1054 foreach (AttributeSection attr_section in AttributeSections){
\r
1055 foreach (Attribute a in attr_section.Attributes){
\r