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