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