[monop] Port to use IKVM.Reflection, add -xi and -xa options to easily lookup Xamarin...
[mono.git] / mcs / tools / monop / monop.cs
1 //
2 // monop -- a semi-clone of javap
3 //
4 // TODO:
5 //   Dump all attributes.
6 //
7 // Authors:
8 //      Ben Maurer (bmaurer@users.sourceforge.net)
9 //      John Luke  (john.luke@gmail.com)
10 //
11 // (C) 2004 Ben Maurer
12 // (C) 2004 John Luke
13 //
14
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36
37 using System;
38 using System.CodeDom.Compiler;
39 using System.Collections;
40 using System.Diagnostics;
41 using System.IO;
42 using IKVM.Reflection;
43 using System.Text;
44 using Mono.CSharp;
45 using Type=IKVM.Reflection.Type;
46
47 class MonoP {
48         static Universe universe = new Universe(UniverseOptions.EnableFunctionPointers | UniverseOptions.ResolveMissingMembers | UniverseOptions.DisablePseudoCustomAttributeRetrieval);
49         static Assembly mscorlib;
50         static Type obsolete_attribute;
51         static string assembly;
52         
53         // very common namespaces, all in corlib
54         static readonly string [] v_common_ns = {
55                 "System",
56                 "System.Collections",
57                 "System.Reflection",
58                 "System.Text",
59                 "System.IO",
60         };
61         
62         static readonly string [] common_assemblies = {
63                 "System.Xml.dll",
64                 "System.Web.dll",
65                 "gtk-sharp.dll",
66                 "glib-sharp.dll"
67         };
68         
69         static readonly string [] common_ns = {
70                 "System.Xml",
71                 "System.Web",
72                 "Foundation",
73                 "CoreFoundation",
74                 "CoreGraphics",
75                 "UIKit",
76                 "Gtk",
77                 "GLib",
78         };
79         
80         static Type GetType (string tname, bool ignoreCase)
81         {
82                 Type t;
83                 if (assembly != null) {
84                         Assembly a = GetAssembly (assembly, true);
85                         t = a.GetType (tname, false, ignoreCase);
86                 } else {
87                         t = mscorlib.GetType (tname, false, ignoreCase);
88                 }
89                 return t;
90         }
91         
92         static string SearchTypes (string name, ref Type retval, out int count)
93         {
94                 StringBuilder sb = new StringBuilder ();
95                 Type current = null;
96                 count = 0;
97
98                 string [] assemblies = GetKnownAssemblyNames ();
99                 for (int i = 0; i < assemblies.Length; i++) {
100                         Console.WriteLine ("Loading {0}", assemblies[i]);
101                         Assembly a = GetAssembly (assemblies [i], false);
102                         if (a == null)
103                                 continue;
104
105                         Type [] types = a.GetTypes ();
106                         for (int j = 0; j < types.Length; j++) {
107                                 Type t = types [j];
108                                 if (t.IsPublic == false)
109                                         continue;
110                                 
111                                 if (t.Name == name || t.Name.ToLower ().IndexOf (name.ToLower ()) > 0) {
112                                         current = t;
113                                         count ++;
114                                         sb.Append (t.FullName + " from " + a.Location + "\n");
115                                 }
116                         }
117                 }
118
119                 if (count == 0) 
120                         return null;
121
122                 if (count == 1) {
123                         retval = current;
124                         return String.Empty;
125                 }
126                 
127                 return sb.ToString ();
128         }
129
130         static string [] GetKnownAssemblyNames ()
131         {
132                 Console.WriteLine (options.PublicDir);
133                 if (options.Style == "xios" || options.Style == "xand"){
134                         return Directory.GetFiles (options.PublicDir, "*.dll");
135                 }
136                 
137                 Process p = new Process ();
138                 p.StartInfo.UseShellExecute = false;
139                 p.StartInfo.RedirectStandardOutput = true;
140                 p.StartInfo.FileName = "gacutil";
141                 p.StartInfo.Arguments = "-l";
142                 try {
143                         p.Start ();
144                 }
145                 catch {
146                         Console.WriteLine ("WARNING: gacutil could not be found.");
147                         return new string[0];
148                 }
149
150                 string s;
151                 ArrayList names = new ArrayList ();
152                 StreamReader output = p.StandardOutput;
153
154                 while ((s = output.ReadLine ()) != null)
155                         names.Add (s);
156
157                 p.WaitForExit ();
158                 
159                 int length = names.Count - 1;
160                 string [] retval = new string [length];
161                 retval [0] = typeof (Object).Assembly.FullName;         
162                 names.CopyTo (1, retval, 1, length - 1); // skip the first and last line
163                 return retval;
164         }
165
166         static Assembly GetAssembly (string assembly, bool exit)
167         {
168                 Assembly a = null;
169
170                 // if -r:~/foo.dll syntax is used the shell misses it
171                 if (assembly.StartsWith ("~/"))
172                         assembly = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), assembly.Substring (2));
173
174                 try {
175                         // if it exists try to use LoadFrom
176                         if (File.Exists (assembly))
177                                 a = universe.LoadFile (assembly);
178                         else
179                                 a = LoadFromMonoPath (assembly);
180                 } catch {
181                         // ignore exception it gets handled below
182                 }
183
184                 if (a == null && exit) {
185                         Console.WriteLine ("Could not load {0}", MonoP.assembly);
186                         Environment.Exit (1);
187                 }
188
189                 return a;
190         }
191
192         static Assembly LoadFromMonoPath (string assembly)
193         {
194                 // ; on win32, : everywhere else
195                 char sep = (Path.DirectorySeparatorChar == '/' ? ':' : ';');
196                 string[] paths = Environment.GetEnvironmentVariable ("MONO_PATH").Split (sep);
197                 foreach (string path in paths) {        
198                         string apath = Path.Combine (path, assembly);
199                         if (File.Exists (apath))
200                                 return universe.LoadFile (apath);       
201                 }
202                 return null;
203         }
204
205         static Type GetType (string tname)
206         {
207                 return GetType (tname, false);
208         }
209
210         static void PrintRefs (string assembly)
211         {
212                 Assembly a = GetAssembly (assembly, true);
213                 foreach (AssemblyName an in a.GetReferencedAssemblies ())
214                         Console.WriteLine (an);
215         }
216
217         static void PrintTypes (string assembly, bool show_private, bool filter_obsolete)
218         {
219                 Assembly a = GetAssembly (assembly, true);
220
221                 Console.WriteLine ();
222                 Console.WriteLine ("Assembly Information:");
223
224                 foreach (string ai in a.ToString ().Split (','))
225                         Console.WriteLine (ai.Trim ());
226                         
227                 Console.WriteLine ();
228                 Type [] types = show_private ? a.GetTypes () : a.GetExportedTypes ();
229                 Array.Sort (types, new TypeSorter ());
230
231                 int obsolete_count = 0;
232                 foreach (Type t in types) {
233                         if (filter_obsolete && t.IsDefined (obsolete_attribute, false))
234                                 obsolete_count++;
235                         else
236                                 Console.WriteLine (t.FullName);
237                 }
238
239                 Console.WriteLine ("\nTotal: {0} types.", types.Length - obsolete_count);
240         }
241         
242         internal static void Completion (string prefix)
243         {
244                 foreach (Type t in mscorlib.GetExportedTypes ()) {
245                         if (t.Name.StartsWith (prefix)) {
246                                 if (Array.IndexOf (v_common_ns, t.Namespace) != -1) {
247                                         Console.WriteLine (t.Name);
248                                         return;
249                                 }
250                         }
251                         
252                         if (t.FullName.StartsWith (prefix)) {
253                                 Console.WriteLine (t.FullName);
254                         }
255                 }
256                 
257                 foreach (string assm in common_assemblies) {
258                         try {
259                                 
260                                 Assembly a = GetAssembly (assm, true);
261                                 foreach (Type t in a.GetExportedTypes ()) {
262                                         
263                                         if (t.Name.StartsWith (prefix)) {
264                                                 if (Array.IndexOf (common_ns, t.Namespace) != -1) {
265                                                         Console.WriteLine (t.Name);
266                                                         return;
267                                                 }
268                                         }
269                                         
270                                         if (t.FullName.StartsWith (prefix)) {
271                                                 Console.WriteLine (t.FullName);
272                                         }
273                                 }
274                                 
275                         } catch {
276                         }
277                 }
278                 
279         }
280
281         static void ShowAll (string assembly, bool show_private, bool filter_obsolete)
282         {
283                 Assembly a = GetAssembly (assembly, true);
284
285                 foreach (string ai in a.ToString ().Split (','))
286                         Console.WriteLine (ai.Trim ());
287                         
288                 Console.WriteLine ();
289                 Type [] types = show_private ? a.GetTypes () : a.GetExportedTypes ();
290                 Array.Sort (types, new TypeSorter ());
291                 
292                 var sw = new StreamWriter (Console.OpenStandardOutput (), Console.Out.Encoding);                                
293                 foreach (Type t in types) {
294                         if (filter_obsolete && t.IsDefined (obsolete_attribute, false))
295                                 continue;
296
297                         new Outline (universe, mscorlib, t, sw, true, show_private, filter_obsolete).OutlineType ();
298                 }
299                 sw.Flush ();
300         }
301
302         static Options options = new Options ();
303         
304         static void Main (string [] args)
305         {
306                 if (!options.ProcessArgs (args))
307                         return;
308                 
309                 if (options.Style == null)
310                         mscorlib = universe.LoadFile (typeof (int).Assembly.Location);
311                 else
312                         mscorlib = universe.LoadFile (Path.Combine (options.PublicDir, "mscorlib.dll"));
313                                                       
314                 obsolete_attribute = mscorlib.GetType ("System.ObsoleteAttribute");
315                 
316                 if (options.AssemblyReference != null) {
317                         assembly = options.AssemblyReference;
318
319                         if (options.ShowAll){
320                                 ShowAll (assembly, options.ShowPrivate, options.FilterObsolete);
321                                 return;
322                         } else {
323                                 if (options.Type == null) {
324                                         if (options.PrintRefs)
325                                                 PrintRefs (assembly);
326                                         else
327                                                 PrintTypes (assembly, options.ShowPrivate, options.FilterObsolete);
328                                         return;
329                                 }
330                         }
331                 }
332                 
333                 string message = null;
334                 string tname = options.Type;
335                 Type t = null;
336                 int count;
337
338
339                 if (options.Search) {
340                         string matches = SearchTypes (tname, ref t, out count);
341
342                         if (count == 0)
343                                 goto notfound;
344
345                         if (count == 1)
346                                 goto found;
347                         
348                         if (count > 1){
349                                 Console.WriteLine ("Found " + count + " types that match:");
350                                 Console.WriteLine (matches);
351                                 return;
352                         }
353                 }
354                         
355                 t = GetType (tname);
356
357                 if (t == null) {
358                         // Try some very common ones, dont load anything
359                         foreach (string ns in v_common_ns) {
360                                 t = GetType (ns + "." + tname, true);
361                                 if (t != null)
362                                         goto found;
363                         }
364                 }
365
366                 if (t == null) {
367                         foreach (string assm in GetKnownAssemblyNames ()) {
368                                 try {
369                                         Assembly a = GetAssembly (assm, false);
370                                         if (a == null)
371                                                 continue;
372                                         t = a.GetType (tname, false, true);
373                                         if (t != null) {
374                                                 message = String.Format ("{0} is included in the {1} assembly.",
375                                                                 t.FullName, 
376                                                                 t.Assembly.GetName ().Name);
377                                                 goto found;
378                                         }
379                                         foreach (string ns in common_ns) {
380                                                 t = a.GetType (ns + "." + tname, false, true);
381                                                 if (t != null) {
382                                                         message = String.Format ("{0} is included in the {1} assembly.",
383                                                                         t.FullName, 
384                                                                         t.Assembly.GetName ().Name);
385                                                         goto found;
386                                                 }
387                                         }
388                                 } catch (Exception e){
389                                         Console.WriteLine ("Failure: " + e);
390                                 }
391                         }
392                 }
393
394         notfound:
395                 if (t == null) {
396                         Console.WriteLine ("Could not find {0}", tname);
397                         return;
398                 }
399         found:
400                 //
401                 // This gets us nice buffering
402                 //
403                 StreamWriter sw = new StreamWriter (Console.OpenStandardOutput (), Console.Out.Encoding);                               
404                 new Outline (universe, mscorlib, t, sw, options.DeclaredOnly, options.ShowPrivate, options.FilterObsolete).OutlineType ();
405                 sw.Flush ();
406
407                 if (message != null)
408                         Console.WriteLine (message);
409         }
410 }
411