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.Collections;
\r
14 using System.Reflection;
\r
15 using System.Reflection.Emit;
\r
16 using System.Runtime.InteropServices;
\r
17 using System.Runtime.CompilerServices;
\r
20 namespace Mono.CSharp {
\r
22 public class Attribute {
\r
23 public readonly string Name;
\r
24 public readonly ArrayList Arguments;
\r
31 // The following are only meaningful when the attribute
\r
32 // being emitted is one of the builtin ones
\r
34 public AttributeTargets Targets;
\r
35 public bool AllowMultiple;
\r
36 public bool Inherited;
\r
38 public bool UsageAttr = false;
\r
40 public MethodImplOptions ImplOptions;
\r
41 public UnmanagedType UnmanagedType;
\r
43 public Attribute (string name, ArrayList args, Location loc)
\r
50 void error617 (string name)
\r
52 Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
\r
53 "argument. Named attribute arguments must be fields which are not " +
\r
54 "readonly, static or const, or properties with a set accessor which "+
\r
60 Report.Error (182, Location,
\r
61 "An attribute argument must be a constant expression, typeof " +
\r
62 "expression or array creation expression");
\r
65 public CustomAttributeBuilder Resolve (EmitContext ec)
\r
68 bool MethodImplAttr = false;
\r
69 bool MarshalAsAttr = false;
\r
73 if (Name.IndexOf ("Attribute") == -1)
\r
74 name = Name + "Attribute";
\r
75 else if (Name.LastIndexOf ("Attribute") == 0)
\r
76 name = Name + "Attribute";
\r
78 Type = RootContext.LookupType (ec.DeclSpace, name, false, Location);
\r
82 246, Location, "Could not find attribute '" + Name + "' (are you" +
\r
83 " missing a using directive or an assembly reference ?)");
\r
87 if (Type == TypeManager.attribute_usage_type)
\r
89 if (Type == TypeManager.methodimpl_attr_type)
\r
90 MethodImplAttr = true;
\r
91 if (Type == TypeManager.marshal_as_attr_type)
\r
92 MarshalAsAttr = true;
\r
95 // Now we extract the positional and named arguments
\r
97 ArrayList pos_args = new ArrayList ();
\r
98 ArrayList named_args = new ArrayList ();
\r
100 if (Arguments != null) {
\r
101 pos_args = (ArrayList) Arguments [0];
\r
102 if (Arguments.Count > 1)
\r
103 named_args = (ArrayList) Arguments [1];
\r
106 object [] pos_values = new object [pos_args.Count];
\r
109 // First process positional arguments
\r
113 for (i = 0; i < pos_args.Count; i++) {
\r
114 Argument a = (Argument) pos_args [i];
\r
117 if (!a.Resolve (ec, Location))
\r
121 if (e is Constant) {
\r
122 pos_values [i] = ((Constant) e).GetValue ();
\r
123 } else if (e is TypeOf) {
\r
124 pos_values [i] = ((TypeOf) e).TypeArg;
\r
131 this.Targets = (AttributeTargets) pos_values [0];
\r
133 if (MethodImplAttr)
\r
134 this.ImplOptions = (MethodImplOptions) pos_values [0];
\r
137 this.UnmanagedType =
\r
138 (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
\r
142 // Now process named arguments
\r
145 ArrayList field_infos = new ArrayList ();
\r
146 ArrayList prop_infos = new ArrayList ();
\r
147 ArrayList field_values = new ArrayList ();
\r
148 ArrayList prop_values = new ArrayList ();
\r
150 for (i = 0; i < named_args.Count; i++) {
\r
151 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
152 string member_name = (string) de.Key;
\r
153 Argument a = (Argument) de.Value;
\r
156 if (!a.Resolve (ec, Location))
\r
159 Expression member = Expression.MemberLookup (
\r
160 ec, Type, member_name,
\r
161 MemberTypes.Field | MemberTypes.Property,
\r
162 BindingFlags.Public | BindingFlags.Instance,
\r
165 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
\r
166 error617 (member_name);
\r
171 if (member is PropertyExpr) {
\r
172 PropertyExpr pe = (PropertyExpr) member;
\r
173 PropertyInfo pi = pe.PropertyInfo;
\r
175 if (!pi.CanWrite) {
\r
176 error617 (member_name);
\r
180 if (e is Constant) {
\r
181 object o = ((Constant) e).GetValue ();
\r
182 prop_values.Add (o);
\r
185 if (member_name == "AllowMultiple")
\r
186 this.AllowMultiple = (bool) o;
\r
187 if (member_name == "Inherited")
\r
188 this.Inherited = (bool) o;
\r
196 prop_infos.Add (pi);
\r
198 } else if (member is FieldExpr) {
\r
199 FieldExpr fe = (FieldExpr) member;
\r
200 FieldInfo fi = fe.FieldInfo;
\r
202 if (fi.IsInitOnly) {
\r
203 error617 (member_name);
\r
208 field_values.Add (((Constant) e).GetValue ());
\r
214 field_infos.Add (fi);
\r
218 Expression mg = Expression.MemberLookup (
\r
219 ec, Type, ".ctor", MemberTypes.Constructor,
\r
220 BindingFlags.Public | BindingFlags.Instance, Location);
\r
225 "Could not find a constructor for this argument list.");
\r
229 MethodBase constructor = Invocation.OverloadResolve (
\r
230 ec, (MethodGroupExpr) mg, pos_args, Location);
\r
232 if (constructor == null) {
\r
235 "Could not find a constructor for this argument list.");
\r
239 PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];
\r
240 FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];
\r
241 object [] field_values_arr = new object [field_values.Count];
\r
242 object [] prop_values_arr = new object [prop_values.Count];
\r
244 field_infos.CopyTo (field_info_arr, 0);
\r
245 field_values.CopyTo (field_values_arr, 0);
\r
247 prop_values.CopyTo (prop_values_arr, 0);
\r
248 prop_infos.CopyTo (prop_info_arr, 0);
\r
250 CustomAttributeBuilder cb = new CustomAttributeBuilder (
\r
251 (ConstructorInfo) constructor, pos_values,
\r
252 prop_info_arr, prop_values_arr,
\r
253 field_info_arr, field_values_arr);
\r
258 static string GetValidPlaces (Attribute attr)
\r
260 StringBuilder sb = new StringBuilder ();
\r
261 AttributeTargets targets = 0;
\r
263 TypeContainer a = TypeManager.LookupAttr (attr.Type);
\r
267 System.Attribute [] attrs = null;
\r
270 attrs = System.Attribute.GetCustomAttributes (attr.Type);
\r
273 Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
\r
274 " (maybe you forgot to set the usage using the" +
\r
275 " AttributeUsage attribute ?).");
\r
279 foreach (System.Attribute tmp in attrs)
\r
280 if (tmp is AttributeUsageAttribute)
\r
281 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
283 targets = a.Targets;
\r
286 if ((targets & AttributeTargets.Assembly) != 0)
\r
287 sb.Append ("'assembly' ");
\r
289 if ((targets & AttributeTargets.Class) != 0)
\r
290 sb.Append ("'class' ");
\r
292 if ((targets & AttributeTargets.Constructor) != 0)
\r
293 sb.Append ("'constructor' ");
\r
295 if ((targets & AttributeTargets.Delegate) != 0)
\r
296 sb.Append ("'delegate' ");
\r
298 if ((targets & AttributeTargets.Enum) != 0)
\r
299 sb.Append ("'enum' ");
\r
301 if ((targets & AttributeTargets.Event) != 0)
\r
302 sb.Append ("'event' ");
\r
304 if ((targets & AttributeTargets.Field) != 0)
\r
305 sb.Append ("'field' ");
\r
307 if ((targets & AttributeTargets.Interface) != 0)
\r
308 sb.Append ("'interface' ");
\r
310 if ((targets & AttributeTargets.Method) != 0)
\r
311 sb.Append ("'method' ");
\r
313 if ((targets & AttributeTargets.Module) != 0)
\r
314 sb.Append ("'module' ");
\r
316 if ((targets & AttributeTargets.Parameter) != 0)
\r
317 sb.Append ("'parameter' ");
\r
319 if ((targets & AttributeTargets.Property) != 0)
\r
320 sb.Append ("'property' ");
\r
322 if ((targets & AttributeTargets.ReturnValue) != 0)
\r
323 sb.Append ("'return value' ");
\r
325 if ((targets & AttributeTargets.Struct) != 0)
\r
326 sb.Append ("'struct' ");
\r
328 return sb.ToString ();
\r
332 public static void error592 (Attribute a, Location loc)
\r
335 592, loc, "Attribute '" + a.Name +
\r
336 "' is not valid on this declaration type. " +
\r
337 "It is valid on " + GetValidPlaces (a) + "declarations only.");
\r
340 public static bool CheckAttribute (Attribute a, object element)
\r
342 TypeContainer attr = TypeManager.LookupAttr (a.Type);
\r
343 AttributeTargets targets = 0;
\r
346 if (attr == null) {
\r
348 System.Attribute [] attrs = null;
\r
351 attrs = System.Attribute.GetCustomAttributes (a.Type);
\r
354 Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
\r
355 " (maybe you forgot to set the usage using the" +
\r
356 " AttributeUsage attribute ?).");
\r
360 foreach (System.Attribute tmp in attrs)
\r
361 if (tmp is AttributeUsageAttribute)
\r
362 targets = ((AttributeUsageAttribute) tmp).ValidOn;
\r
364 targets = attr.Targets;
\r
366 if (element is Class) {
\r
367 if ((targets & AttributeTargets.Class) != 0)
\r
372 } else if (element is Struct) {
\r
373 if ((targets & AttributeTargets.Struct) != 0)
\r
377 } else if (element is Constructor) {
\r
378 if ((targets & AttributeTargets.Constructor) != 0)
\r
382 } else if (element is Delegate) {
\r
383 if ((targets & AttributeTargets.Delegate) != 0)
\r
387 } else if (element is Enum) {
\r
388 if ((targets & AttributeTargets.Enum) != 0)
\r
392 } else if (element is Event) {
\r
393 if ((targets & AttributeTargets.Event) != 0)
\r
397 } else if (element is Field) {
\r
398 if ((targets & AttributeTargets.Field) != 0)
\r
402 } else if (element is Interface) {
\r
403 if ((targets & AttributeTargets.Interface) != 0)
\r
407 } else if (element is Method || element is Operator) {
\r
408 if ((targets & AttributeTargets.Method) != 0)
\r
412 } else if (element is ParameterBuilder) {
\r
413 if ((targets & AttributeTargets.Parameter) != 0)
\r
417 } else if (element is Property) {
\r
418 if ((targets & AttributeTargets.Property) != 0)
\r
422 } else if (element is AssemblyBuilder){
\r
423 if ((targets & AttributeTargets.Assembly) != 0)
\r
432 public static void ApplyAttributes (EmitContext ec, object builder, object kind,
\r
433 Attributes opt_attrs, Location loc)
\r
435 if (opt_attrs == null)
\r
438 if (opt_attrs.AttributeSections == null)
\r
441 foreach (AttributeSection asec in opt_attrs.AttributeSections) {
\r
443 if (asec.Attributes == null)
\r
446 if (asec.Target == "assembly" && !(builder is AssemblyBuilder))
\r
449 foreach (Attribute a in asec.Attributes) {
\r
450 CustomAttributeBuilder cb = a.Resolve (ec);
\r
455 if (!(kind is TypeContainer))
\r
456 if (!CheckAttribute (a, kind)) {
\r
461 if (kind is Method || kind is Operator) {
\r
463 if (a.Type == TypeManager.methodimpl_attr_type) {
\r
464 if (a.ImplOptions == MethodImplOptions.InternalCall)
\r
465 ((MethodBuilder) builder).SetImplementationFlags (
\r
466 MethodImplAttributes.InternalCall |
\r
467 MethodImplAttributes.Runtime);
\r
468 } else if (a.Type != TypeManager.dllimport_type)
\r
469 ((MethodBuilder) builder).SetCustomAttribute (cb);
\r
471 } else if (kind is Constructor) {
\r
472 ((ConstructorBuilder) builder).SetCustomAttribute (cb);
\r
473 } else if (kind is Field) {
\r
474 ((FieldBuilder) builder).SetCustomAttribute (cb);
\r
475 } else if (kind is Property || kind is Indexer) {
\r
476 ((PropertyBuilder) builder).SetCustomAttribute (cb);
\r
477 } else if (kind is Event) {
\r
478 ((EventBuilder) builder).SetCustomAttribute (cb);
\r
479 } else if (kind is ParameterBuilder) {
\r
481 if (a.Type == TypeManager.marshal_as_attr_type) {
\r
482 UnmanagedMarshal marshal =
\r
483 UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
\r
485 ((ParameterBuilder) builder).SetMarshal (marshal);
\r
487 ((ParameterBuilder) builder).SetCustomAttribute (cb);
\r
489 } else if (kind is Enum) {
\r
490 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
492 } else if (kind is TypeContainer) {
\r
493 TypeContainer tc = (TypeContainer) kind;
\r
496 tc.Targets = a.Targets;
\r
497 tc.AllowMultiple = a.AllowMultiple;
\r
498 tc.Inherited = a.Inherited;
\r
500 } else if (a.Type == TypeManager.default_member_type) {
\r
501 if (tc.Indexers != null) {
\r
502 Report.Error (646, loc,
\r
503 "Cannot specify the DefaultMember attribute on" +
\r
504 " a type containing an indexer");
\r
509 if (!CheckAttribute (a, kind)) {
\r
515 ((TypeBuilder) builder).SetCustomAttribute (cb);
\r
517 } else if (kind is AssemblyBuilder){
\r
518 ((AssemblyBuilder) builder).SetCustomAttribute (cb);
\r
519 } else if (kind is ModuleBuilder) {
\r
520 ((ModuleBuilder) builder).SetCustomAttribute (cb);
\r
522 throw new Exception ("Unknown kind: " + kind);
\r
527 public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
\r
528 MethodAttributes flags, Type ret_type, Type [] param_types)
\r
531 // We extract from the attribute the information we need
\r
534 if (Arguments == null) {
\r
535 Console.WriteLine ("Internal error : this is not supposed to happen !");
\r
539 string attr_name = Name;
\r
541 if (Name.IndexOf ("Attribute") == -1)
\r
542 attr_name = Name + "Attribute";
\r
543 else if (Name.LastIndexOf ("Attribute") == 0)
\r
544 attr_name = Name + "Attribute";
\r
546 Type = RootContext.LookupType (ec.DeclSpace, attr_name, false, Location);
\r
548 if (Type == null) {
\r
549 Report.Error (246, Location, "Could not find attribute '" + Name + "' (are you" +
\r
550 " missing a using directive or an assembly reference ?)");
\r
554 ArrayList named_args = new ArrayList ();
\r
556 ArrayList pos_args = (ArrayList) Arguments [0];
\r
557 if (Arguments.Count > 1)
\r
558 named_args = (ArrayList) Arguments [1];
\r
561 string dll_name = null;
\r
563 Argument tmp = (Argument) pos_args [0];
\r
565 if (!tmp.Resolve (ec, Location))
\r
568 if (tmp.Expr is Constant)
\r
569 dll_name = (string) ((Constant) tmp.Expr).GetValue ();
\r
575 // Now we process the named arguments
\r
576 CallingConvention cc = CallingConvention.Winapi;
\r
577 CharSet charset = CharSet.Ansi;
\r
578 bool preserve_sig = true;
\r
579 bool exact_spelling = false;
\r
580 bool set_last_err = false;
\r
581 string entry_point = null;
\r
583 for (int i = 0; i < named_args.Count; i++) {
\r
585 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
587 string member_name = (string) de.Key;
\r
588 Argument a = (Argument) de.Value;
\r
590 if (!a.Resolve (ec, Location))
\r
593 Expression member = Expression.MemberLookup (
\r
594 ec, Type, member_name,
\r
595 MemberTypes.Field | MemberTypes.Property,
\r
596 BindingFlags.Public | BindingFlags.Instance,
\r
599 if (member == null || !(member is FieldExpr)) {
\r
600 error617 (member_name);
\r
604 if (member is FieldExpr) {
\r
605 FieldExpr fe = (FieldExpr) member;
\r
606 FieldInfo fi = fe.FieldInfo;
\r
608 if (fi.IsInitOnly) {
\r
609 error617 (member_name);
\r
613 if (a.Expr is Constant) {
\r
614 Constant c = (Constant) a.Expr;
\r
616 if (member_name == "CallingConvention")
\r
617 cc = (CallingConvention) c.GetValue ();
\r
618 else if (member_name == "CharSet")
\r
619 charset = (CharSet) c.GetValue ();
\r
620 else if (member_name == "EntryPoint")
\r
621 entry_point = (string) c.GetValue ();
\r
622 else if (member_name == "SetLastError")
\r
623 set_last_err = (bool) c.GetValue ();
\r
624 else if (member_name == "ExactSpelling")
\r
625 exact_spelling = (bool) c.GetValue ();
\r
626 else if (member_name == "PreserveSig")
\r
627 preserve_sig = (bool) c.GetValue ();
\r
636 MethodBuilder mb = builder.DefinePInvokeMethod (
\r
637 name, dll_name, flags | MethodAttributes.HideBySig,
\r
638 CallingConventions.Standard,
\r
645 mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
\r
652 public class AttributeSection {
\r
654 public readonly string Target;
\r
655 public readonly ArrayList Attributes;
\r
657 public AttributeSection (string target, ArrayList attrs)
\r
660 Attributes = attrs;
\r
665 public class Attributes {
\r
666 public ArrayList AttributeSections;
\r
667 public Location Location;
\r
669 public Attributes (AttributeSection a, Location loc)
\r
671 AttributeSections = new ArrayList ();
\r
672 AttributeSections.Add (a);
\r
676 public void AddAttribute (AttributeSection a)
\r
679 AttributeSections.Add (a);
\r