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