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