Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / tools / linker / Mono.Linker / LinkContext.cs
1 //
2 // LinkContext.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 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 using System;
30 using System.Collections;
31 using System.IO;
32
33 using Mono.Cecil;
34 using Mono.Cecil.Cil;
35
36 namespace Mono.Linker {
37
38         public class LinkContext {
39
40                 Pipeline _pipeline;
41                 AssemblyAction _coreAction;
42                 Hashtable _actions;
43                 string _outputDirectory;
44                 Hashtable _parameters;
45                 bool _linkSymbols;
46
47                 AssemblyResolver _resolver;
48
49                 ReaderParameters _readerParameters;
50                 ISymbolReaderProvider _symbolReaderProvider;
51                 ISymbolWriterProvider _symbolWriterProvider;
52
53                 AnnotationStore _annotations;
54
55                 public Pipeline Pipeline {
56                         get { return _pipeline; }
57                 }
58
59                 public AnnotationStore Annotations {
60                         get { return _annotations; }
61                 }
62
63                 public string OutputDirectory {
64                         get { return _outputDirectory; }
65                         set { _outputDirectory = value; }
66                 }
67
68                 public AssemblyAction CoreAction {
69                         get { return _coreAction; }
70                         set { _coreAction = value; }
71                 }
72
73                 public bool LinkSymbols {
74                         get { return _linkSymbols; }
75                         set { _linkSymbols = value; }
76                 }
77
78                 public IDictionary Actions {
79                         get { return _actions; }
80                 }
81
82                 public AssemblyResolver Resolver {
83                         get { return _resolver; }
84                 }
85
86                 public ISymbolReaderProvider SymbolReaderProvider {
87                         get { return _symbolReaderProvider; }
88                         set { _symbolReaderProvider = value; }
89                 }
90
91                 public ISymbolWriterProvider SymbolWriterProvider {
92                         get { return _symbolWriterProvider; }
93                         set { _symbolWriterProvider = value; }
94                 }
95
96                 public LinkContext (Pipeline pipeline)
97                         : this (pipeline, new AssemblyResolver ())
98                 {
99                 }
100
101                 public LinkContext (Pipeline pipeline, AssemblyResolver resolver)
102                 {
103                         _pipeline = pipeline;
104                         _resolver = resolver;
105                         _actions = new Hashtable ();
106                         _parameters = new Hashtable ();
107                         _annotations = new AnnotationStore ();
108                         _readerParameters = new ReaderParameters {
109                                 AssemblyResolver = _resolver,
110                         };
111                 }
112
113                 public TypeDefinition GetType (string fullName)
114                 {
115                         int pos = fullName.IndexOf (",");
116                         fullName = fullName.Replace ("+", "/");
117                         if (pos == -1) {
118                                 foreach (AssemblyDefinition asm in GetAssemblies ()) {
119                                         var type = asm.MainModule.GetType (fullName);
120                                         if (type != null)
121                                                 return type;
122                                 }
123
124                                 return null;
125                         }
126
127                         string asmname = fullName.Substring (pos + 1);
128                         fullName = fullName.Substring (0, pos);
129                         AssemblyDefinition assembly = Resolve (AssemblyNameReference.Parse (asmname));
130                         return assembly.MainModule.GetType (fullName);
131                 }
132
133                 public AssemblyDefinition Resolve (string name)
134                 {
135                         if (File.Exists (name)) {
136                                 AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly (name, _readerParameters);
137                                 _resolver.CacheAssembly (assembly);
138                                 return assembly;
139                         }
140
141                         return Resolve (new AssemblyNameReference (name, new Version ()));
142                 }
143
144                 public AssemblyDefinition Resolve (IMetadataScope scope)
145                 {
146                         AssemblyNameReference reference = GetReference (scope);
147                         try {
148                                 AssemblyDefinition assembly = _resolver.Resolve (reference, _readerParameters);
149
150                                 if (SeenFirstTime (assembly)) {
151                                         SafeReadSymbols (assembly);
152                                         SetAction (assembly);
153                                 }
154
155                                 return assembly;
156                         }
157                         catch {
158                                 throw new AssemblyResolutionException (reference);
159                         }
160                 }
161
162                 bool SeenFirstTime (AssemblyDefinition assembly)
163                 {
164                         return !_annotations.HasAction (assembly);
165                 }
166
167                 public void SafeReadSymbols (AssemblyDefinition assembly)
168                 {
169                         if (!_linkSymbols)
170                                 return;
171
172                         if (assembly.MainModule.HasSymbols)
173                                 return;
174
175                         try {
176                                 if (_symbolReaderProvider != null) {
177                                         var symbolReader = _symbolReaderProvider.GetSymbolReader (
178                                                 assembly.MainModule,
179                                                 assembly.MainModule.FullyQualifiedName);
180
181                                         _annotations.AddSymbolReader (assembly, symbolReader);
182                                         assembly.MainModule.ReadSymbols (symbolReader);
183                                 } else
184                                         assembly.MainModule.ReadSymbols ();
185                         } catch {}
186                 }
187
188                 static AssemblyNameReference GetReference (IMetadataScope scope)
189                 {
190                         AssemblyNameReference reference;
191                         if (scope is ModuleDefinition) {
192                                 AssemblyDefinition asm = ((ModuleDefinition) scope).Assembly;
193                                 reference = asm.Name;
194                         } else
195                                 reference = (AssemblyNameReference) scope;
196
197                         return reference;
198                 }
199
200                 void SetAction (AssemblyDefinition assembly)
201                 {
202                         AssemblyAction action = AssemblyAction.Link;
203
204                         AssemblyNameDefinition name = assembly.Name;
205
206                         if (_actions.Contains (name.Name))
207                                 action = (AssemblyAction) _actions [name.Name];
208                         else if (IsCore (name))
209                                 action = _coreAction;
210
211                         _annotations.SetAction (assembly, action);
212                 }
213
214                 static bool IsCore (AssemblyNameReference name)
215                 {
216                         switch (name.Name) {
217                         case "mscorlib":
218                         case "Accessibility":
219                         case "Mono.Security":
220                                 return true;
221                         default:
222                                 return name.Name.StartsWith ("System")
223                                         || name.Name.StartsWith ("Microsoft");
224                         }
225                 }
226
227                 public AssemblyDefinition [] GetAssemblies ()
228                 {
229                         IDictionary cache = _resolver.AssemblyCache;
230                         AssemblyDefinition [] asms = new AssemblyDefinition [cache.Count];
231                         cache.Values.CopyTo (asms, 0);
232                         return asms;
233                 }
234
235                 public void SetParameter (string key, string value)
236                 {
237                         _parameters [key] = value;
238                 }
239
240                 public bool HasParameter (string key)
241                 {
242                         return _parameters.Contains (key);
243                 }
244
245                 public string GetParameter (string key)
246                 {
247                         return (string) _parameters [key];
248                 }
249         }
250 }