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