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