2009-06-10 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.V_3:
591                                 version = "3.0";
592                                 break;
593                         default:
594                                 throw new InternalErrorException ("Invalid feature version", RootContext.Version);
595                         }
596
597                         Report.Error (1644, loc,
598                                 "Feature `{0}' cannot be used because it is not part of the C# {1} language specification",
599                                       feature, version);
600                 }
601
602                 public static void FeatureIsNotSupported (Location loc, string feature)
603                 {
604                         Report.Error (1644, loc,
605                                 "Feature `{0}' is not supported in Mono mcs1 compiler. Consider using the `gmcs' compiler instead",
606                                 feature);
607                 }
608                 
609                 public static string FriendlyStackTrace (Exception e)
610                 {
611                         return FriendlyStackTrace (new StackTrace (e, true));
612                 }
613                 
614                 static string FriendlyStackTrace (StackTrace t)
615                 {               
616                         StringBuilder sb = new StringBuilder ();
617                         
618                         bool foundUserCode = false;
619                         
620                         for (int i = 0; i < t.FrameCount; i++) {
621                                 StackFrame f = t.GetFrame (i);
622                                 MethodBase mb = f.GetMethod ();
623                                 
624                                 if (!foundUserCode && mb.ReflectedType == typeof (Report))
625                                         continue;
626                                 
627                                 foundUserCode = true;
628                                 
629                                 sb.Append ("\tin ");
630                                 
631                                 if (f.GetFileLineNumber () > 0)
632                                         sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
633                                 
634                                 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
635                                 
636                                 bool first = true;
637                                 foreach (ParameterInfo pi in mb.GetParameters ()) {
638                                         if (!first)
639                                                 sb.Append (", ");
640                                         first = false;
641                                         
642                                         sb.Append (TypeManager.CSharpName (pi.ParameterType));
643                                 }
644                                 sb.Append (")\n");
645                         }
646         
647                         return sb.ToString ();
648                 }
649
650                 public static void StackTrace ()
651                 {
652                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
653                 }
654
655                 static bool IsValidWarning (int code)
656                 {       
657                         return Array.BinarySearch (AllWarnings, code) >= 0;
658                 }
659                         
660                 static public void RuntimeMissingSupport (Location loc, string feature) 
661                 {
662                         Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
663                 }
664
665                 /// <summary>
666                 /// In most error cases is very useful to have information about symbol that caused the error.
667                 /// Call this method before you call Report.Error when it makes sense.
668                 /// </summary>
669                 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
670                 {
671                         SymbolRelatedToPreviousError (loc.ToString (), symbol);
672                 }
673
674                 static public void SymbolRelatedToPreviousError (MemberInfo mi)
675                 {
676                         if (reporting_disabled)
677                                 return;
678
679                         Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType);
680                         if (TypeManager.IsDelegateType (dt)) {
681                                 SymbolRelatedToPreviousError (dt);
682                                 return;
683                         }                       
684                         
685                         DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt);
686                         if (temp_ds == null) {
687                                 SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi));
688                         } else {
689                                 MethodBase mb = mi as MethodBase;
690                                 if (mb != null) {
691                                         mb = TypeManager.DropGenericMethodArguments (mb);
692                                         IMethodData md = TypeManager.GetMethod (mb);
693                                         if (md != null)
694                                                 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
695
696                                         return;
697                                 }
698
699                                 // FIXME: Completely wrong, it has to use FindMembers
700                                 MemberCore mc = temp_ds.GetDefinition (mi.Name);
701                                 if (mc != null)
702                                         SymbolRelatedToPreviousError (mc);
703                         }
704                 }
705
706                 static public void SymbolRelatedToPreviousError (MemberCore mc)
707                 {
708                         SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
709                 }
710
711                 static public void SymbolRelatedToPreviousError (Type type)
712                 {
713                         if (reporting_disabled)
714                                 return;
715
716                         type = TypeManager.DropGenericTypeArguments (type);
717
718                         if (TypeManager.IsGenericParameter (type)) {
719                                 TypeParameter tp = TypeManager.LookupTypeParameter (type);
720                                 if (tp != null) {
721                                         SymbolRelatedToPreviousError (tp.Location, "");
722                                         return;
723                                 }
724                         }
725
726                         if (type is TypeBuilder) {
727                                 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
728                                 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
729                         } else if (TypeManager.HasElementType (type)) {
730                                 SymbolRelatedToPreviousError (TypeManager.GetElementType (type));
731                         } else {
732                                 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
733                         }
734                 }
735
736                 static void SymbolRelatedToPreviousError (string loc, string symbol)
737                 {
738                         string msg = String.Format ("{0} (Location of the symbol related to previous ", loc);
739                         if (extra_information.Contains (msg))
740                                 return;
741
742                         extra_information.Add (msg);
743                 }
744
745                 public static void AddWarningAsError (string warningId)
746                 {
747                         int id;
748                         try {
749                                 id = int.Parse (warningId);
750                         } catch {
751                                 id = -1;
752                         }
753
754                         if (!CheckWarningCode (id, warningId, Location.Null))
755                                 return;
756
757                         if (warnings_as_error == null)
758                                 warnings_as_error = new ArrayList ();
759                         
760                         warnings_as_error.Add (id);
761                 }
762
763                 public static void RemoveWarningAsError (string warningId)
764                 {
765                         int id;
766                         try {
767                                 id = int.Parse (warningId);
768                         } catch {
769                                 id = -1;
770                         }
771
772                         if (!CheckWarningCode (id, warningId, Location.Null))
773                                 return;
774
775                         if (warnings_only == null)
776                                 warnings_only = new ArrayList ();
777
778                         warnings_only.Add (id);
779                 }
780
781                 public static bool CheckWarningCode (int code, Location loc)
782                 {
783                         return CheckWarningCode (code, code.ToString (), loc);
784                 }
785
786                 public static bool CheckWarningCode (int code, string scode, Location loc)
787                 {
788                         if (IsValidWarning (code))
789                                 return true;
790
791                         Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", scode);
792                         return false;
793                 }
794
795                 public static void ExtraInformation (Location loc, string msg)
796                 {
797                         extra_information.Add (String.Format ("{0} {1}", loc, msg));
798                 }
799
800                 public static WarningRegions RegisterWarningRegion (Location location)
801                 {
802                         if (warning_regions_table == null)
803                                 warning_regions_table = new Hashtable ();
804
805                         WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
806                         if (regions == null) {
807                                 regions = new WarningRegions ();
808                                 warning_regions_table.Add (location.Name, regions);
809                         }
810                         return regions;
811                 }
812
813                 static public void Warning (int code, int level, Location loc, string message)
814                 {
815                         WarningMessage w = new WarningMessage (code, level, loc, message, extra_information);
816                         extra_information.Clear ();
817                         w.Print ();
818                 }
819
820                 static public void Warning (int code, int level, Location loc, string format, string arg)
821                 {
822                         WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg), extra_information);
823                         extra_information.Clear ();
824                         w.Print ();
825                 }
826
827                 static public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
828                 {
829                         WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg1, arg2), extra_information);
830                         extra_information.Clear ();
831                         w.Print ();
832                 }
833
834                 static public void Warning (int code, int level, Location loc, string format, params object[] args)
835                 {
836                         WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, args), extra_information);
837                         extra_information.Clear ();
838                         w.Print ();
839                 }
840
841                 static public void Warning (int code, int level, string message)
842                 {
843                         Warning (code, level, Location.Null, message);
844                 }
845
846                 static public void Warning (int code, int level, string format, string arg)
847                 {
848                         Warning (code, level, Location.Null, format, arg);
849                 }
850
851                 static public void Warning (int code, int level, string format, string arg1, string arg2)
852                 {
853                         Warning (code, level, Location.Null, format, arg1, arg2);
854                 }
855
856                 static public void Warning (int code, int level, string format, params string[] args)
857                 {
858                         Warning (code, level, Location.Null, String.Format (format, args));
859                 }
860
861                 static public void Error (int code, Location loc, string error)
862                 {
863                         new ErrorMessage (code, loc, error, extra_information).Print ();
864                         extra_information.Clear ();
865                 }
866
867                 static public void Error (int code, Location loc, string format, string arg)
868                 {
869                         new ErrorMessage (code, loc, String.Format (format, arg), extra_information).Print ();
870                         extra_information.Clear ();
871                 }
872
873                 static public void Error (int code, Location loc, string format, string arg1, string arg2)
874                 {
875                         new ErrorMessage (code, loc, String.Format (format, arg1, arg2), extra_information).Print ();
876                         extra_information.Clear ();
877                 }
878
879                 static public void Error (int code, Location loc, string format, params object[] args)
880                 {
881                         Error (code, loc, String.Format (format, args));
882                 }
883
884                 static public void Error (int code, string error)
885                 {
886                         Error (code, Location.Null, error);
887                 }
888
889                 static public void Error (int code, string format, string arg)
890                 {
891                         Error (code, Location.Null, format, arg);
892                 }
893
894                 static public void Error (int code, string format, string arg1, string arg2)
895                 {
896                         Error (code, Location.Null, format, arg1, arg2);
897                 }
898
899                 static public void Error (int code, string format, params string[] args)
900                 {
901                         Error (code, Location.Null, String.Format (format, args));
902                 }
903
904                 static public void SetIgnoreWarning (int code)
905                 {
906                         if (warning_ignore_table == null)
907                                 warning_ignore_table = new Hashtable ();
908
909                         warning_ignore_table [code] = true;
910                 }
911                 
912                 static public int ExpectedError {
913                         set {
914                                 expected_error = value;
915                         }
916                         get {
917                                 return expected_error;
918                         }
919                 }
920                 
921                 public static int WarningLevel {
922                         get {
923                                 return warning_level;
924                         }
925                         set {
926                                 warning_level = value;
927                         }
928                 }
929
930                 public static int DebugFlags = 0;
931
932                 [Conditional ("MCS_DEBUG")]
933                 static public void Debug (string message, params object[] args)
934                 {
935                         Debug (4, message, args);
936                 }
937                         
938                 [Conditional ("MCS_DEBUG")]
939                 static public void Debug (int category, string message, params object[] args)
940                 {
941                         if ((category & DebugFlags) == 0)
942                                 return;
943
944                         StringBuilder sb = new StringBuilder (message);
945
946                         if ((args != null) && (args.Length > 0)) {
947                                 sb.Append (": ");
948
949                                 bool first = true;
950                                 foreach (object arg in args) {
951                                         if (first)
952                                                 first = false;
953                                         else
954                                                 sb.Append (", ");
955                                         if (arg == null)
956                                                 sb.Append ("null");
957                                         else if (arg is ICollection)
958                                                 sb.Append (PrintCollection ((ICollection) arg));
959                                         else
960                                                 sb.Append (arg);
961                                 }
962                         }
963
964                         Console.WriteLine (sb.ToString ());
965                 }
966
967                 static public string PrintCollection (ICollection collection)
968                 {
969                         StringBuilder sb = new StringBuilder ();
970
971                         sb.Append (collection.GetType ());
972                         sb.Append ("(");
973
974                         bool first = true;
975                         foreach (object o in collection) {
976                                 if (first)
977                                         first = false;
978                                 else
979                                         sb.Append (", ");
980                                 sb.Append (o);
981                         }
982
983                         sb.Append (")");
984                         return sb.ToString ();
985                 }
986         }
987
988         public enum TimerType {
989                 FindMembers     = 0,
990                 TcFindMembers   = 1,
991                 MemberLookup    = 2,
992                 CachedLookup    = 3,
993                 CacheInit       = 4,
994                 MiscTimer       = 5,
995                 CountTimers     = 6
996         }
997
998         public enum CounterType {
999                 FindMembers     = 0,
1000                 MemberCache     = 1,
1001                 MiscCounter     = 2,
1002                 CountCounters   = 3
1003         }
1004
1005         public class Timer
1006         {
1007                 static DateTime[] timer_start;
1008                 static TimeSpan[] timers;
1009                 static long[] timer_counters;
1010                 static long[] counters;
1011
1012                 static Timer ()
1013                 {
1014                         timer_start = new DateTime [(int) TimerType.CountTimers];
1015                         timers = new TimeSpan [(int) TimerType.CountTimers];
1016                         timer_counters = new long [(int) TimerType.CountTimers];
1017                         counters = new long [(int) CounterType.CountCounters];
1018
1019                         for (int i = 0; i < (int) TimerType.CountTimers; i++) {
1020                                 timer_start [i] = DateTime.Now;
1021                                 timers [i] = TimeSpan.Zero;
1022                         }
1023                 }
1024
1025                 [Conditional("TIMER")]
1026                 static public void IncrementCounter (CounterType which)
1027                 {
1028                         ++counters [(int) which];
1029                 }
1030
1031                 [Conditional("TIMER")]
1032                 static public void StartTimer (TimerType which)
1033                 {
1034                         timer_start [(int) which] = DateTime.Now;
1035                 }
1036
1037                 [Conditional("TIMER")]
1038                 static public void StopTimer (TimerType which)
1039                 {
1040                         timers [(int) which] += DateTime.Now - timer_start [(int) which];
1041                         ++timer_counters [(int) which];
1042                 }
1043
1044                 [Conditional("TIMER")]
1045                 static public void ShowTimers ()
1046                 {
1047                         ShowTimer (TimerType.FindMembers, "- FindMembers timer");
1048                         ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
1049                         ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
1050                         ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
1051                         ShowTimer (TimerType.CacheInit, "- Cache init");
1052                         ShowTimer (TimerType.MiscTimer, "- Misc timer");
1053
1054                         ShowCounter (CounterType.FindMembers, "- Find members");
1055                         ShowCounter (CounterType.MemberCache, "- Member cache");
1056                         ShowCounter (CounterType.MiscCounter, "- Misc counter");
1057                 }
1058
1059                 static public void ShowCounter (CounterType which, string msg)
1060                 {
1061                         Console.WriteLine ("{0} {1}", counters [(int) which], msg);
1062                 }
1063
1064                 static public void ShowTimer (TimerType which, string msg)
1065                 {
1066                         Console.WriteLine (
1067                                 "[{0:00}:{1:000}] {2} (used {3} times)",
1068                                 (int) timers [(int) which].TotalSeconds,
1069                                 timers [(int) which].Milliseconds, msg,
1070                                 timer_counters [(int) which]);
1071                 }
1072         }
1073
1074         public class InternalErrorException : Exception {
1075                 public InternalErrorException (MemberCore mc, Exception e)
1076                         : base (mc.Location + " " + mc.GetSignatureForError (), e)
1077                 {
1078                 }
1079
1080                 public InternalErrorException ()
1081                         : base ("Internal error")
1082                 {
1083                 }
1084
1085                 public InternalErrorException (string message)
1086                         : base (message)
1087                 {
1088                 }
1089
1090                 public InternalErrorException (string message, params object[] args)
1091                         : base (String.Format (message, args))
1092                 { }
1093                 
1094                 public InternalErrorException (Exception e, Location loc)
1095                         : base (loc.ToString (), e)
1096                 {
1097                 }
1098         }
1099
1100         /// <summary>
1101         /// Handles #pragma warning
1102         /// </summary>
1103         public class WarningRegions {
1104
1105                 abstract class PragmaCmd
1106                 {
1107                         public int Line;
1108
1109                         protected PragmaCmd (int line)
1110                         {
1111                                 Line = line;
1112                         }
1113
1114                         public abstract bool IsEnabled (int code, bool previous);
1115                 }
1116                 
1117                 class Disable : PragmaCmd
1118                 {
1119                         int code;
1120                         public Disable (int line, int code)
1121                                 : base (line)
1122                         {
1123                                 this.code = code;
1124                         }
1125
1126                         public override bool IsEnabled (int code, bool previous)
1127                         {
1128                                 return this.code == code ? false : previous;
1129                         }
1130                 }
1131
1132                 class DisableAll : PragmaCmd
1133                 {
1134                         public DisableAll (int line)
1135                                 : base (line) {}
1136
1137                         public override bool IsEnabled(int code, bool previous)
1138                         {
1139                                 return false;
1140                         }
1141                 }
1142
1143                 class Enable : PragmaCmd
1144                 {
1145                         int code;
1146                         public Enable (int line, int code)
1147                                 : base (line)
1148                         {
1149                                 this.code = code;
1150                         }
1151
1152                         public override bool IsEnabled(int code, bool previous)
1153                         {
1154                                 return this.code == code ? true : previous;
1155                         }
1156                 }
1157
1158                 class EnableAll : PragmaCmd
1159                 {
1160                         public EnableAll (int line)
1161                                 : base (line) {}
1162
1163                         public override bool IsEnabled(int code, bool previous)
1164                         {
1165                                 return true;
1166                         }
1167                 }
1168
1169
1170                 ArrayList regions = new ArrayList ();
1171
1172                 public void WarningDisable (int line)
1173                 {
1174                         regions.Add (new DisableAll (line));
1175                 }
1176
1177                 public void WarningDisable (Location location, int code)
1178                 {
1179                         if (Report.CheckWarningCode (code, location))
1180                                 regions.Add (new Disable (location.Row, code));
1181                 }
1182
1183                 public void WarningEnable (int line)
1184                 {
1185                         regions.Add (new EnableAll (line));
1186                 }
1187
1188                 public void WarningEnable (Location location, int code)
1189                 {
1190                         if (Report.CheckWarningCode (code, location))
1191                                 regions.Add (new Enable (location.Row, code));
1192                 }
1193
1194                 public bool IsWarningEnabled (int code, int src_line)
1195                 {
1196                         bool result = true;
1197                         foreach (PragmaCmd pragma in regions) {
1198                                 if (src_line < pragma.Line)
1199                                         break;
1200
1201                                 result = pragma.IsEnabled (code, result);
1202                         }
1203                         return result;
1204                 }
1205         }
1206 }