Minor changes
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Rewrite / Rewriter.cs
1 //\r
2 // Rewriter.cs\r
3 //\r
4 // Authors:\r
5 //      Chris Bacon (chrisbacon76@gmail.com)\r
6 //\r
7 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)\r
8 //\r
9 // Permission is hereby granted, free of charge, to any person obtaining\r
10 // a copy of this software and associated documentation files (the\r
11 // "Software"), to deal in the Software without restriction, including\r
12 // without limitation the rights to use, copy, modify, merge, publish,\r
13 // distribute, sublicense, and/or sell copies of the Software, and to\r
14 // permit persons to whom the Software is furnished to do so, subject to\r
15 // the following conditions:\r
16 // \r
17 // The above copyright notice and this permission notice shall be\r
18 // included in all copies or substantial portions of the Software.\r
19 // \r
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27 //\r
28 \r
29 using System;\r
30 using System.Collections.Generic;\r
31 using System.Linq;\r
32 using System.Text;\r
33 using Mono.Cecil.Cil;\r
34 using Mono.Cecil;\r
35 using System.IO;\r
36 \r
37 namespace Mono.CodeContracts.Rewrite {\r
38         public class Rewriter {\r
39 \r
40                 public static RewriterResults Rewrite (RewriterOptions options)\r
41                 {\r
42                         Rewriter rewriter = new Rewriter(options);\r
43                         return rewriter.RewriteImpl();\r
44                 }\r
45                 \r
46                 private Rewriter(RewriterOptions options)\r
47                 {\r
48                         this.options = options;\r
49                 }\r
50                 \r
51                 private RewriterOptions options;\r
52                 private List<string> warnings = new List<string> ();\r
53                 private List<string> errors = new List<string> ();\r
54                 private bool usingMdb = false;\r
55                 private bool usingPdb = false;\r
56                 private List<ISymbolReader> symReaders = new List<ISymbolReader> ();\r
57                 \r
58                 private void LoadSymbolReader (AssemblyDefinition assembly) {\r
59                         if (this.options.Assembly.IsStream && this.options.Assembly.Streams.Symbols == null) {\r
60                                 this.warnings.Add ("-debug specified, but no symbol stream provided.");\r
61                         } else {\r
62                                 try {\r
63                                         ISymbolReaderProvider symProv = new Mono.Cecil.Mdb.MdbReaderProvider ();\r
64                                         foreach (var module in assembly.Modules) {\r
65                                                 ISymbolReader sym = this.options.Assembly.IsFilename ?\r
66                                                         symProv.GetSymbolReader (module, this.options.Assembly.Filename) :\r
67                                                         symProv.GetSymbolReader (module, this.options.Assembly.Streams.Symbols);\r
68                                                 module.ReadSymbols (sym);\r
69                                                 this.symReaders.Add (sym);\r
70                                         }\r
71                                         this.usingMdb = true;\r
72                                 } catch {\r
73                                         try {\r
74                                                 ISymbolReaderProvider symProv = new Mono.Cecil.Pdb.PdbReaderProvider ();\r
75                                                 foreach (var module in assembly.Modules) {\r
76                                                         ISymbolReader sym = this.options.Assembly.IsFilename ?\r
77                                                                 symProv.GetSymbolReader (module, this.options.Assembly.Filename) :\r
78                                                                 symProv.GetSymbolReader (module, this.options.Assembly.Streams.Symbols);\r
79                                                         module.ReadSymbols (sym);\r
80                                                         this.symReaders.Add (sym);\r
81                                                 }\r
82                                                 this.usingPdb = true;\r
83                                         } catch {\r
84                                         }\r
85                                 }\r
86                                 if (!this.usingMdb && !this.usingPdb) {\r
87                                         this.warnings.Add ("-debug specified, but no MDB or PDB symbol file found.");\r
88                                 }\r
89                         }\r
90                 }\r
91                 \r
92                 private ISymbolWriter LoadSymbolWriter(AssemblyDefinition assembly, AssemblyRef output)\r
93                 {\r
94                         // TODO: Get symbol writing to work.\r
95                         ISymbolWriterProvider symProv = null;\r
96                         if (this.usingMdb) {\r
97                                 symProv = new Mono.Cecil.Mdb.MdbWriterProvider ();\r
98                         } else if (this.usingPdb) {\r
99                                 symProv = new Mono.Cecil.Pdb.PdbWriterProvider ();\r
100                         } else {\r
101                                 this.warnings.Add ("-writePDBFile specified, but no symbol file found, cannot write symbols.");\r
102                         }\r
103                         if (symProv != null) {\r
104                                 return output.IsFilename ?\r
105                                         symProv.GetSymbolWriter (assembly.MainModule, output.Filename) :\r
106                                         symProv.GetSymbolWriter (assembly.MainModule, output.Streams.Symbols);\r
107                         }\r
108                         return null;\r
109                 }\r
110 \r
111 \r
112                 private RewriterResults RewriteImpl ()\r
113                 {\r
114                         if (!this.options.Rewrite) {\r
115                                 return RewriterResults.Warning ("Not asked to rewrite");\r
116                         }\r
117 \r
118                         if (!this.options.Assembly.IsSet) {\r
119                                 return RewriterResults.Error ("No assembly given to rewrite");\r
120                         }\r
121                         AssemblyDefinition assembly = this.options.Assembly.IsFilename ?\r
122                                 AssemblyDefinition.ReadAssembly (this.options.Assembly.Filename) :\r
123                                 AssemblyDefinition.ReadAssembly (this.options.Assembly.Streams.Assembly);\r
124                         \r
125                         if (this.options.ForceAssemblyRename != null) {\r
126                                 assembly.Name = new AssemblyNameDefinition (this.options.ForceAssemblyRename, new Version (0, 0, 0, 0));\r
127                         }\r
128 \r
129                         if (options.Debug) {\r
130                                 this.LoadSymbolReader (assembly);\r
131                         }\r
132 \r
133                         var output = this.options.OutputFile.IsSet ? this.options.OutputFile : this.options.Assembly;\r
134                         ISymbolWriter symWriter = null;\r
135                         if (options.WritePdbFile) {\r
136                                 if (!options.Debug) {\r
137                                         return RewriterResults.Error ("Must specify -debug if using -writePDBFile.");\r
138                                 }\r
139                                 if (output.IsStream && output.Streams.Symbols==null){\r
140                                         return RewriterResults.Error ("-writePDFFile specified, but no output symbol stream provided.");\r
141                                 }\r
142                                 symWriter = this.LoadSymbolWriter (assembly, output);\r
143                         }\r
144                         \r
145                         try {\r
146                                 PerformRewrite rewriter = new PerformRewrite (symWriter, this.options);\r
147                                 rewriter.Rewrite (assembly);\r
148 \r
149                                 if (output.IsFilename) {\r
150                                         assembly.Name.Name = Path.GetFileNameWithoutExtension (output.Filename);\r
151                                         assembly.Write (output.Filename);\r
152                                 } else {\r
153                                         assembly.Write (output.Streams.Assembly);\r
154                                 }\r
155                         } finally {\r
156                                 if (symWriter != null) {\r
157                                         symWriter.Dispose ();\r
158                                 }\r
159                                 foreach (var symReader in this.symReaders) {\r
160                                         try {\r
161                                                 if (symReader != null) {\r
162                                                         symReader.Dispose ();\r
163                                                 }\r
164                                         } catch {\r
165                                         }\r
166                                 }\r
167                         }\r
168 \r
169                         return new RewriterResults (warnings, errors);\r
170                 }\r
171                 \r
172         }\r
173 }\r