Normalize line endings.
[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.Generic;
14 using System.Diagnostics;
15 using System.Reflection;
16 using System.Reflection.Emit;
17
18 namespace Mono.CSharp {
19
20         //
21         // Errors and warnings manager
22         //
23         public class Report
24         {
25                 /// <summary>  
26                 ///   Whether warnings should be considered errors
27                 /// </summary>
28                 public bool WarningsAreErrors;
29                 List<int> warnings_as_error;
30                 List<int> warnings_only;
31
32                 public static int DebugFlags = 0;
33
34                 //
35                 // Keeps track of the warnings that we are ignoring
36                 //
37                 public Dictionary<int, bool> warning_ignore_table;
38
39                 Dictionary<string, WarningRegions> warning_regions_table;
40
41                 int warning_level;
42
43                 ReportPrinter printer;
44
45                 int reporting_disabled;
46                 
47                 /// <summary>
48                 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
49                 /// </summary>
50                 List<string> extra_information = new List<string> ();
51
52                 // 
53                 // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
54                 //
55                 public static readonly int[] AllWarnings = new int[] {
56                         28, 67, 78,
57                         105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
58                         219, 251, 252, 253, 278, 282,
59                         402, 414, 419, 420, 429, 436, 440, 458, 464, 465, 467, 469, 472,
60                         612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675, 693,
61                         809,
62                         1030, 1058, 1066,
63                         1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
64                         1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692,
65                         1700, 1717, 1718, 1720,
66                         1901,
67                         2002, 2023, 2029,
68                         3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009,
69                         3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019,
70                         3021, 3022, 3023, 3024, 3026, 3027
71                 };
72
73                 static Report ()
74                 {
75                         // Just to be sure that binary search is working
76                         Array.Sort (AllWarnings);
77                 }
78
79                 public Report (ReportPrinter printer)
80                 {
81                         if (printer == null)
82                                 throw new ArgumentNullException ("printer");
83
84                         this.printer = printer;
85                         warning_level = 4;
86                 }
87
88                 public void DisableReporting ()
89                 {
90                         ++reporting_disabled;
91                 }
92
93                 public void EnableReporting ()
94                 {
95                         --reporting_disabled;
96                 }
97
98                 public void FeatureIsNotAvailable (Location loc, string feature)
99                 {
100                         string version;
101                         switch (RootContext.Version) {
102                         case LanguageVersion.ISO_1:
103                                 version = "1.0";
104                                 break;
105                         case LanguageVersion.ISO_2:
106                                 version = "2.0";
107                                 break;
108                         case LanguageVersion.V_3:
109                                 version = "3.0";
110                                 break;
111                         default:
112                                 throw new InternalErrorException ("Invalid feature version", RootContext.Version);
113                         }
114
115                         Error (1644, loc,
116                                 "Feature `{0}' cannot be used because it is not part of the C# {1} language specification",
117                                       feature, version);
118                 }
119
120                 public void FeatureIsNotSupported (Location loc, string feature)
121                 {
122                         Error (1644, loc,
123                                 "Feature `{0}' is not supported in Mono mcs1 compiler. Consider using the `gmcs' compiler instead",
124                                 feature);
125                 }
126                 
127                 static bool IsValidWarning (int code)
128                 {       
129                         return Array.BinarySearch (AllWarnings, code) >= 0;
130                 }
131
132                 bool IsWarningEnabled (int code, int level, Location loc)
133                 {
134                         if (WarningLevel < level)
135                                 return false;
136
137                         if (warning_ignore_table != null) {
138                                 if (warning_ignore_table.ContainsKey (code)) {
139                                         return false;
140                                 }
141                         }
142
143                         if (warning_regions_table == null || loc.IsNull)
144                                 return true;
145
146                         WarningRegions regions;
147                         if (!warning_regions_table.TryGetValue (loc.Name, out regions))
148                                 return true;
149
150                         return regions.IsWarningEnabled (code, loc.Row);
151                 }
152
153                 bool IsWarningAsError (int code)
154                 {
155                         bool is_error = WarningsAreErrors;
156
157                         // Check specific list
158                         if (warnings_as_error != null)
159                                 is_error |= warnings_as_error.Contains (code);
160
161                         // Ignore excluded warnings
162                         if (warnings_only != null && warnings_only.Contains (code))
163                                 is_error = false;
164
165                         return is_error;
166                 }
167                         
168                 public void RuntimeMissingSupport (Location loc, string feature) 
169                 {
170                         Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
171                 }
172
173                 /// <summary>
174                 /// In most error cases is very useful to have information about symbol that caused the error.
175                 /// Call this method before you call Report.Error when it makes sense.
176                 /// </summary>
177                 public void SymbolRelatedToPreviousError (Location loc, string symbol)
178                 {
179                         SymbolRelatedToPreviousError (loc.ToString (), symbol);
180                 }
181
182                 public void SymbolRelatedToPreviousError (MemberSpec ms)
183                 {
184                         if (reporting_disabled > 0 || !printer.HasRelatedSymbolSupport)
185                                 return;
186
187                         var mc = ms.MemberDefinition as MemberCore;
188                         while (ms is ElementTypeSpec) {
189                                 ms = ((ElementTypeSpec) ms).Element;
190                                 mc = ms.MemberDefinition as MemberCore;
191                         }
192
193                         if (mc != null) {
194                                 SymbolRelatedToPreviousError (mc);
195                         } else {
196                                 SymbolRelatedToPreviousError (ms.MemberDefinition.Assembly.Location, "");
197                         }
198                 }
199
200                 public void SymbolRelatedToPreviousError (MemberCore mc)
201                 {
202                         SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
203                 }
204
205                 void SymbolRelatedToPreviousError (string loc, string symbol)
206                 {
207                         string msg = String.Format ("{0} (Location of the symbol related to previous ", loc);
208                         if (extra_information.Contains (msg))
209                                 return;
210
211                         extra_information.Add (msg);
212                 }
213
214                 public void AddWarningAsError (string warningId)
215                 {
216                         int id;
217                         try {
218                                 id = int.Parse (warningId);
219                         } catch {
220                                 id = -1;
221                         }
222
223                         if (!CheckWarningCode (id, warningId, Location.Null))
224                                 return;
225
226                         if (warnings_as_error == null)
227                                 warnings_as_error = new List<int> ();
228                         
229                         warnings_as_error.Add (id);
230                 }
231
232                 public void RemoveWarningAsError (string warningId)
233                 {
234                         int id;
235                         try {
236                                 id = int.Parse (warningId);
237                         } catch {
238                                 id = -1;
239                         }
240
241                         if (!CheckWarningCode (id, warningId, Location.Null))
242                                 return;
243
244                         if (warnings_only == null)
245                                 warnings_only = new List<int> ();
246
247                         warnings_only.Add (id);
248                 }
249
250                 public bool CheckWarningCode (int code, Location loc)
251                 {
252                         return CheckWarningCode (code, code.ToString (), loc);
253                 }
254
255                 public bool CheckWarningCode (int code, string scode, Location loc)
256                 {
257                         if (IsValidWarning (code))
258                                 return true;
259
260                         Warning (1691, 1, loc, "`{0}' is not a valid warning number", scode);
261                         return false;
262                 }
263
264                 public void ExtraInformation (Location loc, string msg)
265                 {
266                         extra_information.Add (String.Format ("{0} {1}", loc, msg));
267                 }
268
269                 public WarningRegions RegisterWarningRegion (Location location)
270                 {
271                         WarningRegions regions;
272                         if (warning_regions_table == null) {
273                                 regions = null;
274                                 warning_regions_table = new Dictionary<string, WarningRegions> ();
275                         } else {
276                                 warning_regions_table.TryGetValue (location.Name, out regions);
277                         }
278
279                         if (regions == null) {
280                                 regions = new WarningRegions ();
281                                 warning_regions_table.Add (location.Name, regions);
282                         }
283
284                         return regions;
285                 }
286
287                 public void Warning (int code, int level, Location loc, string message)
288                 {
289                         if (reporting_disabled > 0)
290                                 return;
291
292                         if (!IsWarningEnabled (code, level, loc))
293                                 return;
294
295                         AbstractMessage msg;
296                         if (IsWarningAsError (code))
297                                 msg = new ErrorMessage (code, loc, message, extra_information);
298                         else
299                                 msg = new WarningMessage (code, loc, message, extra_information);
300
301                         extra_information.Clear ();
302                         printer.Print (msg);
303                 }
304
305                 public void Warning (int code, int level, Location loc, string format, string arg)
306                 {
307                         Warning (code, level, loc, String.Format (format, arg));
308                 }
309
310                 public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
311                 {
312                         Warning (code, level, loc, String.Format (format, arg1, arg2));
313                 }
314
315                 public void Warning (int code, int level, Location loc, string format, params object[] args)
316                 {
317                         Warning (code, level, loc, String.Format (format, args));
318                 }
319
320                 public void Warning (int code, int level, string message)
321                 {
322                         Warning (code, level, Location.Null, message);
323                 }
324
325                 public void Warning (int code, int level, string format, string arg)
326                 {
327                         Warning (code, level, Location.Null, format, arg);
328                 }
329
330                 public void Warning (int code, int level, string format, string arg1, string arg2)
331                 {
332                         Warning (code, level, Location.Null, format, arg1, arg2);
333                 }
334
335                 public void Warning (int code, int level, string format, params string[] args)
336                 {
337                         Warning (code, level, Location.Null, String.Format (format, args));
338                 }
339
340                 //
341                 // Warnings encountered so far
342                 //
343                 public int Warnings {
344                         get { return printer.WarningsCount; }
345                 }
346
347                 public void Error (int code, Location loc, string error)
348                 {
349                         if (reporting_disabled > 0)
350                                 return;
351
352                         ErrorMessage msg = new ErrorMessage (code, loc, error, extra_information);
353                         extra_information.Clear ();
354
355                         printer.Print (msg);
356                 }
357
358                 public void Error (int code, Location loc, string format, string arg)
359                 {
360                         Error (code, loc, String.Format (format, arg));
361                 }
362
363                 public void Error (int code, Location loc, string format, string arg1, string arg2)
364                 {
365                         Error (code, loc, String.Format (format, arg1, arg2));
366                 }
367
368                 public void Error (int code, Location loc, string format, params string[] args)
369                 {
370                         Error (code, loc, String.Format (format, args));
371                 }
372
373                 public void Error (int code, string error)
374                 {
375                         Error (code, Location.Null, error);
376                 }
377
378                 public void Error (int code, string format, string arg)
379                 {
380                         Error (code, Location.Null, format, arg);
381                 }
382
383                 public void Error (int code, string format, string arg1, string arg2)
384                 {
385                         Error (code, Location.Null, format, arg1, arg2);
386                 }
387
388                 public void Error (int code, string format, params string[] args)
389                 {
390                         Error (code, Location.Null, String.Format (format, args));
391                 }
392
393                 //
394                 // Errors encountered so far
395                 //
396                 public int Errors {
397                         get { return printer.ErrorsCount; }
398                 }
399
400                 public bool IsDisabled {
401                         get {
402                                 return reporting_disabled > 0;
403                         }
404                 }
405
406                 public ReportPrinter Printer {
407                         get { return printer; }
408                 }
409
410                 public void SetIgnoreWarning (int code)
411                 {
412                         if (warning_ignore_table == null)
413                                 warning_ignore_table = new Dictionary<int, bool> ();
414
415                         warning_ignore_table [code] = true;
416                 }
417
418                 public ReportPrinter SetPrinter (ReportPrinter printer)
419                 {
420                         ReportPrinter old = this.printer;
421                         this.printer = printer;
422                         return old;
423                 }
424
425                 public int WarningLevel {
426                         get {
427                                 return warning_level;
428                         }
429                         set {
430                                 warning_level = value;
431                         }
432                 }
433
434                 [Conditional ("MCS_DEBUG")]
435                 static public void Debug (string message, params object[] args)
436                 {
437                         Debug (4, message, args);
438                 }
439                         
440                 [Conditional ("MCS_DEBUG")]
441                 static public void Debug (int category, string message, params object[] args)
442                 {
443                         if ((category & DebugFlags) == 0)
444                                 return;
445
446                         StringBuilder sb = new StringBuilder (message);
447
448                         if ((args != null) && (args.Length > 0)) {
449                                 sb.Append (": ");
450
451                                 bool first = true;
452                                 foreach (object arg in args) {
453                                         if (first)
454                                                 first = false;
455                                         else
456                                                 sb.Append (", ");
457                                         if (arg == null)
458                                                 sb.Append ("null");
459 //                                      else if (arg is ICollection)
460 //                                              sb.Append (PrintCollection ((ICollection) arg));
461                                         else
462                                                 sb.Append (arg);
463                                 }
464                         }
465
466                         Console.WriteLine (sb.ToString ());
467                 }
468 /*
469                 static public string PrintCollection (ICollection collection)
470                 {
471                         StringBuilder sb = new StringBuilder ();
472
473                         sb.Append (collection.GetType ());
474                         sb.Append ("(");
475
476                         bool first = true;
477                         foreach (object o in collection) {
478                                 if (first)
479                                         first = false;
480                                 else
481                                         sb.Append (", ");
482                                 sb.Append (o);
483                         }
484
485                         sb.Append (")");
486                         return sb.ToString ();
487                 }
488 */ 
489         }
490
491         public abstract class AbstractMessage
492         {
493                 readonly string[] extra_info;
494                 protected readonly int code;
495                 protected readonly Location location;
496                 readonly string message;
497
498                 protected AbstractMessage (int code, Location loc, string msg, List<string> extraInfo)
499                 {
500                         this.code = code;
501                         if (code < 0)
502                                 this.code = 8000 - code;
503
504                         this.location = loc;
505                         this.message = msg;
506                         if (extraInfo.Count != 0) {
507                                 this.extra_info = extraInfo.ToArray ();
508                         }
509                 }
510
511                 protected AbstractMessage (AbstractMessage aMsg)
512                 {
513                         this.code = aMsg.code;
514                         this.location = aMsg.location;
515                         this.message = aMsg.message;
516                         this.extra_info = aMsg.extra_info;
517                 }
518
519                 public int Code {
520                         get { return code; }
521                 }
522
523                 public override bool Equals (object obj)
524                 {
525                         AbstractMessage msg = obj as AbstractMessage;
526                         if (msg == null)
527                                 return false;
528
529                         return code == msg.code && location.Equals (msg.location) && message == msg.message;
530                 }
531
532                 public override int GetHashCode ()
533                 {
534                         return code.GetHashCode ();
535                 }
536
537                 public abstract bool IsWarning { get; }
538
539                 public Location Location {
540                         get { return location; }
541                 }
542
543                 public abstract string MessageType { get; }
544
545                 public string[] RelatedSymbols {
546                         get { return extra_info; }
547                 }
548
549                 public string Text {
550                         get { return message; }
551                 }
552         }
553
554         sealed class WarningMessage : AbstractMessage
555         {
556                 public WarningMessage (int code, Location loc, string message, List<string> extra_info)
557                         : base (code, loc, message, extra_info)
558                 {
559                 }
560
561                 public override bool IsWarning {
562                         get { return true; }
563                 }
564
565                 public override string MessageType {
566                         get {
567                                 return "warning";
568                         }
569                 }
570         }
571
572         sealed class ErrorMessage : AbstractMessage
573         {
574                 public ErrorMessage (int code, Location loc, string message, List<string> extraInfo)
575                         : base (code, loc, message, extraInfo)
576                 {
577                 }
578
579                 public ErrorMessage (AbstractMessage aMsg)
580                         : base (aMsg)
581                 {
582                 }
583
584                 public override bool IsWarning {
585                         get { return false; }
586                 }
587
588                 public override string MessageType {
589                         get {
590                                 return "error";
591                         }
592                 }
593         }
594
595         //
596         // Generic base for any message writer
597         //
598         public abstract class ReportPrinter {
599                 /// <summary>  
600                 ///   Whether to dump a stack trace on errors. 
601                 /// </summary>
602                 public bool Stacktrace;
603                 
604                 int warnings, errors;
605
606                 public int WarningsCount {
607                         get { return warnings; }
608                 }
609                 
610                 public int ErrorsCount {
611                         get { return errors; }
612                 }
613
614                 protected virtual string FormatText (string txt)
615                 {
616                         return txt;
617                 }
618
619                 //
620                 // When (symbols related to previous ...) can be used
621                 //
622                 public virtual bool HasRelatedSymbolSupport {
623                         get { return true; }
624                 }
625
626                 public virtual void Print (AbstractMessage msg)
627                 {
628                         if (msg.IsWarning)
629                                 ++warnings;
630                         else
631                                 ++errors;
632                 }
633
634                 protected void Print (AbstractMessage msg, TextWriter output)
635                 {
636                         StringBuilder txt = new StringBuilder ();
637                         if (!msg.Location.IsNull) {
638                                 txt.Append (msg.Location.ToString ());
639                                 txt.Append (" ");
640                         }
641
642                         txt.AppendFormat ("{0} CS{1:0000}: {2}", msg.MessageType, msg.Code, msg.Text);
643
644                         if (!msg.IsWarning)
645                                 output.WriteLine (FormatText (txt.ToString ()));
646                         else
647                                 output.WriteLine (txt.ToString ());
648
649                         if (msg.RelatedSymbols != null) {
650                                 foreach (string s in msg.RelatedSymbols)
651                                         output.WriteLine (s + msg.MessageType + ")");
652                         }
653                 }
654         }
655
656         //
657         // Default message recorder, it uses two types of message groups.
658         // Common messages: messages reported in all sessions.
659         // Merged messages: union of all messages in all sessions. 
660         //
661         // Used by the Lambda expressions to compile the code with various
662         // parameter values, or by attribute resolver
663         //
664         class SessionReportPrinter : ReportPrinter
665         {
666                 List<AbstractMessage> session_messages;
667                 //
668                 // A collection of exactly same messages reported in all sessions
669                 //
670                 List<AbstractMessage> common_messages;
671
672                 //
673                 // A collection of unique messages reported in all sessions
674                 //
675                 List<AbstractMessage> merged_messages;
676
677                 public override void Print (AbstractMessage msg)
678                 {
679                         //
680                         // This line is useful when debugging recorded messages
681                         //
682                         // Console.WriteLine ("RECORDING: {0}", msg.ToString ());
683
684                         if (session_messages == null)
685                                 session_messages = new List<AbstractMessage> ();
686
687                         session_messages.Add (msg);
688
689                         base.Print (msg);
690                 }
691
692                 public void EndSession ()
693                 {
694                         if (session_messages == null)
695                                 return;
696
697                         //
698                         // Handles the first session
699                         //
700                         if (common_messages == null) {
701                                 common_messages = new List<AbstractMessage> (session_messages);
702                                 merged_messages = session_messages;
703                                 session_messages = null;
704                                 return;
705                         }
706
707                         //
708                         // Store common messages if any
709                         //
710                         for (int i = 0; i < common_messages.Count; ++i) {
711                                 AbstractMessage cmsg = common_messages[i];
712                                 bool common_msg_found = false;
713                                 foreach (AbstractMessage msg in session_messages) {
714                                         if (cmsg.Equals (msg)) {
715                                                 common_msg_found = true;
716                                                 break;
717                                         }
718                                 }
719
720                                 if (!common_msg_found)
721                                         common_messages.RemoveAt (i);
722                         }
723
724                         //
725                         // Merge session and previous messages
726                         //
727                         for (int i = 0; i < session_messages.Count; ++i) {
728                                 AbstractMessage msg = session_messages[i];
729                                 bool msg_found = false;
730                                 for (int ii = 0; ii < merged_messages.Count; ++ii) {
731                                         if (msg.Equals (merged_messages[ii])) {
732                                                 msg_found = true;
733                                                 break;
734                                         }
735                                 }
736
737                                 if (!msg_found)
738                                         merged_messages.Add (msg);
739                         }
740                 }
741
742                 public bool IsEmpty {
743                         get {
744                                 return merged_messages == null && common_messages == null;
745                         }
746                 }
747
748                 //
749                 // Prints collected messages, common messages have a priority
750                 //
751                 public bool Merge (ReportPrinter dest)
752                 {
753                         var messages_to_print = merged_messages;
754                         if (common_messages != null && common_messages.Count > 0) {
755                                 messages_to_print = common_messages;
756                         }
757
758                         if (messages_to_print == null)
759                                 return false;
760
761                         foreach (AbstractMessage msg in messages_to_print)
762                                 dest.Print (msg);
763
764                         return true;
765                 }
766         }
767
768         class StreamReportPrinter : ReportPrinter
769         {
770                 readonly TextWriter writer;
771
772                 public StreamReportPrinter (TextWriter writer)
773                 {
774                         this.writer = writer;
775                 }
776
777                 public override void Print (AbstractMessage msg)
778                 {
779                         Print (msg, writer);
780                         base.Print (msg);
781                 }
782         }
783
784         class ConsoleReportPrinter : StreamReportPrinter
785         {
786                 static readonly string prefix, postfix;
787
788                 static ConsoleReportPrinter ()
789                 {
790                         string term = Environment.GetEnvironmentVariable ("TERM");
791                         bool xterm_colors = false;
792                         
793                         switch (term){
794                         case "xterm":
795                         case "rxvt":
796                         case "rxvt-unicode": 
797                                 if (Environment.GetEnvironmentVariable ("COLORTERM") != null){
798                                         xterm_colors = true;
799                                 }
800                                 break;
801
802                         case "xterm-color":
803                                 xterm_colors = true;
804                                 break;
805                         }
806                         if (!xterm_colors)
807                                 return;
808
809                         if (!(UnixUtils.isatty (1) && UnixUtils.isatty (2)))
810                                 return;
811                         
812                         string config = Environment.GetEnvironmentVariable ("MCS_COLORS");
813                         if (config == null){
814                                 config = "errors=red";
815                                 //config = "brightwhite,red";
816                         }
817
818                         if (config == "disable")
819                                 return;
820
821                         if (!config.StartsWith ("errors="))
822                                 return;
823
824                         config = config.Substring (7);
825                         
826                         int p = config.IndexOf (",");
827                         if (p == -1)
828                                 prefix = GetForeground (config);
829                         else
830                                 prefix = GetBackground (config.Substring (p+1)) + GetForeground (config.Substring (0, p));
831                         postfix = "\x001b[0m";
832                 }
833
834                 public ConsoleReportPrinter ()
835                         : base (Console.Error)
836                 {
837                 }
838
839                 public ConsoleReportPrinter (TextWriter writer)
840                         : base (writer)
841                 {
842                 }
843
844                 public int Fatal { get; set; }
845
846                 static int NameToCode (string s)
847                 {
848                         switch (s) {
849                         case "black":
850                                 return 0;
851                         case "red":
852                                 return 1;
853                         case "green":
854                                 return 2;
855                         case "yellow":
856                                 return 3;
857                         case "blue":
858                                 return 4;
859                         case "magenta":
860                                 return 5;
861                         case "cyan":
862                                 return 6;
863                         case "grey":
864                         case "white":
865                                 return 7;
866                         }
867                         return 7;
868                 }
869
870                 //
871                 // maps a color name to its xterm color code
872                 //
873                 static string GetForeground (string s)
874                 {
875                         string highcode;
876
877                         if (s.StartsWith ("bright")) {
878                                 highcode = "1;";
879                                 s = s.Substring (6);
880                         } else
881                                 highcode = "";
882
883                         return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m";
884                 }
885
886                 static string GetBackground (string s)
887                 {
888                         return "\x001b[" + (40 + NameToCode (s)).ToString () + "m";
889                 }
890
891                 protected override string FormatText (string txt)
892                 {
893                         if (prefix != null)
894                                 return prefix + txt + postfix;
895
896                         return txt;
897                 }
898
899                 static string FriendlyStackTrace (StackTrace t)
900                 {               
901                         StringBuilder sb = new StringBuilder ();
902                         
903                         bool foundUserCode = false;
904                         
905                         for (int i = 0; i < t.FrameCount; i++) {
906                                 StackFrame f = t.GetFrame (i);
907                                 MethodBase mb = f.GetMethod ();
908                                 
909                                 if (!foundUserCode && mb.ReflectedType == typeof (Report))
910                                         continue;
911                                 
912                                 foundUserCode = true;
913                                 
914                                 sb.Append ("\tin ");
915                                 
916                                 if (f.GetFileLineNumber () > 0)
917                                         sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
918                                 
919                                 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
920                                 
921                                 bool first = true;
922                                 foreach (ParameterInfo pi in mb.GetParameters ()) {
923                                         if (!first)
924                                                 sb.Append (", ");
925                                         first = false;
926
927                                         sb.Append (pi.ParameterType.FullName);
928                                 }
929                                 sb.Append (")\n");
930                         }
931         
932                         return sb.ToString ();
933                 }
934
935                 int print_count;
936                 public override void Print (AbstractMessage msg)
937                 {
938                         base.Print (msg);
939
940                         if (Stacktrace)
941                                 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
942
943                         if (++print_count == Fatal)
944                                 throw new Exception (msg.Text);
945                 }
946
947                 public static string FriendlyStackTrace (Exception e)
948                 {
949                         return FriendlyStackTrace (new StackTrace (e, true));
950                 }
951
952                 public static void StackTrace ()
953                 {
954                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
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
1065                 public InternalErrorException (Exception exception, string message, params object[] args)
1066                         : base (String.Format (message, args), exception)
1067                 {
1068                 }
1069                 
1070                 public InternalErrorException (Exception e, Location loc)
1071                         : base (loc.ToString (), e)
1072                 {
1073                 }
1074         }
1075
1076         /// <summary>
1077         /// Handles #pragma warning
1078         /// </summary>
1079         public class WarningRegions {
1080
1081                 abstract class PragmaCmd
1082                 {
1083                         public int Line;
1084
1085                         protected PragmaCmd (int line)
1086                         {
1087                                 Line = line;
1088                         }
1089
1090                         public abstract bool IsEnabled (int code, bool previous);
1091                 }
1092                 
1093                 class Disable : PragmaCmd
1094                 {
1095                         int code;
1096                         public Disable (int line, int code)
1097                                 : base (line)
1098                         {
1099                                 this.code = code;
1100                         }
1101
1102                         public override bool IsEnabled (int code, bool previous)
1103                         {
1104                                 return this.code == code ? false : previous;
1105                         }
1106                 }
1107
1108                 class DisableAll : PragmaCmd
1109                 {
1110                         public DisableAll (int line)
1111                                 : base (line) {}
1112
1113                         public override bool IsEnabled(int code, bool previous)
1114                         {
1115                                 return false;
1116                         }
1117                 }
1118
1119                 class Enable : PragmaCmd
1120                 {
1121                         int code;
1122                         public Enable (int line, int code)
1123                                 : base (line)
1124                         {
1125                                 this.code = code;
1126                         }
1127
1128                         public override bool IsEnabled(int code, bool previous)
1129                         {
1130                                 return this.code == code ? true : previous;
1131                         }
1132                 }
1133
1134                 class EnableAll : PragmaCmd
1135                 {
1136                         public EnableAll (int line)
1137                                 : base (line) {}
1138
1139                         public override bool IsEnabled(int code, bool previous)
1140                         {
1141                                 return true;
1142                         }
1143                 }
1144
1145
1146                 List<PragmaCmd> regions = new List<PragmaCmd> ();
1147
1148                 public void WarningDisable (int line)
1149                 {
1150                         regions.Add (new DisableAll (line));
1151                 }
1152
1153                 public void WarningDisable (Location location, int code, Report Report)
1154                 {
1155                         if (Report.CheckWarningCode (code, location))
1156                                 regions.Add (new Disable (location.Row, code));
1157                 }
1158
1159                 public void WarningEnable (int line)
1160                 {
1161                         regions.Add (new EnableAll (line));
1162                 }
1163
1164                 public void WarningEnable (Location location, int code, Report Report)
1165                 {
1166                         if (Report.CheckWarningCode (code, location))
1167                                 regions.Add (new Enable (location.Row, code));
1168                 }
1169
1170                 public bool IsWarningEnabled (int code, int src_line)
1171                 {
1172                         bool result = true;
1173                         foreach (PragmaCmd pragma in regions) {
1174                                 if (src_line < pragma.Line)
1175                                         break;
1176
1177                                 result = pragma.IsEnabled (code, result);
1178                         }
1179                         return result;
1180                 }
1181         }
1182 }