Merge branch 'master' of github.com:mono/mono
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Rewrite / Rewriter.cs
1 //
2 // Rewriter.cs
3 //
4 // Authors:
5 //      Chris Bacon (chrisbacon76@gmail.com)
6 //
7 // Copyright (C) 2010 Chris Bacon
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.Generic;
31 using System.Linq;
32 using System.Text;
33 using Mono.Cecil.Cil;
34 using Mono.Cecil;
35 using System.IO;
36 using Mono.CompilerServices.SymbolWriter;
37
38 namespace Mono.CodeContracts.Rewrite {
39         public class Rewriter {
40
41                 public static RewriterResults Rewrite (RewriterOptions options)
42                 {
43                         Rewriter rewriter = new Rewriter(options);
44                         return rewriter.RewriteImpl();
45                 }
46                 
47                 private Rewriter(RewriterOptions options)
48                 {
49                         this.options = options;
50                 }
51                 
52                 private RewriterOptions options;
53                 private List<string> warnings = new List<string> ();
54                 private List<string> errors = new List<string> ();
55                 private bool usingMdb = false;
56                 private bool usingPdb = false;
57                 
58                 private void LoadSymbolReader (AssemblyDefinition assembly) {
59                         if (this.options.Assembly.IsStream && this.options.Assembly.Streams.Symbols == null) {
60                                 this.warnings.Add ("-debug specified, but no symbol stream provided.");
61                         } else {
62                                 try {
63                                         foreach (ModuleDefinition module in assembly.Modules) {
64                                                 module.LoadSymbols ();
65                                         }
66                                         this.usingMdb = true;
67                                 } catch {
68                                 }
69                                 if (!this.usingMdb && !this.usingPdb) {
70                                         this.warnings.Add ("-debug specified, but no MDB or PDB symbol file found.");
71                                 }
72                         }
73                 }
74                 
75                 private ISymbolWriter LoadSymbolWriter(AssemblyDefinition assembly, AssemblyRef output)
76                 {
77                         // TODO: Get symbol writing to work.
78 //                      ISymbolWriterProvider symProv = null;
79 //                      if (this.usingMdb) {
80 //                              symProv = new Mono.Cecil.Mdb.MdbWriterProvider ();
81 //                      } else if (this.usingPdb) {
82 //                              symProv = new Mono.Cecil.Pdb.PdbWriterProvider ();
83 //                      } else {
84 //                              this.warnings.Add ("-writePDBFile specified, but no symbol file found, cannot write symbols.");
85 //                      }
86 //                      if (symProv != null) {
87 //                              return output.IsFilename ?
88 //                                      symProv.GetSymbolWriter (assembly.MainModule, output.Filename) :
89 //                                      symProv.GetSymbolWriter (assembly.MainModule, output.Streams.Symbols);
90 //                      }
91                         return null;
92                 }
93
94
95                 private RewriterResults RewriteImpl ()
96                 {
97                         if (!this.options.Rewrite) {
98                                 return RewriterResults.Warning ("Not asked to rewrite");
99                         }
100
101                         if (!this.options.Assembly.IsSet) {
102                                 return RewriterResults.Error ("No assembly given to rewrite");
103                         }
104                         AssemblyDefinition assembly = this.options.Assembly.IsFilename ?
105                                 AssemblyFactory.GetAssembly (this.options.Assembly.Filename) :
106                                 AssemblyFactory.GetAssembly (this.options.Assembly.Streams.Assembly);
107                         
108                         if (this.options.ForceAssemblyRename != null) {
109                                 assembly.Name.Name = this.options.ForceAssemblyRename;
110                         } else if (this.options.OutputFile.IsSet && this.options.OutputFile.IsFilename) {
111                                 assembly.Name.Name = Path.GetFileNameWithoutExtension(this.options.OutputFile.Filename);
112                         }
113
114                         if (options.Debug) {
115                                 this.LoadSymbolReader (assembly);
116                         }
117
118                         var output = this.options.OutputFile.IsSet ? this.options.OutputFile : this.options.Assembly;
119                         ISymbolWriter symWriter = null;
120                         if (options.WritePdbFile) {
121                                 if (!options.Debug) {
122                                         return RewriterResults.Error ("Must specify -debug if using -writePDBFile.");
123                                 }
124                                 if (output.IsStream && output.Streams.Symbols==null){
125                                         return RewriterResults.Error ("-writePDFFile specified, but no output symbol stream provided.");
126                                 }
127                                 symWriter = this.LoadSymbolWriter (assembly, output);
128                         }
129                         
130                         try {
131                                 PerformRewrite rewriter = new PerformRewrite (symWriter, this.options);
132                                 rewriter.Rewrite (assembly);
133
134                                 if (output.IsFilename) {
135                                         AssemblyFactory.SaveAssembly(assembly, output.Filename);
136                                 } else {
137                                         AssemblyFactory.SaveAssembly(assembly, output.Streams.Assembly);
138                                 }
139                         } finally {
140                                 if (symWriter != null) {
141                                         symWriter.Dispose ();
142                                 }
143                         }
144
145                         return new RewriterResults (warnings, errors);
146                 }
147                 
148         }
149 }