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
18 namespace Mono.CSharp {
\r
20 public class Attribute {
\r
22 public readonly string Name;
\r
23 public readonly ArrayList Arguments;
\r
30 // The following are only meaningful when the attribute
\r
31 // being emitted is one of the builtin ones
\r
33 public AttributeTargets Targets;
\r
34 public bool AllowMultiple;
\r
35 public bool Inherited;
\r
37 public bool UsageAttr = false;
\r
39 public Attribute (string name, ArrayList args, Location loc)
\r
46 void error617 (string name)
\r
48 Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
\r
49 "argument. Named attribute arguments must be fields which are not " +
\r
50 "readonly, static or const, or properties with a set accessor which "+
\r
56 Report.Error (182, Location,
\r
57 "An attribute argument must be a constant expression, typeof " +
\r
58 "expression or array creation expression");
\r
61 public CustomAttributeBuilder Resolve (EmitContext ec)
\r
67 if (Name.IndexOf ("Attribute") == -1)
\r
68 name = Name + "Attribute";
\r
69 else if (Name.LastIndexOf ("Attribute") == 0)
\r
70 name = Name + "Attribute";
\r
72 Type = ec.TypeContainer.LookupType (name, false);
\r
75 Report.Error (246, Location, "Could not find attribute '" + Name + "' (are you" +
\r
76 " missing a using directive or an assembly reference ?)");
\r
80 if (Type == TypeManager.attribute_usage_type)
\r
83 // Now we extract the positional and named arguments
\r
85 ArrayList pos_args = new ArrayList ();
\r
86 ArrayList named_args = new ArrayList ();
\r
88 if (Arguments != null) {
\r
89 pos_args = (ArrayList) Arguments [0];
\r
90 if (Arguments.Count > 1)
\r
91 named_args = (ArrayList) Arguments [1];
\r
94 object [] pos_values = new object [pos_args.Count];
\r
97 // First process positional arguments
\r
101 for (i = 0; i < pos_args.Count; i++) {
\r
103 Argument a = (Argument) pos_args [i];
\r
105 if (!a.Resolve (ec, Location))
\r
108 Expression e = Expression.Reduce (ec, a.Expr);
\r
110 if (e is Literal) {
\r
111 pos_values [i] = ((Literal) e).GetValue ();
\r
114 this.Targets = (AttributeTargets) pos_values [0];
\r
122 // Now process named arguments
\r
125 ArrayList field_infos = new ArrayList ();
\r
126 ArrayList prop_infos = new ArrayList ();
\r
127 ArrayList field_values = new ArrayList ();
\r
128 ArrayList prop_values = new ArrayList ();
\r
130 for (i = 0; i < named_args.Count; i++) {
\r
132 DictionaryEntry de = (DictionaryEntry) named_args [i];
\r
134 string member_name = (string) de.Key;
\r
135 Argument a = (Argument) de.Value;
\r
137 if (!a.Resolve (ec, Location))
\r
140 Expression member = Expression.MemberLookup (ec, Type, member_name, false,
\r
141 MemberTypes.Field | MemberTypes.Property,
\r
142 BindingFlags.Public | BindingFlags.Instance,
\r
145 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
\r
146 error617 (member_name);
\r
150 if (member is PropertyExpr) {
\r
151 PropertyExpr pe = (PropertyExpr) member;
\r
152 PropertyInfo pi = pe.PropertyInfo;
\r
154 if (!pi.CanWrite) {
\r
155 error617 (member_name);
\r
159 Expression e = Expression.Reduce (ec, a.Expr);
\r
161 if (e is Literal) {
\r
162 object o = ((Literal) e).GetValue ();
\r
163 prop_values.Add (o);
\r
166 if (member_name == "AllowMultiple")
\r
167 this.AllowMultiple = (bool) o;
\r
168 if (member_name == "Inherited")
\r
169 this.Inherited = (bool) o;
\r
177 prop_infos.Add (pi);
\r
179 } else if (member is FieldExpr) {
\r
180 FieldExpr fe = (FieldExpr) member;
\r
181 FieldInfo fi = fe.FieldInfo;
\r
183 if (fi.IsInitOnly) {
\r
184 error617 (member_name);
\r
188 Expression e = Expression.Reduce (ec, a.Expr);
\r
191 field_values.Add (((Literal) e).GetValue ());
\r
197 field_infos.Add (fi);
\r
201 Expression mg = Expression.MemberLookup (ec, Type, ".ctor", false,
\r
202 MemberTypes.Constructor,
\r
203 BindingFlags.Public | BindingFlags.Instance,
\r
207 Report.Error (-6, Location, "Could not find a constructor for this argument list.");
\r
211 MethodBase constructor = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, pos_args, Location);
\r
213 if (constructor == null) {
\r
214 Report.Error (-6, Location, "Could not find a constructor for this argument list.");
\r
218 PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];
\r
219 FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];
\r
220 object [] field_values_arr = new object [field_values.Count];
\r
221 object [] prop_values_arr = new object [prop_values.Count];
\r
223 field_infos.CopyTo (field_info_arr, 0);
\r
224 field_values.CopyTo (field_values_arr, 0);
\r
226 prop_values.CopyTo (prop_values_arr, 0);
\r
227 prop_infos.CopyTo (prop_info_arr, 0);
\r
229 CustomAttributeBuilder cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, pos_values,
\r
230 prop_info_arr, prop_values_arr,
\r
231 field_info_arr, field_values_arr);
\r
236 static string GetValidPlaces (Attribute attr)
\r
238 StringBuilder sb = new StringBuilder ();
\r
240 TypeContainer a = TypeManager.LookupAttr (attr.Type);
\r
245 if ((a.Targets & AttributeTargets.Assembly) != 0)
\r
246 sb.Append ("'assembly' ");
\r
248 if ((a.Targets & AttributeTargets.Class) != 0)
\r
249 sb.Append ("'class' ");
\r
251 if ((a.Targets & AttributeTargets.Constructor) != 0)
\r
252 sb.Append ("'constructor' ");
\r
254 if ((a.Targets & AttributeTargets.Delegate) != 0)
\r
255 sb.Append ("'delegate' ");
\r
257 if ((a.Targets & AttributeTargets.Enum) != 0)
\r
258 sb.Append ("'enum' ");
\r
260 if ((a.Targets & AttributeTargets.Event) != 0)
\r
261 sb.Append ("'event' ");
\r
263 if ((a.Targets & AttributeTargets.Field) != 0)
\r
264 sb.Append ("'field' ");
\r
266 if ((a.Targets & AttributeTargets.Interface) != 0)
\r
267 sb.Append ("'interface' ");
\r
269 if ((a.Targets & AttributeTargets.Method) != 0)
\r
270 sb.Append ("'method' ");
\r
272 if ((a.Targets & AttributeTargets.Module) != 0)
\r
273 sb.Append ("'module' ");
\r
275 if ((a.Targets & AttributeTargets.Parameter) != 0)
\r
276 sb.Append ("'parameter' ");
\r
278 if ((a.Targets & AttributeTargets.Property) != 0)
\r
279 sb.Append ("'property' ");
\r
281 if ((a.Targets & AttributeTargets.ReturnValue) != 0)
\r
282 sb.Append ("'return value' ");
\r
284 if ((a.Targets & AttributeTargets.Struct) != 0)
\r
285 sb.Append ("'struct' ");
\r
287 return sb.ToString ();
\r
291 public static void Error592 (Attribute a, Location loc)
\r
293 Report.Error (592, loc, "Attribute '" + a.Name + "' is not valid on this declaration type. " +
\r
294 "It is valid on " + GetValidPlaces (a) + "declarations only.");
\r
297 public static bool CheckAttribute (Attribute a, object element)
\r
299 TypeContainer attr = TypeManager.LookupAttr (a.Type);
\r
304 if (element is Class) {
\r
305 if ((attr.Targets & AttributeTargets.Class) != 0)
\r
310 } else if (element is Struct) {
\r
311 if ((attr.Targets & AttributeTargets.Struct) != 0)
\r
315 } else if (element is Constructor) {
\r
316 if ((attr.Targets & AttributeTargets.Constructor) != 0)
\r
320 } else if (element is Delegate) {
\r
321 if ((attr.Targets & AttributeTargets.Delegate) != 0)
\r
325 } else if (element is Enum) {
\r
326 if ((attr.Targets & AttributeTargets.Enum) != 0)
\r
330 } else if (element is Event) {
\r
331 if ((attr.Targets & AttributeTargets.Event) != 0)
\r
335 } else if (element is Field) {
\r
336 if ((attr.Targets & AttributeTargets.Field) != 0)
\r
340 } else if (element is Interface) {
\r
341 if ((attr.Targets & AttributeTargets.Interface) != 0)
\r
345 } else if (element is Method) {
\r
346 if ((attr.Targets & AttributeTargets.Method) != 0)
\r
350 } else if (element is Parameter) {
\r
351 if ((attr.Targets & AttributeTargets.Parameter) != 0)
\r
355 } else if (element is Property) {
\r
356 if ((attr.Targets & AttributeTargets.Property) != 0)
\r
366 public class AttributeSection {
\r
368 public readonly string Target;
\r
369 public readonly ArrayList Attributes;
\r
371 public AttributeSection (string target, ArrayList attrs)
\r
374 Attributes = attrs;
\r
379 public class Attributes {
\r
381 public ArrayList AttributeSections;
\r
383 public Attributes (AttributeSection a)
\r
385 AttributeSections = new ArrayList ();
\r
386 AttributeSections.Add (a);
\r
390 public void AddAttribute (AttributeSection a)
\r
393 AttributeSections.Add (a);
\r