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