2007-12-27 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / mcs / report.cs
1 //
2 // report.cs: report errors and warnings.
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //         Marek Safar (marek.safar@seznam.cz)         
6 //
7 // (C) 2001 Ximian, Inc. (http://www.ximian.com)
8 //
9
10 using System;
11 using System.IO;
12 using System.Text;
13 using System.Collections;
14 using System.Collections.Specialized;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
18
19 namespace Mono.CSharp {
20
21         /// <summary>
22         ///   This class is used to report errors and warnings t te user.
23         /// </summary>
24         public class Report {
25                 /// <summary>  
26                 ///   Errors encountered so far
27                 /// </summary>
28                 static public int Errors;
29
30                 /// <summary>  
31                 ///   Warnings encountered so far
32                 /// </summary>
33                 static public int Warnings;
34
35                 /// <summary>  
36                 ///   Whether errors should be throw an exception
37                 /// </summary>
38                 static public bool Fatal;
39                 
40                 /// <summary>  
41                 ///   Whether warnings should be considered errors
42                 /// </summary>
43                 static public bool WarningsAreErrors;
44
45
46                 /// <summary>  
47                 ///   Whether to dump a stack trace on errors. 
48                 /// </summary>
49                 static public bool Stacktrace;
50
51                 static public TextWriter Stderr = Console.Error;
52                 
53                 //
54                 // If the 'expected' error code is reported then the
55                 // compilation succeeds.
56                 //
57                 // Used for the test suite to excercise the error codes
58                 //
59                 static int expected_error = 0;
60
61                 //
62                 // Keeps track of the warnings that we are ignoring
63                 //
64                 public static Hashtable warning_ignore_table;
65
66                 static Hashtable warning_regions_table;
67
68                 //
69                 // This is used to save/restore the error state.  When the
70                 // error stack contains elements, warnings and errors are not
71                 // reported to the user.  This is used by the Lambda expression
72                 // support to compile the code with various parameter values.
73                 // A stack because of `Report.Errors == errors;'
74                 //
75                 static Stack error_stack;
76                 static Stack warning_stack;
77                 static bool reporting_disabled;
78                 
79                 static int warning_level;
80                 
81                 /// <summary>
82                 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
83                 /// </summary>
84                 static ArrayList extra_information = new ArrayList ();
85
86                 // 
87                 // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
88                 //
89                 public static readonly int[] AllWarnings = new int[] {
90                         28, 67, 78,
91                         105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
92                         219, 251, 252, 253, 278, 282,
93                         419, 420, 429, 436, 440, 465, 467, 469, 472,
94                         612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675,
95                         809,
96                         1030,
97                         1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
98                         1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692,
99                         1717, 1718, 1720,
100                         1901,
101                         2002, 2023, 2029,
102                         3005, 3012, 3018, 3019, 3021, 3022, 3023, 3026, 3027,
103 #if GMCS_SOURCE
104                         402, 414, 458, 693, 1058, 1700, 3024
105 #endif
106                 };
107
108                 static Report ()
109                 {
110                         // Just to be sure that binary search is working
111                         Array.Sort (AllWarnings);
112                 }
113
114                 public static void Reset ()
115                 {
116                         Errors = Warnings = 0;
117                         WarningsAreErrors = false;
118                         warning_ignore_table = null;
119                         warning_regions_table = null;
120                         reporting_disabled = false;
121                 }
122
123                 public static void DisableReporting ()
124                 {
125                         if (error_stack == null)
126                                 error_stack = new Stack ();
127                         error_stack.Push (Errors);
128
129                         if (Warnings > 0) {
130                                 if (warning_stack == null)
131                                         warning_stack = new Stack ();
132                                 warning_stack.Push (Warnings);
133                         }
134
135                         reporting_disabled = true;
136                 }
137
138                 public static void EnableReporting ()
139                 {
140                         if (warning_stack != null)
141                                 Warnings = (int) warning_stack.Pop ();
142
143                         Errors = (int) error_stack.Pop ();
144                         if (error_stack.Count == 0) {
145                                 reporting_disabled = false;
146                         }
147                 }
148
149                 public static IMessageRecorder msg_recorder;
150
151                 public static IMessageRecorder SetMessageRecorder (IMessageRecorder recorder)
152                 {
153                         IMessageRecorder previous = msg_recorder;
154                         msg_recorder = recorder;
155                         return previous;
156                 }
157
158                 public interface IMessageRecorder
159                 {
160                         void EndSession ();
161                         void AddMessage (AbstractMessage msg);
162                         bool PrintMessages ();
163                 }
164
165                 //
166                 // Default message recorder, it uses two types of message groups.
167                 // Common messages: messages reported in all sessions.
168                 // Merged messages: union of all messages in all sessions. 
169                 //              
170                 public struct MessageRecorder : IMessageRecorder
171                 {
172                         ArrayList session_messages;
173                         //
174                         // A collection of exactly same messages reported in all sessions
175                         //
176                         ArrayList common_messages;
177
178                         //
179                         // A collection of unique messages reported in all sessions
180                         //
181                         ArrayList merged_messages;
182
183                         public void EndSession ()
184                         {
185                                 if (session_messages == null)
186                                         return;
187
188                                 //
189                                 // Handles the first session
190                                 //
191                                 if (common_messages == null) {
192                                         common_messages = new ArrayList (session_messages);
193                                         merged_messages = session_messages;
194                                         session_messages = null;
195                                         return;
196                                 }
197
198                                 //
199                                 // Store common messages if any
200                                 //
201                                 for (int i = 0; i < common_messages.Count; ++i) {
202                                         AbstractMessage cmsg = (AbstractMessage) common_messages [i];
203                                         bool common_msg_found = false;
204                                         foreach (AbstractMessage msg in session_messages) {
205                                                 if (cmsg.Equals (msg)) {
206                                                         common_msg_found = true;
207                                                         break;
208                                                 }
209                                         }
210
211                                         if (!common_msg_found)
212                                                 common_messages.RemoveAt (i);
213                                 }
214
215                                 //
216                                 // Merge session and previous messages
217                                 //
218                                 for (int i = 0; i < session_messages.Count; ++i) {
219                                         AbstractMessage msg = (AbstractMessage) session_messages [i];
220                                         bool msg_found = false;
221                                         for (int ii = 0; ii < merged_messages.Count; ++ii) {
222                                                 if (msg.Equals (merged_messages [ii])) {
223                                                         msg_found = true;
224                                                         break;
225                                                 }
226                                         }
227
228                                         if (!msg_found)
229                                                 merged_messages.Add (msg);
230                                 }
231                         }
232
233                         public void AddMessage (AbstractMessage msg)
234                         {
235                                 if (session_messages == null)
236                                         session_messages = new ArrayList ();
237
238                                 session_messages.Add (msg);
239                         }
240
241                         //
242                         // Prints collected messages, common messages have a priority
243                         //
244                         public bool PrintMessages ()
245                         {
246                                 ArrayList messages_to_print = merged_messages;
247                                 if (common_messages != null && common_messages.Count > 0) {
248                                         messages_to_print = common_messages;
249                                 }
250
251                                 if (messages_to_print == null)
252                                         return false;
253
254                                 foreach (AbstractMessage msg in messages_to_print)
255                                         msg.Print ();
256
257                                 return true;
258                         }
259                 }
260                 
261                 public abstract class AbstractMessage
262                 {
263                         readonly string[] extra_info;
264                         protected readonly int code;
265                         protected readonly Location location;
266                         readonly string message;
267
268                         protected AbstractMessage (int code, Location loc, string msg, ArrayList extraInfo)
269                         {
270                                 this.code = code;
271                                 if (code < 0)
272                                         this.code = 8000 - code;
273
274                                 this.location = loc;
275                                 this.message = msg;
276                                 if (extraInfo.Count != 0) {
277                                         this.extra_info = (string[])extraInfo.ToArray (typeof (string));
278                                 }
279                         }
280
281                         protected AbstractMessage (AbstractMessage aMsg)
282                         {
283                                 this.code = aMsg.code;
284                                 this.location = aMsg.location;
285                                 this.message = aMsg.message;
286                                 this.extra_info = aMsg.extra_info;
287                         }
288
289                         static void Check (int code)
290                         {
291                                 if (code == expected_error) {
292                                         Environment.Exit (0);
293                                 }
294                         }
295
296                         public override bool Equals (object obj)
297                         {
298                                 AbstractMessage msg = obj as AbstractMessage;
299                                 if (msg == null)
300                                         return false;
301
302                                 return code == msg.code && location.Equals (msg.location) && message == msg.message;
303                         }
304
305                         public override int GetHashCode ()
306                         {
307                                 return code.GetHashCode ();
308                         }
309
310                         public abstract bool IsWarning { get; }
311
312                         public abstract string MessageType { get; }
313
314                         public virtual void Print ()
315                         {
316                                 if (msg_recorder != null) {
317                                         //
318                                         // This line is useful when debugging messages recorder
319                                         //
320                                         // Console.WriteLine ("RECORDING: {0} {1} {2}", code, location, message);
321                                         msg_recorder.AddMessage (this);
322                                         return;
323                                 }
324
325                                 if (reporting_disabled)
326                                         return;
327
328                                 StringBuilder msg = new StringBuilder ();
329                                 if (!location.IsNull) {
330                                         msg.Append (location.ToString ());
331                                         msg.Append (" ");
332                                 }
333                                 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, message);
334
335                                 //
336                                 // 
337                                 if (Stderr == Console.Error)
338                                         Stderr.WriteLine (ColorFormat (msg.ToString ()));
339                                 else
340                                         Stderr.WriteLine (msg.ToString ());
341
342                                 if (extra_info != null) {
343                                         foreach (string s in extra_info)
344                                                 Stderr.WriteLine (s + MessageType + ")");
345                                 }
346
347                                 if (Stacktrace)
348                                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
349
350                                 if (Fatal) {
351                                         if (!IsWarning || WarningsAreErrors)
352                                                 throw new Exception (message);
353                                 }
354
355                                 Check (code);
356                         }
357
358                         public virtual string ColorFormat (string s)
359                         {
360                                 return s;
361                         }
362                 }
363
364                 sealed class WarningMessage : AbstractMessage
365                 {
366                         readonly int Level;
367
368                         public WarningMessage (int code, int level, Location loc, string message, ArrayList extra_info)
369                                 : base (code, loc, message, extra_info)
370                         {
371                                 Level = level;
372                         }
373
374                         public override bool IsWarning {
375                                 get { return true; }
376                         }
377
378                         bool IsEnabled ()
379                         {
380                                 if (WarningLevel < Level)
381                                         return false;
382
383                                 if (warning_ignore_table != null) {
384                                         if (warning_ignore_table.Contains (code)) {
385                                                 return false;
386                                         }
387                                 }
388
389                                 if (warning_regions_table == null || location.IsNull)
390                                         return true;
391
392                                 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
393                                 if (regions == null)
394                                         return true;
395
396                                 return regions.IsWarningEnabled (code, location.Row);
397                         }
398
399                         public override void Print ()
400                         {
401                                 if (!IsEnabled ())
402                                         return;
403
404                                 if (WarningsAreErrors) {
405                                         new ErrorMessage (this).Print ();
406                                         return;
407                                 }
408
409                                 Warnings++;
410                                 base.Print ();
411                         }
412
413                         public override string MessageType {
414                                 get {
415                                         return "warning";
416                                 }
417                         }
418                 }
419
420                 static int NameToCode (string s)
421                 {
422                         switch (s){
423                         case "black":
424                                 return 0;
425                         case "red":
426                                 return 1;
427                         case "green":
428                                 return 2;
429                         case "yellow":
430                                 return 3;
431                         case "blue":
432                                 return 4;
433                         case "magenta":
434                                 return 5;
435                         case "cyan":
436                                 return 6;
437                         case "grey":
438                         case "white":
439                                 return 7;
440                         }
441                         return 7;
442                 }
443                 
444                 //
445                 // maps a color name to its xterm color code
446                 //
447                 static string GetForeground (string s)
448                 {
449                         string highcode;
450
451                         if (s.StartsWith ("bright")){
452                                 highcode = "1;";
453                                 s = s.Substring (6);
454                         } else
455                                 highcode = "";
456
457                         return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m";
458                 }
459
460                 static string GetBackground (string s)
461                 {
462                         return "\x001b[" + (40 + NameToCode (s)).ToString () + "m";
463                 }
464                 
465                 sealed class ErrorMessage : AbstractMessage
466                 {
467                         static string prefix, postfix;
468
469                         [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
470                         extern static int _isatty (int fd);
471                         
472                         static bool isatty (int fd)
473                         {
474                                 try {
475                                         return _isatty (fd) == 1;
476                                 } catch {
477                                         return false;
478                                 }
479                         }
480                         
481                         static ErrorMessage ()
482                         {
483                                 string term = Environment.GetEnvironmentVariable ("TERM");
484                                 bool xterm_colors = false;
485                                 
486                                 switch (term){
487                                 case "xterm":
488                                 case "rxvt":
489                                 case "rxvt-unicode": 
490                                         if (Environment.GetEnvironmentVariable ("COLORTERM") != null){
491                                                 xterm_colors = true;
492                                         }
493                                         break;
494
495                                 case "xterm-color":
496                                         xterm_colors = true;
497                                         break;
498                                 }
499                                 if (!xterm_colors)
500                                         return;
501
502                                 if (!(isatty (1) && isatty (2)))
503                                         return;
504                                 
505                                 string config = Environment.GetEnvironmentVariable ("MCS_COLORS");
506                                 if (config == null){
507                                         config = "errors=red";
508                                         //config = "brightwhite,red";
509                                 }
510
511                                 if (config == "disable")
512                                         return;
513
514                                 if (!config.StartsWith ("errors="))
515                                         return;
516
517                                 config = config.Substring (7);
518                                 
519                                 int p = config.IndexOf (",");
520                                 if (p == -1)
521                                         prefix = GetForeground (config);
522                                 else
523                                         prefix = GetBackground (config.Substring (p+1)) + GetForeground (config.Substring (0, p));
524                                 postfix = "\x001b[0m";
525                         }
526
527                         public ErrorMessage (int code, Location loc, string message, ArrayList extraInfo)
528                                 : base (code, loc, message, extraInfo)
529                         {
530                         }
531
532                         public ErrorMessage (AbstractMessage aMsg)
533                                 : base (aMsg)
534                         {
535                         }
536
537                         public override string ColorFormat (string s)
538                         {
539                                 if (prefix != null)
540                                         return prefix + s + postfix;
541                                 return s;
542                         }
543                         
544                         public override void Print()
545                         {
546                                 Errors++;
547                                 base.Print ();
548                         }
549
550                         public override bool IsWarning {
551                                 get { return false; }
552                         }
553
554                         public override string MessageType {
555                                 get {
556                                         return "error";
557                                 }
558                         }
559                 }
560
561                 public static void FeatureIsNotAvailable (Location loc, string feature)
562                 {
563                         string version;
564                         switch (RootContext.Version) {
565                         case LanguageVersion.ISO_1:
566                                 version = "1.0";
567                                 break;
568                         case LanguageVersion.ISO_2:
569                                 version = "2.0";
570                                 break;
571                         case LanguageVersion.Default_MCS:
572                                 Report.Error (1644, loc, "Feature `{0}' is not available in Mono mcs compiler. Consider using Mono gmcs compiler instead",
573                                               feature);
574                                 return;
575                         default:
576                                 throw new InternalErrorException ("Invalid feature version", RootContext.Version);
577                         }
578
579                         Report.Error (1644, loc,
580                                 "Feature `{0}' cannot be used because it is not part of the C# {1} language specification",
581                                       feature, version);
582                 }
583                 
584                 public static string FriendlyStackTrace (Exception e)
585                 {
586                         return FriendlyStackTrace (new StackTrace (e, true));
587                 }
588                 
589                 static string FriendlyStackTrace (StackTrace t)
590                 {               
591                         StringBuilder sb = new StringBuilder ();
592                         
593                         bool foundUserCode = false;
594                         
595                         for (int i = 0; i < t.FrameCount; i++) {
596                                 StackFrame f = t.GetFrame (i);
597                                 MethodBase mb = f.GetMethod ();
598                                 
599                                 if (!foundUserCode && mb.ReflectedType == typeof (Report))
600                                         continue;
601                                 
602                                 foundUserCode = true;
603                                 
604                                 sb.Append ("\tin ");
605                                 
606                                 if (f.GetFileLineNumber () > 0)
607                                         sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
608                                 
609                                 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
610                                 
611                                 bool first = true;
612                                 foreach (ParameterInfo pi in mb.GetParameters ()) {
613                                         if (!first)
614                                                 sb.Append (", ");
615                                         first = false;
616                                         
617                                         sb.Append (TypeManager.CSharpName (pi.ParameterType));
618                                 }
619                                 sb.Append (")\n");
620                         }
621         
622                         return sb.ToString ();
623                 }
624
625                 public static void StackTrace ()
626                 {
627                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
628                 }
629
630                 public static bool IsValidWarning (int code)
631                 {       
632                         return Array.BinarySearch (AllWarnings, code) >= 0;
633                 }
634                         
635                 static public void RuntimeMissingSupport (Location loc, string feature) 
636                 {
637                         Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
638                 }
639
640                 /// <summary>
641                 /// In most error cases is very useful to have information about symbol that caused the error.
642                 /// Call this method before you call Report.Error when it makes sense.
643                 /// </summary>
644                 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
645                 {
646                         SymbolRelatedToPreviousError (loc.ToString (), symbol);
647                 }
648
649                 static public void SymbolRelatedToPreviousError (MemberInfo mi)
650                 {
651                         if (reporting_disabled)
652                                 return;
653
654                         Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType);
655                         if (TypeManager.IsDelegateType (dt)) {
656                                 SymbolRelatedToPreviousError (dt);
657                                 return;
658                         }                       
659                         
660                         DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt);
661                         if (temp_ds == null) {
662                                 SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi));
663                         } else {
664                                 MethodBase mb = mi as MethodBase;
665                                 if (mb != null) {
666                                         mb = TypeManager.DropGenericMethodArguments (mb);
667                                         IMethodData md = TypeManager.GetMethod (mb);
668                                         SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
669                                         return;
670                                 }
671
672                                 MemberCore mc = temp_ds.GetDefinition (mi.Name);
673                                 SymbolRelatedToPreviousError (mc);
674                         }
675                 }
676
677                 static public void SymbolRelatedToPreviousError (MemberCore mc)
678                 {
679                         SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
680                 }
681
682                 static public void SymbolRelatedToPreviousError (Type type)
683                 {
684                         if (reporting_disabled)
685                                 return;
686
687                         type = TypeManager.DropGenericTypeArguments (type);
688
689                         if (TypeManager.IsGenericParameter (type)) {
690                                 TypeParameter tp = TypeManager.LookupTypeParameter (type);
691                                 if (tp != null) {
692                                         SymbolRelatedToPreviousError (tp.Location, "");
693                                         return;
694                                 }
695                         }
696
697                         if (type is TypeBuilder) {
698                                 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
699                                 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
700                         } else if (type.HasElementType) {
701                                 SymbolRelatedToPreviousError (type.GetElementType ());
702                         } else {
703                                 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
704                         }
705                 }
706
707                 static void SymbolRelatedToPreviousError (string loc, string symbol)
708                 {
709                         extra_information.Add (String.Format ("{0} (Location of the symbol related to previous ", loc));
710                 }
711
712                 public static void ExtraInformation (Location loc, string msg)
713                 {
714                         extra_information.Add (String.Format ("{0} {1}", loc, msg));
715                 }
716
717                 public static WarningRegions RegisterWarningRegion (Location location)
718                 {
719                         if (warning_regions_table == null)
720                                 warning_regions_table = new Hashtable ();
721
722                         WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
723                         if (regions == null) {
724                                 regions = new WarningRegions ();
725                                 warning_regions_table.Add (location.Name, regions);
726                         }
727                         return regions;
728                 }
729
730                 static public void Warning (int code, int level, Location loc, string message)
731                 {
732                         WarningMessage w = new WarningMessage (code, level, loc, message, extra_information);
733                         extra_information.Clear ();
734                         w.Print ();
735                 }
736
737                 static public void Warning (int code, int level, Location loc, string format, string arg)
738                 {
739                         WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg), extra_information);
740                         extra_information.Clear ();
741                         w.Print ();
742                 }
743
744                 static public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
745                 {
746                         WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg1, arg2), extra_information);
747                         extra_information.Clear ();
748                         w.Print ();
749                 }
750
751                 static public void Warning (int code, int level, Location loc, string format, params object[] args)
752                 {
753                         WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, args), extra_information);
754                         extra_information.Clear ();
755                         w.Print ();
756                 }
757
758                 static public void Warning (int code, int level, string message)
759                 {
760                         Warning (code, level, Location.Null, message);
761                 }
762
763                 static public void Warning (int code, int level, string format, string arg)
764                 {
765                         Warning (code, level, Location.Null, format, arg);
766                 }
767
768                 static public void Warning (int code, int level, string format, string arg1, string arg2)
769                 {
770                         Warning (code, level, Location.Null, format, arg1, arg2);
771                 }
772
773                 static public void Warning (int code, int level, string format, params string[] args)
774                 {
775                         Warning (code, level, Location.Null, String.Format (format, args));
776                 }
777
778                 static public void Error (int code, Location loc, string error)
779                 {
780                         new ErrorMessage (code, loc, error, extra_information).Print ();
781                         extra_information.Clear ();
782                 }
783
784                 static public void Error (int code, Location loc, string format, string arg)
785                 {
786                         new ErrorMessage (code, loc, String.Format (format, arg), extra_information).Print ();
787                         extra_information.Clear ();
788                 }
789
790                 static public void Error (int code, Location loc, string format, string arg1, string arg2)
791                 {
792                         new ErrorMessage (code, loc, String.Format (format, arg1, arg2), extra_information).Print ();
793                         extra_information.Clear ();
794                 }
795
796                 static public void Error (int code, Location loc, string format, params object[] args)
797                 {
798                         Error (code, loc, String.Format (format, args));
799                 }
800
801                 static public void Error (int code, string error)
802                 {
803                         Error (code, Location.Null, error);
804                 }
805
806                 static public void Error (int code, string format, string arg)
807                 {
808                         Error (code, Location.Null, format, arg);
809                 }
810
811                 static public void Error (int code, string format, string arg1, string arg2)
812                 {
813                         Error (code, Location.Null, format, arg1, arg2);
814                 }
815
816                 static public void Error (int code, string format, params string[] args)
817                 {
818                         Error (code, Location.Null, String.Format (format, args));
819                 }
820
821                 static public void SetIgnoreWarning (int code)
822                 {
823                         if (warning_ignore_table == null)
824                                 warning_ignore_table = new Hashtable ();
825
826                         warning_ignore_table [code] = true;
827                 }
828                 
829                 static public int ExpectedError {
830                         set {
831                                 expected_error = value;
832                         }
833                         get {
834                                 return expected_error;
835                         }
836                 }
837                 
838                 public static int WarningLevel {
839                         get {
840                                 return warning_level;
841                         }
842                         set {
843                                 warning_level = value;
844                         }
845                 }
846
847                 public static int DebugFlags = 0;
848
849                 [Conditional ("MCS_DEBUG")]
850                 static public void Debug (string message, params object[] args)
851                 {
852                         Debug (4, message, args);
853                 }
854                         
855                 [Conditional ("MCS_DEBUG")]
856                 static public void Debug (int category, string message, params object[] args)
857                 {
858                         if ((category & DebugFlags) == 0)
859                                 return;
860
861                         StringBuilder sb = new StringBuilder (message);
862
863                         if ((args != null) && (args.Length > 0)) {
864                                 sb.Append (": ");
865
866                                 bool first = true;
867                                 foreach (object arg in args) {
868                                         if (first)
869                                                 first = false;
870                                         else
871                                                 sb.Append (", ");
872                                         if (arg == null)
873                                                 sb.Append ("null");
874                                         else if (arg is ICollection)
875                                                 sb.Append (PrintCollection ((ICollection) arg));
876                                         else
877                                                 sb.Append (arg);
878                                 }
879                         }
880
881                         Console.WriteLine (sb.ToString ());
882                 }
883
884                 static public string PrintCollection (ICollection collection)
885                 {
886                         StringBuilder sb = new StringBuilder ();
887
888                         sb.Append (collection.GetType ());
889                         sb.Append ("(");
890
891                         bool first = true;
892                         foreach (object o in collection) {
893                                 if (first)
894                                         first = false;
895                                 else
896                                         sb.Append (", ");
897                                 sb.Append (o);
898                         }
899
900                         sb.Append (")");
901                         return sb.ToString ();
902                 }
903         }
904
905         public enum TimerType {
906                 FindMembers     = 0,
907                 TcFindMembers   = 1,
908                 MemberLookup    = 2,
909                 CachedLookup    = 3,
910                 CacheInit       = 4,
911                 MiscTimer       = 5,
912                 CountTimers     = 6
913         }
914
915         public enum CounterType {
916                 FindMembers     = 0,
917                 MemberCache     = 1,
918                 MiscCounter     = 2,
919                 CountCounters   = 3
920         }
921
922         public class Timer
923         {
924                 static DateTime[] timer_start;
925                 static TimeSpan[] timers;
926                 static long[] timer_counters;
927                 static long[] counters;
928
929                 static Timer ()
930                 {
931                         timer_start = new DateTime [(int) TimerType.CountTimers];
932                         timers = new TimeSpan [(int) TimerType.CountTimers];
933                         timer_counters = new long [(int) TimerType.CountTimers];
934                         counters = new long [(int) CounterType.CountCounters];
935
936                         for (int i = 0; i < (int) TimerType.CountTimers; i++) {
937                                 timer_start [i] = DateTime.Now;
938                                 timers [i] = TimeSpan.Zero;
939                         }
940                 }
941
942                 [Conditional("TIMER")]
943                 static public void IncrementCounter (CounterType which)
944                 {
945                         ++counters [(int) which];
946                 }
947
948                 [Conditional("TIMER")]
949                 static public void StartTimer (TimerType which)
950                 {
951                         timer_start [(int) which] = DateTime.Now;
952                 }
953
954                 [Conditional("TIMER")]
955                 static public void StopTimer (TimerType which)
956                 {
957                         timers [(int) which] += DateTime.Now - timer_start [(int) which];
958                         ++timer_counters [(int) which];
959                 }
960
961                 [Conditional("TIMER")]
962                 static public void ShowTimers ()
963                 {
964                         ShowTimer (TimerType.FindMembers, "- FindMembers timer");
965                         ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
966                         ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
967                         ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
968                         ShowTimer (TimerType.CacheInit, "- Cache init");
969                         ShowTimer (TimerType.MiscTimer, "- Misc timer");
970
971                         ShowCounter (CounterType.FindMembers, "- Find members");
972                         ShowCounter (CounterType.MemberCache, "- Member cache");
973                         ShowCounter (CounterType.MiscCounter, "- Misc counter");
974                 }
975
976                 static public void ShowCounter (CounterType which, string msg)
977                 {
978                         Console.WriteLine ("{0} {1}", counters [(int) which], msg);
979                 }
980
981                 static public void ShowTimer (TimerType which, string msg)
982                 {
983                         Console.WriteLine (
984                                 "[{0:00}:{1:000}] {2} (used {3} times)",
985                                 (int) timers [(int) which].TotalSeconds,
986                                 timers [(int) which].Milliseconds, msg,
987                                 timer_counters [(int) which]);
988                 }
989         }
990
991         public class InternalErrorException : Exception {
992                 public InternalErrorException (MemberCore mc, Exception e)
993                         : base (mc.Location + " " + mc.GetSignatureForError (), e)
994                 {
995                 }
996
997                 public InternalErrorException ()
998                         : base ("Internal error")
999                 {
1000                 }
1001
1002                 public InternalErrorException (string message)
1003                         : base (message)
1004                 {
1005                 }
1006
1007                 public InternalErrorException (string message, params object[] args)
1008                         : base (String.Format (message, args))
1009                 { }
1010                 
1011                 public InternalErrorException (Exception e, Location loc)
1012                         : base (loc.ToString (), e)
1013                 {
1014                 }
1015         }
1016
1017         /// <summary>
1018         /// Handles #pragma warning
1019         /// </summary>
1020         public class WarningRegions {
1021
1022                 abstract class PragmaCmd
1023                 {
1024                         public int Line;
1025
1026                         protected PragmaCmd (int line)
1027                         {
1028                                 Line = line;
1029                         }
1030
1031                         public abstract bool IsEnabled (int code, bool previous);
1032                 }
1033                 
1034                 class Disable : PragmaCmd
1035                 {
1036                         int code;
1037                         public Disable (int line, int code)
1038                                 : base (line)
1039                         {
1040                                 this.code = code;
1041                         }
1042
1043                         public override bool IsEnabled (int code, bool previous)
1044                         {
1045                                 return this.code == code ? false : previous;
1046                         }
1047                 }
1048
1049                 class DisableAll : PragmaCmd
1050                 {
1051                         public DisableAll (int line)
1052                                 : base (line) {}
1053
1054                         public override bool IsEnabled(int code, bool previous)
1055                         {
1056                                 return false;
1057                         }
1058                 }
1059
1060                 class Enable : PragmaCmd
1061                 {
1062                         int code;
1063                         public Enable (int line, int code)
1064                                 : base (line)
1065                         {
1066                                 this.code = code;
1067                         }
1068
1069                         public override bool IsEnabled(int code, bool previous)
1070                         {
1071                                 return this.code == code ? true : previous;
1072                         }
1073                 }
1074
1075                 class EnableAll : PragmaCmd
1076                 {
1077                         public EnableAll (int line)
1078                                 : base (line) {}
1079
1080                         public override bool IsEnabled(int code, bool previous)
1081                         {
1082                                 return true;
1083                         }
1084                 }
1085
1086
1087                 ArrayList regions = new ArrayList ();
1088
1089                 public void WarningDisable (int line)
1090                 {
1091                         regions.Add (new DisableAll (line));
1092                 }
1093
1094                 public void WarningDisable (Location location, int code)
1095                 {
1096                         if (CheckWarningCode (code, location))
1097                                 regions.Add (new Disable (location.Row, code));
1098                 }
1099
1100                 public void WarningEnable (int line)
1101                 {
1102                         regions.Add (new EnableAll (line));
1103                 }
1104
1105                 public void WarningEnable (Location location, int code)
1106                 {
1107                         if (CheckWarningCode (code, location))
1108                                 regions.Add (new Enable (location.Row, code));
1109                 }
1110
1111                 public bool IsWarningEnabled (int code, int src_line)
1112                 {
1113                         bool result = true;
1114                         foreach (PragmaCmd pragma in regions) {
1115                                 if (src_line < pragma.Line)
1116                                         break;
1117
1118                                 result = pragma.IsEnabled (code, result);
1119                         }
1120                         return result;
1121                 }
1122
1123                 static bool CheckWarningCode (int code, Location loc)
1124                 {
1125                         if (Report.IsValidWarning (code))
1126                                 return true;
1127
1128                         Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code.ToString ());
1129                         return false;
1130                 }
1131         }
1132 }