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