2001-12-11 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / attribute.cs
1 //\r
2 // attribute.cs: Attribute Handler\r
3 //\r
4 // Author: Ravi Pratap (ravi@ximian.com)\r
5 //\r
6 // Licensed under the terms of the GNU GPL\r
7 //\r
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)\r
9 //\r
10 //\r
11 \r
12 using System;\r
13 using System.Collections;\r
14 using System.Reflection;\r
15 using System.Reflection.Emit;\r
16 \r
17 namespace CIR {\r
18 \r
19         public class Attribute {\r
20                 \r
21                 public readonly string    Name;\r
22                 public readonly ArrayList Arguments;\r
23 \r
24                 Location Location;\r
25                 \r
26                 public Attribute (string name, ArrayList args, Location loc)\r
27                 {\r
28                         Name = name;\r
29                         Arguments = args;\r
30                         Location = loc;\r
31                 }\r
32 \r
33                 void error617 (string name)\r
34                 {\r
35                         Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +\r
36                                       "argument. Named attribute arguments must be fields which are not " +\r
37                                       "readonly, static or const, or properties with a set accessor which "+\r
38                                       "are not static.");\r
39                 }\r
40 \r
41                 void error182 ()\r
42                 {\r
43                         Report.Error (182, Location,\r
44                                       "An attribute argument must be a constant expression, typeof " +\r
45                                       "expression or array creation expression");\r
46                 }\r
47 \r
48                 public CustomAttributeBuilder Resolve (EmitContext ec)\r
49                 {\r
50                         string name = Name;\r
51 \r
52                         if (Name.IndexOf ("Attribute") == -1)\r
53                                 name = Name + "Attribute";\r
54                         else if (Name.LastIndexOf ("Attribute") == 0)\r
55                                 name = Name + "Attribute";\r
56                         \r
57                         Type attribute_type = ec.TypeContainer.LookupType (name, false);\r
58 \r
59                         if (attribute_type == null) {\r
60                                 Report.Error (246, Location, "Could not find attribute '" + Name + "' (are you" +\r
61                                               " missing a using directive or an assembly reference ?)");\r
62                                 return null;\r
63                         }\r
64                         \r
65                         // Now we extract the positional and named arguments\r
66                         \r
67                         ArrayList pos_args = new ArrayList ();\r
68                         ArrayList named_args = new ArrayList ();\r
69                         \r
70                         if (Arguments != null) {\r
71                                 pos_args = (ArrayList) Arguments [0];\r
72                                 if (Arguments.Count > 1)\r
73                                         named_args = (ArrayList) Arguments [1];\r
74                         }\r
75                                 \r
76                         object [] pos_values = new object [pos_args.Count];\r
77 \r
78                         //\r
79                         // First process positional arguments \r
80                         //\r
81                         \r
82                         int i;\r
83                         for (i = 0; i < pos_args.Count; i++) {\r
84 \r
85                                 Argument a = (Argument) pos_args [i];\r
86 \r
87                                 if (!a.Resolve (ec))\r
88                                         return null;\r
89 \r
90                                 Expression e = Expression.Reduce (ec, a.Expr);\r
91 \r
92                                 if (e is Literal) \r
93                                         pos_values [i] = ((Literal) e).GetValue ();\r
94                                 else { \r
95                                         error182 ();\r
96                                         return null;\r
97                                 }\r
98                         }\r
99 \r
100                         //\r
101                         // Now process named arguments\r
102                         //\r
103 \r
104                         ArrayList field_infos = new ArrayList ();\r
105                         ArrayList prop_infos  = new ArrayList ();\r
106                         ArrayList field_values = new ArrayList ();\r
107                         ArrayList prop_values = new ArrayList ();\r
108 \r
109                         for (i = 0; i < named_args.Count; i++) {\r
110 \r
111                                 DictionaryEntry de = (DictionaryEntry) named_args [i];\r
112 \r
113                                 string member_name = (string) de.Key;\r
114                                 Argument a  = (Argument) de.Value;\r
115 \r
116                                 if (!a.Resolve (ec))\r
117                                         return null;\r
118 \r
119                                 Expression member = Expression.MemberLookup (ec, attribute_type, member_name, false,\r
120                                                                              MemberTypes.Field | MemberTypes.Property,\r
121                                                                              BindingFlags.Public | BindingFlags.Instance,\r
122                                                                              Location);\r
123 \r
124                                 if (member == null || !(member is PropertyExpr || member is FieldExpr)) {\r
125                                         error617 (member_name);\r
126                                         return null;\r
127                                 }\r
128 \r
129                                 if (member is PropertyExpr) {\r
130                                         PropertyExpr pe = (PropertyExpr) member;\r
131                                         PropertyInfo pi = pe.PropertyInfo;\r
132 \r
133                                         if (!pi.CanWrite) {\r
134                                                 error617 (member_name);\r
135                                                 return null;\r
136                                         }\r
137 \r
138                                         Expression e = Expression.Reduce (ec, a.Expr);\r
139                                         \r
140                                         if (e is Literal) \r
141                                                 prop_values.Add (((Literal) e).GetValue ());\r
142                                         else { \r
143                                                 error182 ();\r
144                                                 return null;\r
145                                         }\r
146                                         \r
147                                         prop_infos.Add (pi);\r
148                                         \r
149                                 } else if (member is FieldExpr) {\r
150                                         FieldExpr fe = (FieldExpr) member;\r
151                                         FieldInfo fi = fe.FieldInfo;\r
152 \r
153                                         if (fi.IsInitOnly) {\r
154                                                 error617 (member_name);\r
155                                                 return null;\r
156                                         }\r
157 \r
158                                         Expression e = Expression.Reduce (ec, a.Expr);\r
159                                         \r
160                                         if (e is Literal) \r
161                                                 field_values.Add (((Literal) e).GetValue ());\r
162                                         else { \r
163                                                 error182 ();\r
164                                                 return null;\r
165                                         }\r
166                                         \r
167                                         field_infos.Add (fi);\r
168                                 }\r
169                         }\r
170                         \r
171                         Expression mg = Expression.MemberLookup (ec, attribute_type, ".ctor", false,\r
172                                                                  MemberTypes.Constructor,\r
173                                                                  BindingFlags.Public | BindingFlags.Instance,\r
174                                                                  Location);\r
175 \r
176                         if (mg == null) {\r
177                                 Report.Error (-6, Location, "Could not find a constructor for this argument list.");\r
178                                 return null;\r
179                         }\r
180 \r
181                         MethodBase constructor = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, pos_args, Location);\r
182 \r
183                         if (constructor == null) {\r
184                                 Report.Error (-6, Location, "Could not find a constructor for this argument list.");\r
185                                 return null;\r
186                         }\r
187                         \r
188                         PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];\r
189                         FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];\r
190                         object [] field_values_arr = new object [field_values.Count];\r
191                         object [] prop_values_arr = new object [prop_values.Count];\r
192 \r
193                         field_infos.CopyTo  (field_info_arr, 0);\r
194                         field_values.CopyTo (field_values_arr, 0);\r
195 \r
196                         prop_values.CopyTo  (prop_values_arr, 0);\r
197                         prop_infos.CopyTo   (prop_info_arr, 0);\r
198                         \r
199                         CustomAttributeBuilder cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, pos_values,\r
200                                                                                 prop_info_arr, prop_values_arr,\r
201                                                                                 field_info_arr, field_values_arr); \r
202                         \r
203                         return cb;\r
204                 }\r
205 \r
206         }\r
207         \r
208         public class AttributeSection {\r
209                 \r
210                 public readonly string    Target;\r
211                 public readonly ArrayList Attributes;\r
212                 \r
213                 public AttributeSection (string target, ArrayList attrs)\r
214                 {\r
215                         Target = target;\r
216                         Attributes = attrs;\r
217                 }\r
218                 \r
219         }\r
220 \r
221         public class Attributes {\r
222 \r
223                 public ArrayList AttributeSections;\r
224 \r
225                 public Attributes (AttributeSection a)\r
226                 {\r
227                         AttributeSections = new ArrayList ();\r
228                         AttributeSections.Add (a);\r
229 \r
230                 }\r
231 \r
232                 public void AddAttribute (AttributeSection a)\r
233                 {\r
234                         if (a != null)\r
235                                 AttributeSections.Add (a);\r
236                 }\r
237                 \r
238         }\r
239 }\r