2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / mcs / import.cs
1 //
2 // import.cs: System.Reflection conversions
3 //
4 // Authors: Marek Safar (marek.safar@gmail.com)
5 //
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
7 //
8 // Copyright 2009, 2010 Novell, Inc
9 //
10
11 using System;
12 using System.Reflection;
13 using System.Runtime.CompilerServices;
14 using System.Linq;
15
16 namespace Mono.CSharp
17 {
18         static class Import
19         {
20                 public static FieldSpec CreateField (FieldInfo fi)
21                 {
22                         // TODO MemberCache: remove
23                         var cs = TypeManager.GetConstant (fi);
24                         if (cs != null)
25                                 return cs;
26                         var fb = TypeManager.GetFieldCore (fi);
27                         if (fb != null)
28                                 return fb.Spec;
29                         // End
30
31                         Modifiers mod = 0;
32                         var fa = fi.Attributes;
33                         switch (fa & FieldAttributes.FieldAccessMask) {
34                                 case FieldAttributes.Public:
35                                         mod = Modifiers.PUBLIC;
36                                         break;
37                                 case FieldAttributes.Assembly:
38                                         mod = Modifiers.INTERNAL;
39                                         break;
40                                 case FieldAttributes.Family:
41                                         mod = Modifiers.PROTECTED;
42                                         break;
43                                 case FieldAttributes.FamORAssem:
44                                         mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
45                                         break;
46                                 default:
47                                         mod = Modifiers.PRIVATE;
48                                         break;
49                         }
50
51                         // TODO MemberCache: Remove completely and use only Imported
52                         IMemberDefinition definition;
53                         var gfd = TypeManager.GetGenericFieldDefinition (fi);
54                         fb = TypeManager.GetFieldCore (gfd);
55                         if (fb != null) {
56                                 definition = fb;
57                         } else {
58                                 cs = TypeManager.GetConstant (gfd);
59                                 if (cs != null)
60                                         definition = cs.MemberDefinition;
61                                 else
62                                         definition = new ImportedMemberDefinition (fi);
63                         }
64
65                         if ((fa & FieldAttributes.Literal) != 0) {
66                                 Expression c;
67                                 if (gfd is System.Reflection.Emit.FieldBuilder) {
68                                         // TODO: Remove after MemberCache
69                                         c = TypeManager.GetConstant (gfd).Value;
70                                 } else {
71                                         c = Constant.CreateConstantFromValue (fi.FieldType, gfd.GetValue (gfd), Location.Null);
72                                 }
73
74                                 return new ConstSpec (definition, fi, mod, c);
75                         }
76
77                         if ((fa & FieldAttributes.InitOnly) != 0) {
78                                 if (fi.FieldType == TypeManager.decimal_type) {
79                                         var dc = ReadDecimalConstant (gfd);
80                                         if (dc != null)
81                                                 return new ConstSpec (definition, fi, mod, dc);
82                                 }
83
84                                 mod |= Modifiers.READONLY;
85                         }
86
87                         if ((fa & FieldAttributes.Static) != 0)
88                                 mod |= Modifiers.STATIC;
89
90                         if (!TypeManager.IsReferenceType (fi.FieldType)) {
91                                 PredefinedAttribute pa = PredefinedAttributes.Get.FixedBuffer;
92                                 if (pa.IsDefined) {
93                                         if (gfd is System.Reflection.Emit.FieldBuilder) {
94                                                  // TODO: Remove this after MemberCache fix
95                                         } else if (gfd.IsDefined (pa.Type, false)) {
96                                                 var element_field = fi.FieldType.GetField (FixedField.FixedElementName);
97                                                 return new FixedFieldSpec (definition, fi, element_field, mod);
98                                         }
99                                 }
100                         }
101
102                         // TODO: volatile
103
104                         return new FieldSpec (definition, fi, mod);
105                 }
106
107                 public static EventSpec CreateEvent (EventInfo ei)
108                 {
109                         // TODO MemberCache: Remove
110                         var ef = TypeManager.GetEventField (ei);
111                         if (ef != null)
112                                 return ef;
113
114                         var add_accessor = CreateMethod (TypeManager.GetAddMethod (ei));
115                         var remove_accessor = CreateMethod (TypeManager.GetRemoveMethod (ei));
116
117                         if (add_accessor.Modifiers != remove_accessor.Modifiers)
118                                 throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
119
120                         var definition = new ImportedMemberDefinition (ei);
121                         return new EventSpec (definition, ei, add_accessor.Modifiers, add_accessor, remove_accessor) {
122                                 EventType = ei.EventHandlerType
123                         };
124                 }
125
126                 public static MethodSpec CreateMethod (MethodBase mb)
127                 {
128                         // TODO MemberCache: Remove
129                         MethodCore mc = TypeManager.GetMethod (mb) as MethodCore;
130                         if (mc != null)
131                                 return mc.Spec;
132
133                         Modifiers mod = 0;
134                         var ma = mb.Attributes;
135                         switch (ma & MethodAttributes.MemberAccessMask) {
136                                 case MethodAttributes.Public:
137                                         mod = Modifiers.PUBLIC;
138                                         break;
139                                 case MethodAttributes.Assembly:
140                                         mod = Modifiers.INTERNAL;
141                                         break;
142                                 case MethodAttributes.Family:
143                                         mod = Modifiers.PROTECTED;
144                                         break;
145                                 case MethodAttributes.FamORAssem:
146                                         mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
147                                         break;
148                                 default:
149                                         mod = Modifiers.PRIVATE;
150                                         break;
151                         }
152
153                         if ((ma & MethodAttributes.Static) != 0)
154                                 mod |= Modifiers.STATIC;
155                         if ((ma & MethodAttributes.Virtual) != 0)
156                                 mod |= Modifiers.VIRTUAL;
157                         if ((ma & MethodAttributes.Abstract) != 0)
158                                 mod |= Modifiers.ABSTRACT;
159                         if ((ma & MethodAttributes.Final) != 0)
160                                 mod |= Modifiers.SEALED;
161
162                         IMemberDefinition definition;
163                         var gmd = mb as MethodInfo;
164                         if (gmd != null && gmd.IsGenericMethodDefinition) {
165                                 definition = new ImportedGenericMethodDefinition (gmd);
166                         } else if (mb.IsGenericMethod) {        // TODO MemberCache: Remove me
167                                 definition = new ImportedGenericMethodDefinition ((MethodInfo) TypeManager.DropGenericMethodArguments (mb));
168                         } else {
169                                 definition = new ImportedMemberDefinition (mb);
170                         }
171
172                         // TODO MemberCache: Use AParametersCollection p = ParametersImported.Create (mb);
173                         AParametersCollection p = TypeManager.GetParameterData (mb);
174
175                         MemberKind kind;
176                         if (mb.IsConstructor) {
177                                 kind = MemberKind.Constructor;
178                         } else {
179                                 //
180                                 // Detect operators and destructors
181                                 //
182                                 string name = mb.Name;
183                                 kind = MemberKind.Method;
184                                 if (!mb.DeclaringType.IsInterface && name.Length > 6) {
185                                         if ((mod & Modifiers.STATIC) != 0 && name[2] == '_' && name[1] == 'p' && name[0] == 'o') {
186                                                 var op_type = Operator.GetType (name);
187                                                 if (op_type.HasValue) {
188                                                         kind = MemberKind.Operator;
189                                                 }
190                                         } else if (p.IsEmpty && (mod & Modifiers.STATIC) == 0 && name == Destructor.MetadataName) {
191                                                 kind = MemberKind.Destructor;
192                                         }
193                                 }
194                         }
195                                 
196                         MethodSpec ms = new MethodSpec (kind, definition, mb, p, mod);
197                         return ms;
198                 }
199
200                 public static PropertySpec CreateProperty (PropertyInfo pi)
201                 {
202                         var definition = new ImportedMemberDefinition (pi);
203                         var mod = Modifiers.PRIVATE;    // TODO: modifiers
204                         return new PropertySpec (MemberKind.Property | MemberKind.Indexer, definition, pi, mod);
205                 }
206
207                 static TypeSpec CreateType (Type type)
208                 {
209                         Modifiers mod = 0;
210                         var ma = type.Attributes;
211                         switch (ma & TypeAttributes.VisibilityMask) {
212                                 case TypeAttributes.Public:
213                                 case TypeAttributes.NestedPublic:
214                                         mod = Modifiers.PUBLIC;
215                                         break;
216                 case TypeAttributes.NestedPrivate:
217                                         mod = Modifiers.PRIVATE;
218                                         break;
219                                 case TypeAttributes.NestedFamily:
220                                         mod = Modifiers.PROTECTED;
221                                         break;
222                                 case TypeAttributes.NestedFamORAssem:
223                                         mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
224                                         break;
225                                 default:
226                                         mod = Modifiers.INTERNAL;
227                                         break;
228                         }
229
230                         var type_def = TypeManager.DropGenericTypeArguments (type);
231
232                         MemberKind kind;
233                         if (type_def.IsInterface)
234                                 kind = MemberKind.Interface;
235                         else if (type_def.IsEnum)
236                                 kind = MemberKind.Enum;
237                         else if (type_def.IsClass) {
238                                 if (type_def.BaseType == TypeManager.multicast_delegate_type)
239                                         kind = MemberKind.Delegate;
240                                 else
241                                         kind = MemberKind.Class;
242                         } else {
243                                 kind = MemberKind.Struct;
244                         }
245
246                         if (type.IsGenericType) {
247                                 throw new NotImplementedException ();
248                         }
249
250                         var definition = new ImportedTypeDefinition (type_def);
251                         var spec = new TypeSpec (kind, definition, type, type.Name, mod);
252
253                         // TODO: BaseType for class only?
254
255                         return spec;
256                 }
257
258                 public static TypeSpec ImportType (Type type)
259                 {
260                         if (type.IsDefined (typeof (CompilerGeneratedAttribute), false))
261                                 return null;
262
263                         return CreateType (type);
264                 }
265
266                 //
267                 // Decimal constants cannot be encoded in the constant blob, and thus are marked
268                 // as IsInitOnly ('readonly' in C# parlance).  We get its value from the 
269                 // DecimalConstantAttribute metadata.
270                 //
271                 static Constant ReadDecimalConstant (FieldInfo fi)
272                 {
273                         PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant;
274                         if (!pa.IsDefined)
275                                 return null;
276
277                         object[] attrs = fi.GetCustomAttributes (pa.Type, false);
278                         if (attrs.Length != 1)
279                                 return null;
280
281                         return new DecimalConstant (((DecimalConstantAttribute) attrs [0]).Value, Location.Null);
282                 }
283         }
284
285         class ImportedMemberDefinition : IMemberDefinition
286         {
287                 protected readonly ICustomAttributeProvider provider;
288
289                 public ImportedMemberDefinition (ICustomAttributeProvider provider)
290                 {
291                         this.provider = provider;
292                 }
293
294                 public ObsoleteAttribute GetObsoleteAttribute ()
295                 {
296                         var res = provider.GetCustomAttributes (typeof (ObsoleteAttribute), false);
297                         if (res == null || res.Length < 1)
298                                 return null;
299
300                         return res [0] as ObsoleteAttribute;
301                 }
302
303                 public void SetIsUsed ()
304                 {
305                         // Unused for imported members
306                 }
307         }
308
309         class ImportedGenericMethodDefinition : ImportedMemberDefinition, IGenericMethodDefinition
310         {
311                 public ImportedGenericMethodDefinition (MethodInfo provider)
312                         : base (provider)
313                 {
314                 }
315
316                 public MethodInfo MakeGenericMethod (Type[] targs)
317                 {
318                         return ((MethodInfo) provider).MakeGenericMethod (targs);
319                 }
320         }
321
322         class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition
323         {
324                 public ImportedTypeDefinition (Type type)
325                         : base (type)
326                 {
327                 }
328
329                 public void LoadMembers (MemberCache cache)
330                 {
331                         throw new NotImplementedException ();
332                 }
333         }
334 }