5c9df115b905e05ef074d836ca7def74bcf08bca
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil / DefaultImporter.cs
1 //
2 // DefaultReferenceImporter.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2007 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 namespace Mono.Cecil {
30
31         using System;
32         using System.Collections;
33
34         public class DefaultImporter : IImporter {
35
36                 ModuleDefinition m_module;
37
38                 public ModuleDefinition Module {
39                         get { return m_module; }
40                 }
41
42                 public DefaultImporter (ModuleDefinition module)
43                 {
44                         m_module = module;
45                 }
46
47                 public AssemblyNameReference ImportAssembly (AssemblyNameReference asm)
48                 {
49                         AssemblyNameReference asmRef = GetAssemblyNameReference (asm);
50                         if (asmRef != null)
51                                 return asmRef;
52
53                         asmRef = new AssemblyNameReference (
54                                 asm.Name, asm.Culture, asm.Version);
55                         asmRef.PublicKeyToken = asm.PublicKeyToken;
56                         asmRef.HashAlgorithm = asm.HashAlgorithm;
57                         m_module.AssemblyReferences.Add (asmRef);
58                         return asmRef;
59                 }
60
61                 AssemblyNameReference GetAssemblyNameReference (AssemblyNameReference asm)
62                 {
63                         foreach (AssemblyNameReference reference in m_module.AssemblyReferences)
64                                 if (reference.FullName == asm.FullName)
65                                         return reference;
66
67                         return null;
68                 }
69
70                 TypeReference GetTypeSpec (TypeReference t, ImportContext context)
71                 {
72                         Stack s = new Stack ();
73                         while (t is TypeSpecification) {
74                                 s.Push (t);
75                                 t = (t as TypeSpecification).ElementType;
76                         }
77
78                         TypeReference elementType = ImportTypeReference (t, context);
79                         while (s.Count > 0) {
80                                 t = (TypeReference) s.Pop ();
81                                 if (t is PointerType)
82                                         elementType = new PointerType (elementType);
83                                 else if (t is ArrayType) // deal with complex arrays
84                                         elementType = new ArrayType (elementType);
85                                 else if (t is ReferenceType)
86                                         elementType = new ReferenceType (elementType);
87                                 else if (t is GenericInstanceType) {
88                                         GenericInstanceType git = t as GenericInstanceType;
89                                         GenericInstanceType genElemType = new GenericInstanceType (elementType);
90                                         foreach (TypeReference arg in git.GenericArguments)
91                                                 genElemType.GenericArguments.Add (ImportTypeReference (arg, context));
92
93                                         elementType = genElemType;
94                                 } else
95                                         throw new ReflectionException ("Unknown element type: {0}", t.GetType ().Name);
96                         }
97
98                         return elementType;
99                 }
100
101                 static GenericParameter GetGenericParameter (GenericParameter gp, ImportContext context)
102                 {
103                         GenericParameter p;
104                         if (gp.Owner is TypeReference)
105                                 p = context.GenericContext.Type.GenericParameters [gp.Position];
106                         else if (gp.Owner is MethodReference)
107                                 p = context.GenericContext.Method.GenericParameters [gp.Position];
108                         else
109                                 throw new NotSupportedException ();
110
111                         return p;
112                 }
113
114                 public virtual TypeReference ImportTypeReference (TypeReference t, ImportContext context)
115                 {
116                         if (t.Module == m_module)
117                                 return t;
118
119                         if (t is TypeSpecification)
120                                 return GetTypeSpec (t, context);
121
122                         if (t is GenericParameter)
123                                 return GetGenericParameter (t as GenericParameter, context);
124
125                         TypeReference type = m_module.TypeReferences [t.FullName];
126                         if (type != null)
127                                 return type;
128
129                         AssemblyNameReference asm;
130                         if (t.Scope is AssemblyNameReference)
131                                 asm = ImportAssembly ((AssemblyNameReference) t.Scope);
132                         else if (t.Scope is ModuleDefinition)
133                                 asm = ImportAssembly (((ModuleDefinition) t.Scope).Assembly.Name);
134                         else
135                                 throw new NotImplementedException ();
136
137                         type = new TypeReference (t.Name, t.Namespace, asm, t.IsValueType);
138
139                         context.GenericContext.Type = type;
140
141                         foreach (GenericParameter gp in t.GenericParameters)
142                                 type.GenericParameters.Add (GenericParameter.Clone (gp, context));
143
144                         m_module.TypeReferences.Add (type);
145                         return type;
146                 }
147
148                 public virtual FieldReference ImportFieldReference (FieldReference fr, ImportContext context)
149                 {
150                         if (fr.DeclaringType.Module == m_module)
151                                 return fr;
152
153                         FieldReference field = (FieldReference) GetMemberReference (fr);
154                         if (field != null)
155                                 return field;
156
157                         field = new FieldReference (
158                                 fr.Name,
159                                 ImportTypeReference (fr.DeclaringType, context),
160                                 ImportTypeReference (fr.FieldType, context));
161
162                         m_module.MemberReferences.Add (field);
163                         return field;
164                 }
165
166                 MethodReference GetMethodSpec (MethodReference meth, ImportContext context)
167                 {
168                         if (!(meth is GenericInstanceMethod))
169                                 return null;
170
171                         GenericInstanceMethod gim = meth as GenericInstanceMethod;
172                         GenericInstanceMethod ngim = new GenericInstanceMethod (
173                                 ImportMethodReference (gim.ElementMethod, context));
174
175                         foreach (TypeReference arg in gim.GenericArguments)
176                                 ngim.GenericArguments.Add (ImportTypeReference (arg, context));
177
178                         return ngim;
179                 }
180
181                 public virtual MethodReference ImportMethodReference (MethodReference mr, ImportContext context)
182                 {
183                         if (mr.DeclaringType.Module == m_module)
184                                 return mr;
185
186                         if (mr is MethodSpecification)
187                                 return GetMethodSpec (mr, context);
188
189                         MethodReference meth = (MethodReference) GetMemberReference (mr);
190                         if (meth != null)
191                                 return meth;
192
193                         meth = new MethodReference (
194                                 mr.Name,
195                                 mr.HasThis,
196                                 mr.ExplicitThis,
197                                 mr.CallingConvention);
198                         meth.DeclaringType = ImportTypeReference (mr.DeclaringType, context);
199
200                         TypeReference contextType = meth.DeclaringType.GetOriginalType ();
201
202                         context.GenericContext.Method = meth;
203                         context.GenericContext.Type = contextType;
204
205                         foreach (GenericParameter gp in mr.GenericParameters)
206                                 meth.GenericParameters.Add (GenericParameter.Clone (gp, context));
207
208                         meth.ReturnType.ReturnType = ImportTypeReference (mr.ReturnType.ReturnType, context);
209
210                         foreach (ParameterDefinition param in mr.Parameters)
211                                 meth.Parameters.Add (new ParameterDefinition (
212                                         ImportTypeReference (param.ParameterType, context)));
213
214                         m_module.MemberReferences.Add (meth);
215                         return meth;
216                 }
217
218                 MemberReference GetMemberReference (MemberReference member)
219                 {
220                         foreach (MemberReference reference in m_module.MemberReferences)
221                                 if (reference.ToString () == member.ToString ())
222                                         return reference;
223
224                         return null;
225                 }
226         }
227 }