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