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