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