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