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