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