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