2009-12-03 Marek Safar <marek.safar@gmail.com>
[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                 /// <summary>  
25                 ///   Whether errors should be throw an exception
26                 /// </summary>
27                 public bool Fatal;
28                 
29                 /// <summary>  
30                 ///   Whether warnings should be considered errors
31                 /// </summary>
32                 public bool WarningsAreErrors;
33                 List<int> warnings_as_error;
34                 List<int> warnings_only;
35
36                 public static int DebugFlags = 0;
37
38                 //
39                 // Keeps track of the warnings that we are ignoring
40                 //
41                 public Dictionary<int, bool> warning_ignore_table;
42
43                 Dictionary<string, WarningRegions> warning_regions_table;
44
45                 int warning_level;
46
47                 ReportPrinter printer;
48
49                 int reporting_disabled;
50                 
51                 /// <summary>
52                 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
53                 /// </summary>
54                 List<string> extra_information = new List<string> ();
55
56                 // 
57                 // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
58                 //
59                 public static readonly int[] AllWarnings = new int[] {
60                         28, 67, 78,
61                         105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
62                         219, 251, 252, 253, 278, 282,
63                         402, 414, 419, 420, 429, 436, 440, 458, 464, 465, 467, 469, 472,
64                         612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675, 693,
65                         809,
66                         1030, 1058, 1066,
67                         1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
68                         1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692,
69                         1700, 1717, 1718, 1720,
70                         1901,
71                         2002, 2023, 2029,
72                         3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009,
73                         3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019,
74                         3021, 3022, 3023, 3024, 3026, 3027
75                 };
76
77                 static Report ()
78                 {
79                         // Just to be sure that binary search is working
80                         Array.Sort (AllWarnings);
81                 }
82
83                 public Report (ReportPrinter printer)
84                 {
85                         if (printer == null)
86                                 throw new ArgumentNullException ("printer");
87
88                         this.printer = printer;
89                         warning_level = 4;
90                 }
91
92                 public void DisableReporting ()
93                 {
94                         ++reporting_disabled;
95                 }
96
97                 public void EnableReporting ()
98                 {
99                         --reporting_disabled;
100                 }
101
102                 public void FeatureIsNotAvailable (Location loc, string feature)
103                 {
104                         string version;
105                         switch (RootContext.Version) {
106                         case LanguageVersion.ISO_1:
107                                 version = "1.0";
108                                 break;
109                         case LanguageVersion.ISO_2:
110                                 version = "2.0";
111                                 break;
112                         case LanguageVersion.V_3:
113                                 version = "3.0";
114                                 break;
115                         default:
116                                 throw new InternalErrorException ("Invalid feature version", RootContext.Version);
117                         }
118
119                         Error (1644, loc,
120                                 "Feature `{0}' cannot be used because it is not part of the C# {1} language specification",
121                                       feature, version);
122                 }
123
124                 public void FeatureIsNotSupported (Location loc, string feature)
125                 {
126                         Error (1644, loc,
127                                 "Feature `{0}' is not supported in Mono mcs1 compiler. Consider using the `gmcs' compiler instead",
128                                 feature);
129                 }
130                 
131                 static bool IsValidWarning (int code)
132                 {       
133                         return Array.BinarySearch (AllWarnings, code) >= 0;
134                 }
135
136                 bool IsWarningEnabled (int code, int level, Location loc)
137                 {
138                         if (WarningLevel < level)
139                                 return false;
140
141                         if (warning_ignore_table != null) {
142                                 if (warning_ignore_table.ContainsKey (code)) {
143                                         return false;
144                                 }
145                         }
146
147                         if (warning_regions_table == null || loc.IsNull)
148                                 return true;
149
150                         WarningRegions regions;
151                         if (!warning_regions_table.TryGetValue (loc.Name, out regions))
152                                 return true;
153
154                         return regions.IsWarningEnabled (code, loc.Row);
155                 }
156
157                 bool IsWarningAsError (int code)
158                 {
159                         bool is_error = WarningsAreErrors;
160
161                         // Check specific list
162                         if (warnings_as_error != null)
163                                 is_error |= warnings_as_error.Contains (code);
164
165                         // Ignore excluded warnings
166                         if (warnings_only != null && warnings_only.Contains (code))
167                                 is_error = false;
168
169                         return is_error;
170                 }
171                         
172                 public void RuntimeMissingSupport (Location loc, string feature) 
173                 {
174                         Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
175                 }
176
177                 /// <summary>
178                 /// In most error cases is very useful to have information about symbol that caused the error.
179                 /// Call this method before you call Report.Error when it makes sense.
180                 /// </summary>
181                 public void SymbolRelatedToPreviousError (Location loc, string symbol)
182                 {
183                         SymbolRelatedToPreviousError (loc.ToString (), symbol);
184                 }
185
186                 public void SymbolRelatedToPreviousError (MemberInfo mi)
187                 {
188                         if (reporting_disabled > 0 || !printer.HasRelatedSymbolSupport)
189                                 return;
190
191                         Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType);
192                         if (TypeManager.IsDelegateType (dt)) {
193                                 SymbolRelatedToPreviousError (dt);
194                                 return;
195                         }                       
196                         
197                         DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt);
198                         if (temp_ds == null) {
199                                 SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi));
200                         } else {
201                                 MethodBase mb = mi as MethodBase;
202                                 if (mb != null) {
203                                         mb = TypeManager.DropGenericMethodArguments (mb);
204                                         IMethodData md = TypeManager.GetMethod (mb);
205                                         if (md != null)
206                                                 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
207
208                                         return;
209                                 }
210
211                                 // FIXME: Completely wrong, it has to use FindMembers
212                                 MemberCore mc = temp_ds.GetDefinition (mi.Name);
213                                 if (mc != null)
214                                         SymbolRelatedToPreviousError (mc);
215                         }
216                 }
217
218                 public void SymbolRelatedToPreviousError (MemberCore mc)
219                 {
220                         SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
221                 }
222
223                 public void SymbolRelatedToPreviousError (Type type)
224                 {
225                         if (reporting_disabled > 0 || !printer.HasRelatedSymbolSupport)
226                                 return;
227
228                         type = TypeManager.DropGenericTypeArguments (type);
229
230                         if (TypeManager.IsGenericParameter (type)) {
231                                 TypeParameter tp = TypeManager.LookupTypeParameter (type);
232                                 if (tp != null) {
233                                         SymbolRelatedToPreviousError (tp.Location, "");
234                                         return;
235                                 }
236                         }
237
238                         if (type is TypeBuilder) {
239                                 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
240                                 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
241                         } else if (TypeManager.HasElementType (type)) {
242                                 SymbolRelatedToPreviousError (TypeManager.GetElementType (type));
243                         } else {
244                                 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
245                         }
246                 }
247
248                 void SymbolRelatedToPreviousError (string loc, string symbol)
249                 {
250                         string msg = String.Format ("{0} (Location of the symbol related to previous ", loc);
251                         if (extra_information.Contains (msg))
252                                 return;
253
254                         extra_information.Add (msg);
255                 }
256
257                 public void AddWarningAsError (string warningId)
258                 {
259                         int id;
260                         try {
261                                 id = int.Parse (warningId);
262                         } catch {
263                                 id = -1;
264                         }
265
266                         if (!CheckWarningCode (id, warningId, Location.Null))
267                                 return;
268
269                         if (warnings_as_error == null)
270                                 warnings_as_error = new List<int> ();
271                         
272                         warnings_as_error.Add (id);
273                 }
274
275                 public void RemoveWarningAsError (string warningId)
276                 {
277                         int id;
278                         try {
279                                 id = int.Parse (warningId);
280                         } catch {
281                                 id = -1;
282                         }
283
284                         if (!CheckWarningCode (id, warningId, Location.Null))
285                                 return;
286
287                         if (warnings_only == null)
288                                 warnings_only = new List<int> ();
289
290                         warnings_only.Add (id);
291                 }
292
293                 public bool CheckWarningCode (int code, Location loc)
294                 {
295                         return CheckWarningCode (code, code.ToString (), loc);
296                 }
297
298                 public bool CheckWarningCode (int code, string scode, Location loc)
299                 {
300                         if (IsValidWarning (code))
301                                 return true;
302
303                         Warning (1691, 1, loc, "`{0}' is not a valid warning number", scode);
304                         return false;
305                 }
306
307                 public void ExtraInformation (Location loc, string msg)
308                 {
309                         extra_information.Add (String.Format ("{0} {1}", loc, msg));
310                 }
311
312                 public WarningRegions RegisterWarningRegion (Location location)
313                 {
314                         WarningRegions regions;
315                         if (warning_regions_table == null) {
316                                 regions = null;
317                                 warning_regions_table = new Dictionary<string, WarningRegions> ();
318                         } else {
319                                 warning_regions_table.TryGetValue (location.Name, out regions);
320                         }
321
322                         if (regions == null) {
323                                 regions = new WarningRegions ();
324                                 warning_regions_table.Add (location.Name, regions);
325                         }
326
327                         return regions;
328                 }
329
330                 public void Warning (int code, int level, Location loc, string message)
331                 {
332                         if (reporting_disabled > 0)
333                                 return;
334
335                         if (!IsWarningEnabled (code, level, loc))
336                                 return;
337
338                         AbstractMessage msg;
339                         if (IsWarningAsError (code))
340                                 msg = new ErrorMessage (code, loc, message, extra_information);
341                         else
342                                 msg = new WarningMessage (code, loc, message, extra_information);
343
344                         extra_information.Clear ();
345                         printer.Print (msg);
346                 }
347
348                 public void Warning (int code, int level, Location loc, string format, string arg)
349                 {
350                         Warning (code, level, loc, String.Format (format, arg));
351                 }
352
353                 public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
354                 {
355                         Warning (code, level, loc, String.Format (format, arg1, arg2));
356                 }
357
358                 public void Warning (int code, int level, Location loc, string format, params object[] args)
359                 {
360                         Warning (code, level, loc, String.Format (format, args));
361                 }
362
363                 public void Warning (int code, int level, string message)
364                 {
365                         Warning (code, level, Location.Null, message);
366                 }
367
368                 public void Warning (int code, int level, string format, string arg)
369                 {
370                         Warning (code, level, Location.Null, format, arg);
371                 }
372
373                 public void Warning (int code, int level, string format, string arg1, string arg2)
374                 {
375                         Warning (code, level, Location.Null, format, arg1, arg2);
376                 }
377
378                 public void Warning (int code, int level, string format, params string[] args)
379                 {
380                         Warning (code, level, Location.Null, String.Format (format, args));
381                 }
382
383                 //
384                 // Warnings encountered so far
385                 //
386                 public int Warnings {
387                         get { return printer.WarningsCount; }
388                 }
389
390                 public void Error (int code, Location loc, string error)
391                 {
392                         if (reporting_disabled > 0)
393                                 return;
394
395                         ErrorMessage msg = new ErrorMessage (code, loc, error, extra_information);
396                         extra_information.Clear ();
397
398                         printer.Print (msg);
399
400                         if (Fatal)
401                                 throw new Exception (msg.Text);
402                 }
403
404                 public void Error (int code, Location loc, string format, string arg)
405                 {
406                         Error (code, loc, String.Format (format, arg));
407                 }
408
409                 public void Error (int code, Location loc, string format, string arg1, string arg2)
410                 {
411                         Error (code, loc, String.Format (format, arg1, arg2));
412                 }
413
414                 public void Error (int code, Location loc, string format, params object[] args)
415                 {
416                         Error (code, loc, String.Format (format, args));
417                 }
418
419                 public void Error (int code, string error)
420                 {
421                         Error (code, Location.Null, error);
422                 }
423
424                 public void Error (int code, string format, string arg)
425                 {
426                         Error (code, Location.Null, format, arg);
427                 }
428
429                 public void Error (int code, string format, string arg1, string arg2)
430                 {
431                         Error (code, Location.Null, format, arg1, arg2);
432                 }
433
434                 public void Error (int code, string format, params string[] args)
435                 {
436                         Error (code, Location.Null, String.Format (format, args));
437                 }
438
439                 //
440                 // Errors encountered so far
441                 //
442                 public int Errors {
443                         get { return printer.ErrorsCount; }
444                 }
445
446                 public ReportPrinter Printer {
447                         get { return printer; }
448                 }
449
450                 public void SetIgnoreWarning (int code)
451                 {
452                         if (warning_ignore_table == null)
453                                 warning_ignore_table = new Dictionary<int, bool> ();
454
455                         warning_ignore_table [code] = true;
456                 }
457
458                 public ReportPrinter SetPrinter (ReportPrinter printer)
459                 {
460                         ReportPrinter old = this.printer;
461                         this.printer = printer;
462                         return old;
463                 }
464                 
465                 public int WarningLevel {
466                         get {
467                                 return warning_level;
468                         }
469                         set {
470                                 warning_level = value;
471                         }
472                 }
473
474                 [Conditional ("MCS_DEBUG")]
475                 static public void Debug (string message, params object[] args)
476                 {
477                         Debug (4, message, args);
478                 }
479                         
480                 [Conditional ("MCS_DEBUG")]
481                 static public void Debug (int category, string message, params object[] args)
482                 {
483                         if ((category & DebugFlags) == 0)
484                                 return;
485
486                         StringBuilder sb = new StringBuilder (message);
487
488                         if ((args != null) && (args.Length > 0)) {
489                                 sb.Append (": ");
490
491                                 bool first = true;
492                                 foreach (object arg in args) {
493                                         if (first)
494                                                 first = false;
495                                         else
496                                                 sb.Append (", ");
497                                         if (arg == null)
498                                                 sb.Append ("null");
499 //                                      else if (arg is ICollection)
500 //                                              sb.Append (PrintCollection ((ICollection) arg));
501                                         else
502                                                 sb.Append (arg);
503                                 }
504                         }
505
506                         Console.WriteLine (sb.ToString ());
507                 }
508 /*
509                 static public string PrintCollection (ICollection collection)
510                 {
511                         StringBuilder sb = new StringBuilder ();
512
513                         sb.Append (collection.GetType ());
514                         sb.Append ("(");
515
516                         bool first = true;
517                         foreach (object o in collection) {
518                                 if (first)
519                                         first = false;
520                                 else
521                                         sb.Append (", ");
522                                 sb.Append (o);
523                         }
524
525                         sb.Append (")");
526                         return sb.ToString ();
527                 }
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, List<string> 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 = extraInfo.ToArray ();
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, List<string> 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, List<string> 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                 List<AbstractMessage> session_messages;
708                 //
709                 // A collection of exactly same messages reported in all sessions
710                 //
711                 List<AbstractMessage> common_messages;
712
713                 //
714                 // A collection of unique messages reported in all sessions
715                 //
716                 List<AbstractMessage> 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 List<AbstractMessage> ();
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 List<AbstractMessage> (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                         var 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                 readonly 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 : StreamReportPrinter
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                 public ConsoleReportPrinter ()
876                         : base (Console.Error)
877                 {
878                 }
879
880                 public ConsoleReportPrinter (TextWriter writer)
881                         : base (writer)
882                 {
883                 }
884
885                 static int NameToCode (string s)
886                 {
887                         switch (s) {
888                         case "black":
889                                 return 0;
890                         case "red":
891                                 return 1;
892                         case "green":
893                                 return 2;
894                         case "yellow":
895                                 return 3;
896                         case "blue":
897                                 return 4;
898                         case "magenta":
899                                 return 5;
900                         case "cyan":
901                                 return 6;
902                         case "grey":
903                         case "white":
904                                 return 7;
905                         }
906                         return 7;
907                 }
908
909                 //
910                 // maps a color name to its xterm color code
911                 //
912                 static string GetForeground (string s)
913                 {
914                         string highcode;
915
916                         if (s.StartsWith ("bright")) {
917                                 highcode = "1;";
918                                 s = s.Substring (6);
919                         } else
920                                 highcode = "";
921
922                         return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m";
923                 }
924
925                 static string GetBackground (string s)
926                 {
927                         return "\x001b[" + (40 + NameToCode (s)).ToString () + "m";
928                 }
929
930                 protected override string FormatText (string txt)
931                 {
932                         if (prefix != null)
933                                 return prefix + txt + postfix;
934
935                         return txt;
936                 }
937
938                 static string FriendlyStackTrace (StackTrace t)
939                 {               
940                         StringBuilder sb = new StringBuilder ();
941                         
942                         bool foundUserCode = false;
943                         
944                         for (int i = 0; i < t.FrameCount; i++) {
945                                 StackFrame f = t.GetFrame (i);
946                                 MethodBase mb = f.GetMethod ();
947                                 
948                                 if (!foundUserCode && mb.ReflectedType == typeof (Report))
949                                         continue;
950                                 
951                                 foundUserCode = true;
952                                 
953                                 sb.Append ("\tin ");
954                                 
955                                 if (f.GetFileLineNumber () > 0)
956                                         sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
957                                 
958                                 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
959                                 
960                                 bool first = true;
961                                 foreach (ParameterInfo pi in mb.GetParameters ()) {
962                                         if (!first)
963                                                 sb.Append (", ");
964                                         first = false;
965                                         
966                                         sb.Append (TypeManager.CSharpName (pi.ParameterType));
967                                 }
968                                 sb.Append (")\n");
969                         }
970         
971                         return sb.ToString ();
972                 }
973
974                 public override void Print (AbstractMessage msg)
975                 {
976                         base.Print (msg);
977
978                         if (Stacktrace)
979                                 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
980                 }
981
982                 public static string FriendlyStackTrace (Exception e)
983                 {
984                         return FriendlyStackTrace (new StackTrace (e, true));
985                 }
986
987                 public static void StackTrace ()
988                 {
989                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
990                 }
991         }
992
993         public enum TimerType {
994                 FindMembers     = 0,
995                 TcFindMembers   = 1,
996                 MemberLookup    = 2,
997                 CachedLookup    = 3,
998                 CacheInit       = 4,
999                 MiscTimer       = 5,
1000                 CountTimers     = 6
1001         }
1002
1003         public enum CounterType {
1004                 FindMembers     = 0,
1005                 MemberCache     = 1,
1006                 MiscCounter     = 2,
1007                 CountCounters   = 3
1008         }
1009
1010         public class Timer
1011         {
1012                 static DateTime[] timer_start;
1013                 static TimeSpan[] timers;
1014                 static long[] timer_counters;
1015                 static long[] counters;
1016
1017                 static Timer ()
1018                 {
1019                         timer_start = new DateTime [(int) TimerType.CountTimers];
1020                         timers = new TimeSpan [(int) TimerType.CountTimers];
1021                         timer_counters = new long [(int) TimerType.CountTimers];
1022                         counters = new long [(int) CounterType.CountCounters];
1023
1024                         for (int i = 0; i < (int) TimerType.CountTimers; i++) {
1025                                 timer_start [i] = DateTime.Now;
1026                                 timers [i] = TimeSpan.Zero;
1027                         }
1028                 }
1029
1030                 [Conditional("TIMER")]
1031                 static public void IncrementCounter (CounterType which)
1032                 {
1033                         ++counters [(int) which];
1034                 }
1035
1036                 [Conditional("TIMER")]
1037                 static public void StartTimer (TimerType which)
1038                 {
1039                         timer_start [(int) which] = DateTime.Now;
1040                 }
1041
1042                 [Conditional("TIMER")]
1043                 static public void StopTimer (TimerType which)
1044                 {
1045                         timers [(int) which] += DateTime.Now - timer_start [(int) which];
1046                         ++timer_counters [(int) which];
1047                 }
1048
1049                 [Conditional("TIMER")]
1050                 static public void ShowTimers ()
1051                 {
1052                         ShowTimer (TimerType.FindMembers, "- FindMembers timer");
1053                         ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
1054                         ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
1055                         ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
1056                         ShowTimer (TimerType.CacheInit, "- Cache init");
1057                         ShowTimer (TimerType.MiscTimer, "- Misc timer");
1058
1059                         ShowCounter (CounterType.FindMembers, "- Find members");
1060                         ShowCounter (CounterType.MemberCache, "- Member cache");
1061                         ShowCounter (CounterType.MiscCounter, "- Misc counter");
1062                 }
1063
1064                 static public void ShowCounter (CounterType which, string msg)
1065                 {
1066                         Console.WriteLine ("{0} {1}", counters [(int) which], msg);
1067                 }
1068
1069                 static public void ShowTimer (TimerType which, string msg)
1070                 {
1071                         Console.WriteLine (
1072                                 "[{0:00}:{1:000}] {2} (used {3} times)",
1073                                 (int) timers [(int) which].TotalSeconds,
1074                                 timers [(int) which].Milliseconds, msg,
1075                                 timer_counters [(int) which]);
1076                 }
1077         }
1078
1079         public class InternalErrorException : Exception {
1080                 public InternalErrorException (MemberCore mc, Exception e)
1081                         : base (mc.Location + " " + mc.GetSignatureForError (), e)
1082                 {
1083                 }
1084
1085                 public InternalErrorException ()
1086                         : base ("Internal error")
1087                 {
1088                 }
1089
1090                 public InternalErrorException (string message)
1091                         : base (message)
1092                 {
1093                 }
1094
1095                 public InternalErrorException (string message, params object[] args)
1096                         : base (String.Format (message, args))
1097                 { }
1098                 
1099                 public InternalErrorException (Exception e, Location loc)
1100                         : base (loc.ToString (), e)
1101                 {
1102                 }
1103         }
1104
1105         /// <summary>
1106         /// Handles #pragma warning
1107         /// </summary>
1108         public class WarningRegions {
1109
1110                 abstract class PragmaCmd
1111                 {
1112                         public int Line;
1113
1114                         protected PragmaCmd (int line)
1115                         {
1116                                 Line = line;
1117                         }
1118
1119                         public abstract bool IsEnabled (int code, bool previous);
1120                 }
1121                 
1122                 class Disable : PragmaCmd
1123                 {
1124                         int code;
1125                         public Disable (int line, int code)
1126                                 : base (line)
1127                         {
1128                                 this.code = code;
1129                         }
1130
1131                         public override bool IsEnabled (int code, bool previous)
1132                         {
1133                                 return this.code == code ? false : previous;
1134                         }
1135                 }
1136
1137                 class DisableAll : PragmaCmd
1138                 {
1139                         public DisableAll (int line)
1140                                 : base (line) {}
1141
1142                         public override bool IsEnabled(int code, bool previous)
1143                         {
1144                                 return false;
1145                         }
1146                 }
1147
1148                 class Enable : PragmaCmd
1149                 {
1150                         int code;
1151                         public Enable (int line, int code)
1152                                 : base (line)
1153                         {
1154                                 this.code = code;
1155                         }
1156
1157                         public override bool IsEnabled(int code, bool previous)
1158                         {
1159                                 return this.code == code ? true : previous;
1160                         }
1161                 }
1162
1163                 class EnableAll : PragmaCmd
1164                 {
1165                         public EnableAll (int line)
1166                                 : base (line) {}
1167
1168                         public override bool IsEnabled(int code, bool previous)
1169                         {
1170                                 return true;
1171                         }
1172                 }
1173
1174
1175                 List<PragmaCmd> regions = new List<PragmaCmd> ();
1176
1177                 public void WarningDisable (int line)
1178                 {
1179                         regions.Add (new DisableAll (line));
1180                 }
1181
1182                 public void WarningDisable (Location location, int code, Report Report)
1183                 {
1184                         if (Report.CheckWarningCode (code, location))
1185                                 regions.Add (new Disable (location.Row, code));
1186                 }
1187
1188                 public void WarningEnable (int line)
1189                 {
1190                         regions.Add (new EnableAll (line));
1191                 }
1192
1193                 public void WarningEnable (Location location, int code, Report Report)
1194                 {
1195                         if (Report.CheckWarningCode (code, location))
1196                                 regions.Add (new Enable (location.Row, code));
1197                 }
1198
1199                 public bool IsWarningEnabled (int code, int src_line)
1200                 {
1201                         bool result = true;
1202                         foreach (PragmaCmd pragma in regions) {
1203                                 if (src_line < pragma.Line)
1204                                         break;
1205
1206                                 result = pragma.IsEnabled (code, result);
1207                         }
1208                         return result;
1209                 }
1210         }
1211 }