2007-07-13 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / report.cs
1 //
2 // report.cs: report errors and warnings.
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //         Marek Safar (marek.safar@seznam.cz)         
6 //
7 // (C) 2001 Ximian, Inc. (http://www.ximian.com)
8 //
9
10 using System;
11 using System.IO;
12 using System.Text;
13 using System.Collections;
14 using System.Collections.Specialized;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
18
19 namespace Mono.CSharp {
20
21         /// <summary>
22         ///   This class is used to report errors and warnings t te user.
23         /// </summary>
24         public class Report {
25                 /// <summary>  
26                 ///   Errors encountered so far
27                 /// </summary>
28                 static public int Errors;
29
30                 /// <summary>  
31                 ///   Warnings encountered so far
32                 /// </summary>
33                 static public int Warnings;
34
35                 /// <summary>  
36                 ///   Whether errors should be throw an exception
37                 /// </summary>
38                 static public bool Fatal;
39                 
40                 /// <summary>  
41                 ///   Whether warnings should be considered errors
42                 /// </summary>
43                 static public bool WarningsAreErrors;
44
45
46                 /// <summary>  
47                 ///   Whether to dump a stack trace on errors. 
48                 /// </summary>
49                 static public bool Stacktrace;
50
51                 static public TextWriter Stderr = Console.Error;
52                 
53                 //
54                 // If the 'expected' error code is reported then the
55                 // compilation succeeds.
56                 //
57                 // Used for the test suite to excercise the error codes
58                 //
59                 static int expected_error = 0;
60
61                 //
62                 // Keeps track of the warnings that we are ignoring
63                 //
64                 public static Hashtable warning_ignore_table;
65
66                 static Hashtable warning_regions_table;
67
68                 //
69                 // This is used to save/restore the error state.  When the
70                 // error stack contains elements, warnings and errors are not
71                 // reported to the user.  This is used by the Lambda expression
72                 // support to compile the code with various parameter values.
73                 // A stack because of `Report.Errors == errors;'
74                 //
75                 static Stack error_stack;
76                 static bool reporting_disabled;
77                 
78                 static int warning_level;
79                 
80                 /// <summary>
81                 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
82                 /// </summary>
83                 static StringCollection extra_information = new StringCollection ();
84
85                 // 
86                 // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
87                 //
88                 public static readonly int[] AllWarnings = new int[] {
89                         28, 67, 78,
90                         105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
91                         219, 251, 252, 253, 278, 282,
92                         419, 420, 429, 436, 440, 465, 467, 469,
93                         612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675,
94                         809,
95                         1030,
96                         1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
97                         1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692,
98                         1717, 1718, 1720,
99                         1901,
100                         2002, 2023, 2029,
101                         3005, 3012, 3018, 3019, 3021, 3022, 3023, 3026, 3027,
102 #if GMCS_SOURCE
103                         402, 414, 693, 1058, 1700, 3024
104 #endif
105                 };
106
107                 static Report ()
108                 {
109                         // Just to be sure that binary search is working
110                         Array.Sort (AllWarnings);
111                 }
112
113                 public static void Reset ()
114                 {
115                         Errors = Warnings = 0;
116                         WarningsAreErrors = false;
117                         warning_ignore_table = null;
118                         warning_regions_table = null;
119                         reporting_disabled = false;
120                 }
121
122                 public static void DisableReporting ()
123                 {
124                         if (error_stack == null)
125                                 error_stack = new Stack ();
126                         error_stack.Push (Errors);
127                         reporting_disabled = true;
128                 }
129
130                 public static void EnableReporting ()
131                 {
132                         Errors = (int) error_stack.Pop ();
133                         if (error_stack.Count == 0) {
134                                 reporting_disabled = false;
135                         }
136                 }
137                 
138                 abstract class AbstractMessage {
139
140                         static void Check (int code)
141                         {
142                                 if (code == expected_error) {
143                                         Environment.Exit (0);
144                                 }
145                         }
146
147                         public abstract bool IsWarning { get; }
148
149                         public abstract string MessageType { get; }
150
151                         public virtual void Print (int code, Location location, string text)
152                         {
153                                 if (reporting_disabled) {
154                                         //
155                                         // This line is useful when debugging the inner working of
156                                         // Lambdas when various compilation attempts are done.
157                                         //
158                                         //Console.WriteLine ("DISABLED: {0} {1} {2}", code, location, text);
159                                         return;
160                                 }
161                                 
162                                 if (code < 0)
163                                         code = 8000-code;
164
165                                 StringBuilder msg = new StringBuilder ();
166                                 if (!location.IsNull) {
167                                         msg.Append (location.ToString ());
168                                         msg.Append (' ');
169                                 }
170                                 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
171                                 Stderr.WriteLine (msg.ToString ());
172
173                                 foreach (string s in extra_information) 
174                                         Stderr.WriteLine (s + MessageType + ")");
175
176                                 extra_information.Clear ();
177
178                                 if (Stacktrace)
179                                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
180
181                                 if (Fatal) {
182                                         if (!IsWarning || WarningsAreErrors)
183                                                 throw new Exception (text);
184                                 }
185
186                                 Check (code);
187                         }
188                 }
189
190                 sealed class WarningMessage : AbstractMessage {
191                         readonly int Level;
192
193                         public WarningMessage (int level)
194                         {
195                                 Level = level;
196                         }
197
198                         public override bool IsWarning {
199                                 get { return true; }
200                         }
201
202                         bool IsEnabled (int code, Location loc)
203                         {
204                                 if (WarningLevel < Level)
205                                         return false;
206
207                                 if (warning_ignore_table != null) {
208                                         if (warning_ignore_table.Contains (code)) {
209                                                 return false;
210                                         }
211                                 }
212
213                                 if (warning_regions_table == null || loc.IsNull)
214                                         return true;
215
216                                 WarningRegions regions = (WarningRegions)warning_regions_table [loc.Name];
217                                 if (regions == null)
218                                         return true;
219
220                                 return regions.IsWarningEnabled (code, loc.Row);
221                         }
222
223                         public override void Print (int code, Location location, string text)
224                         {
225                                 if (!IsEnabled (code, location)) {
226                                         extra_information.Clear ();
227                                         return;
228                                 }
229
230                                 if (WarningsAreErrors) {
231                                         new ErrorMessage ().Print (code, location, text);
232                                         return;
233                                 }
234
235                                 Warnings++;
236                                 base.Print (code, location, text);
237                         }
238
239                         public override string MessageType {
240                                 get {
241                                         return "warning";
242                                 }
243                         }
244                 }
245
246                 sealed class ErrorMessage : AbstractMessage {
247
248                         public override void Print(int code, Location location, string text)
249                         {
250                                 Errors++;
251                                 base.Print (code, location, text);
252                         }
253
254                         public override bool IsWarning {
255                                 get { return false; }
256                         }
257
258                         public override string MessageType {
259                                 get {
260                                         return "error";
261                                 }
262                         }
263
264                 }
265
266                 public static void FeatureIsNotISO1 (Location loc, string feature)
267                 {
268                         Report.Error (1644, loc,
269                                 "Feature `{0}' cannot be used because it is not part of the C# 1.0 language specification",
270                                       feature);
271                 }
272
273                 public static void FeatureRequiresLINQ (Location loc, string feature)
274                 {
275                         Report.Error (1644, loc,
276                                       "Feature `{0}' can only be used if the language level is LINQ", feature);
277                 }
278                 
279                 public static string FriendlyStackTrace (Exception e)
280                 {
281                         return FriendlyStackTrace (new StackTrace (e, true));
282                 }
283                 
284                 static string FriendlyStackTrace (StackTrace t)
285                 {               
286                         StringBuilder sb = new StringBuilder ();
287                         
288                         bool foundUserCode = false;
289                         
290                         for (int i = 0; i < t.FrameCount; i++) {
291                                 StackFrame f = t.GetFrame (i);
292                                 MethodBase mb = f.GetMethod ();
293                                 
294                                 if (!foundUserCode && mb.ReflectedType == typeof (Report))
295                                         continue;
296                                 
297                                 foundUserCode = true;
298                                 
299                                 sb.Append ("\tin ");
300                                 
301                                 if (f.GetFileLineNumber () > 0)
302                                         sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
303                                 
304                                 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
305                                 
306                                 bool first = true;
307                                 foreach (ParameterInfo pi in mb.GetParameters ()) {
308                                         if (!first)
309                                                 sb.Append (", ");
310                                         first = false;
311                                         
312                                         sb.Append (TypeManager.CSharpName (pi.ParameterType));
313                                 }
314                                 sb.Append (")\n");
315                         }
316         
317                         return sb.ToString ();
318                 }
319
320                 public static void StackTrace ()
321                 {
322                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
323                 }
324
325                 public static bool IsValidWarning (int code)
326                 {       
327                         return Array.BinarySearch (AllWarnings, code) >= 0;
328                 }
329                         
330                 static public void RuntimeMissingSupport (Location loc, string feature) 
331                 {
332                         Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
333                 }
334
335                 /// <summary>
336                 /// In most error cases is very useful to have information about symbol that caused the error.
337                 /// Call this method before you call Report.Error when it makes sense.
338                 /// </summary>
339                 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
340                 {
341                         SymbolRelatedToPreviousError (loc.ToString (), symbol);
342                 }
343
344                 static public void SymbolRelatedToPreviousError (MemberInfo mi)
345                 {
346                         if (reporting_disabled)
347                                 return;
348
349                         Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType);
350                         DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt);
351                         if (temp_ds == null) {
352                                 SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi));
353                         } else {
354                                 MethodBase mb = mi as MethodBase;
355                                 if (mb != null) {
356                                         mb = TypeManager.DropGenericMethodArguments (mb);
357                                         IMethodData md = TypeManager.GetMethod (mb);
358                                         SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
359                                         return;
360                                 }
361
362                                 MemberCore mc = temp_ds.GetDefinition (mi.Name);
363                                 SymbolRelatedToPreviousError (mc);
364                         }
365                 }
366
367                 static public void SymbolRelatedToPreviousError (MemberCore mc)
368                 {
369                         SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
370                 }
371
372                 static public void SymbolRelatedToPreviousError (Type type)
373                 {
374                         if (reporting_disabled)
375                                 return;
376
377                         type = TypeManager.DropGenericTypeArguments (type);
378
379                         if (TypeManager.IsGenericParameter (type)) {
380                                 TypeParameter tp = TypeManager.LookupTypeParameter (type);
381                                 if (tp != null) {
382                                         SymbolRelatedToPreviousError (tp.Location, "");
383                                         return;
384                                 }
385                         }
386
387                         if (type is TypeBuilder) {
388                                 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
389                                 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
390                         } else if (type.HasElementType) {
391                                 SymbolRelatedToPreviousError (type.GetElementType ());
392                         } else {
393                                 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
394                         }
395                 }
396
397                 static void SymbolRelatedToPreviousError (string loc, string symbol)
398                 {
399                         extra_information.Add (String.Format ("{0} (Location of the symbol related to previous ", loc));
400                 }
401
402                 public static void ExtraInformation (Location loc, string msg)
403                 {
404                         if (reporting_disabled)
405                                 return;
406
407                         extra_information.Add (String.Format ("{0} {1}", loc, msg));
408                 }
409
410                 public static WarningRegions RegisterWarningRegion (Location location)
411                 {
412                         if (warning_regions_table == null)
413                                 warning_regions_table = new Hashtable ();
414
415                         WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
416                         if (regions == null) {
417                                 regions = new WarningRegions ();
418                                 warning_regions_table.Add (location.Name, regions);
419                         }
420                         return regions;
421                 }
422
423                 static public void Warning (int code, int level, Location loc, string message)
424                 {
425                         WarningMessage w = new WarningMessage (level);
426                         w.Print (code, loc, message);
427                 }
428
429                 static public void Warning (int code, int level, Location loc, string format, string arg)
430                 {
431                         WarningMessage w = new WarningMessage (level);
432                         w.Print (code, loc, String.Format (format, arg));
433                 }
434
435                 static public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
436                 {
437                         WarningMessage w = new WarningMessage (level);
438                         w.Print (code, loc, String.Format (format, arg1, arg2));
439                 }
440
441                 static public void Warning (int code, int level, Location loc, string format, params string[] args)
442                 {
443                         WarningMessage w = new WarningMessage (level);
444                         w.Print (code, loc, String.Format (format, args));
445                 }
446
447                 static public void Warning (int code, int level, string message)
448                 {
449                         Warning (code, level, Location.Null, message);
450                 }
451
452                 static public void Warning (int code, int level, string format, string arg)
453                 {
454                         Warning (code, level, Location.Null, format, arg);
455                 }
456
457                 static public void Warning (int code, int level, string format, string arg1, string arg2)
458                 {
459                         Warning (code, level, Location.Null, format, arg1, arg2);
460                 }
461
462                 static public void Warning (int code, int level, string format, params string[] args)
463                 {
464                         Warning (code, level, Location.Null, String.Format (format, args));
465                 }
466
467                 static public void Error (int code, Location loc, string error)
468                 {
469                         new ErrorMessage ().Print (code, loc, error);
470                 }
471
472                 static public void Error (int code, Location loc, string format, string arg)
473                 {
474                         new ErrorMessage ().Print (code, loc, String.Format (format, arg));
475                 }
476
477                 static public void Error (int code, Location loc, string format, string arg1, string arg2)
478                 {
479                         new ErrorMessage ().Print (code, loc, String.Format (format, arg1, arg2));
480                 }
481
482                 static public void Error (int code, Location loc, string format, params string[] args)
483                 {
484                         Error (code, loc, String.Format (format, args));
485                 }
486
487                 static public void Error (int code, string error)
488                 {
489                         Error (code, Location.Null, error);
490                 }
491
492                 static public void Error (int code, string format, string arg)
493                 {
494                         Error (code, Location.Null, format, arg);
495                 }
496
497                 static public void Error (int code, string format, string arg1, string arg2)
498                 {
499                         Error (code, Location.Null, format, arg1, arg2);
500                 }
501
502                 static public void Error (int code, string format, params string[] args)
503                 {
504                         Error (code, Location.Null, String.Format (format, args));
505                 }
506
507                 static public void SetIgnoreWarning (int code)
508                 {
509                         if (warning_ignore_table == null)
510                                 warning_ignore_table = new Hashtable ();
511
512                         warning_ignore_table [code] = true;
513                 }
514                 
515                 static public int ExpectedError {
516                         set {
517                                 expected_error = value;
518                         }
519                         get {
520                                 return expected_error;
521                         }
522                 }
523                 
524                 public static int WarningLevel {
525                         get {
526                                 if (reporting_disabled)
527                                         return 0;
528                                 
529                                 return warning_level;
530                         }
531                         set {
532                                 warning_level = value;
533                         }
534                 }
535
536                 public static int DebugFlags = 0;
537
538                 [Conditional ("MCS_DEBUG")]
539                 static public void Debug (string message, params object[] args)
540                 {
541                         Debug (4, message, args);
542                 }
543                         
544                 [Conditional ("MCS_DEBUG")]
545                 static public void Debug (int category, string message, params object[] args)
546                 {
547                         if ((category & DebugFlags) == 0)
548                                 return;
549
550                         StringBuilder sb = new StringBuilder (message);
551
552                         if ((args != null) && (args.Length > 0)) {
553                                 sb.Append (": ");
554
555                                 bool first = true;
556                                 foreach (object arg in args) {
557                                         if (first)
558                                                 first = false;
559                                         else
560                                                 sb.Append (", ");
561                                         if (arg == null)
562                                                 sb.Append ("null");
563                                         else if (arg is ICollection)
564                                                 sb.Append (PrintCollection ((ICollection) arg));
565                                         else
566                                                 sb.Append (arg);
567                                 }
568                         }
569
570                         Console.WriteLine (sb.ToString ());
571                 }
572
573                 static public string PrintCollection (ICollection collection)
574                 {
575                         StringBuilder sb = new StringBuilder ();
576
577                         sb.Append (collection.GetType ());
578                         sb.Append ("(");
579
580                         bool first = true;
581                         foreach (object o in collection) {
582                                 if (first)
583                                         first = false;
584                                 else
585                                         sb.Append (", ");
586                                 sb.Append (o);
587                         }
588
589                         sb.Append (")");
590                         return sb.ToString ();
591                 }
592         }
593
594         public enum TimerType {
595                 FindMembers     = 0,
596                 TcFindMembers   = 1,
597                 MemberLookup    = 2,
598                 CachedLookup    = 3,
599                 CacheInit       = 4,
600                 MiscTimer       = 5,
601                 CountTimers     = 6
602         }
603
604         public enum CounterType {
605                 FindMembers     = 0,
606                 MemberCache     = 1,
607                 MiscCounter     = 2,
608                 CountCounters   = 3
609         }
610
611         public class Timer
612         {
613                 static DateTime[] timer_start;
614                 static TimeSpan[] timers;
615                 static long[] timer_counters;
616                 static long[] counters;
617
618                 static Timer ()
619                 {
620                         timer_start = new DateTime [(int) TimerType.CountTimers];
621                         timers = new TimeSpan [(int) TimerType.CountTimers];
622                         timer_counters = new long [(int) TimerType.CountTimers];
623                         counters = new long [(int) CounterType.CountCounters];
624
625                         for (int i = 0; i < (int) TimerType.CountTimers; i++) {
626                                 timer_start [i] = DateTime.Now;
627                                 timers [i] = TimeSpan.Zero;
628                         }
629                 }
630
631                 [Conditional("TIMER")]
632                 static public void IncrementCounter (CounterType which)
633                 {
634                         ++counters [(int) which];
635                 }
636
637                 [Conditional("TIMER")]
638                 static public void StartTimer (TimerType which)
639                 {
640                         timer_start [(int) which] = DateTime.Now;
641                 }
642
643                 [Conditional("TIMER")]
644                 static public void StopTimer (TimerType which)
645                 {
646                         timers [(int) which] += DateTime.Now - timer_start [(int) which];
647                         ++timer_counters [(int) which];
648                 }
649
650                 [Conditional("TIMER")]
651                 static public void ShowTimers ()
652                 {
653                         ShowTimer (TimerType.FindMembers, "- FindMembers timer");
654                         ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
655                         ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
656                         ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
657                         ShowTimer (TimerType.CacheInit, "- Cache init");
658                         ShowTimer (TimerType.MiscTimer, "- Misc timer");
659
660                         ShowCounter (CounterType.FindMembers, "- Find members");
661                         ShowCounter (CounterType.MemberCache, "- Member cache");
662                         ShowCounter (CounterType.MiscCounter, "- Misc counter");
663                 }
664
665                 static public void ShowCounter (CounterType which, string msg)
666                 {
667                         Console.WriteLine ("{0} {1}", counters [(int) which], msg);
668                 }
669
670                 static public void ShowTimer (TimerType which, string msg)
671                 {
672                         Console.WriteLine (
673                                 "[{0:00}:{1:000}] {2} (used {3} times)",
674                                 (int) timers [(int) which].TotalSeconds,
675                                 timers [(int) which].Milliseconds, msg,
676                                 timer_counters [(int) which]);
677                 }
678         }
679
680         public class InternalErrorException : Exception {
681                 public InternalErrorException (MemberCore mc, Exception e)
682                         : base (mc.Location + " " + mc.GetSignatureForError (), e)
683                 {
684                 }
685
686                 public InternalErrorException ()
687                         : base ("Internal error")
688                 {
689                 }
690
691                 public InternalErrorException (string message)
692                         : base (message)
693                 {
694                 }
695
696                 public InternalErrorException (string message, params object[] args)
697                         : base (String.Format (message, args))
698                 { }
699         }
700
701         /// <summary>
702         /// Handles #pragma warning
703         /// </summary>
704         public class WarningRegions {
705
706                 abstract class PragmaCmd
707                 {
708                         public int Line;
709
710                         protected PragmaCmd (int line)
711                         {
712                                 Line = line;
713                         }
714
715                         public abstract bool IsEnabled (int code, bool previous);
716                 }
717                 
718                 class Disable : PragmaCmd
719                 {
720                         int code;
721                         public Disable (int line, int code)
722                                 : base (line)
723                         {
724                                 this.code = code;
725                         }
726
727                         public override bool IsEnabled (int code, bool previous)
728                         {
729                                 return this.code == code ? false : previous;
730                         }
731                 }
732
733                 class DisableAll : PragmaCmd
734                 {
735                         public DisableAll (int line)
736                                 : base (line) {}
737
738                         public override bool IsEnabled(int code, bool previous)
739                         {
740                                 return false;
741                         }
742                 }
743
744                 class Enable : PragmaCmd
745                 {
746                         int code;
747                         public Enable (int line, int code)
748                                 : base (line)
749                         {
750                                 this.code = code;
751                         }
752
753                         public override bool IsEnabled(int code, bool previous)
754                         {
755                                 return this.code == code ? true : previous;
756                         }
757                 }
758
759                 class EnableAll : PragmaCmd
760                 {
761                         public EnableAll (int line)
762                                 : base (line) {}
763
764                         public override bool IsEnabled(int code, bool previous)
765                         {
766                                 return true;
767                         }
768                 }
769
770
771                 ArrayList regions = new ArrayList ();
772
773                 public void WarningDisable (int line)
774                 {
775                         regions.Add (new DisableAll (line));
776                 }
777
778                 public void WarningDisable (Location location, int code)
779                 {
780                         if (CheckWarningCode (code, location))
781                                 regions.Add (new Disable (location.Row, code));
782                 }
783
784                 public void WarningEnable (int line)
785                 {
786                         regions.Add (new EnableAll (line));
787                 }
788
789                 public void WarningEnable (Location location, int code)
790                 {
791                         if (CheckWarningCode (code, location))
792                                 regions.Add (new Enable (location.Row, code));
793                 }
794
795                 public bool IsWarningEnabled (int code, int src_line)
796                 {
797                         bool result = true;
798                         foreach (PragmaCmd pragma in regions) {
799                                 if (src_line < pragma.Line)
800                                         break;
801
802                                 result = pragma.IsEnabled (code, result);
803                         }
804                         return result;
805                 }
806
807                 static bool CheckWarningCode (int code, Location loc)
808                 {
809                         if (Report.IsValidWarning (code))
810                                 return true;
811
812                         Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code.ToString ());
813                         return false;
814                 }
815         }
816 }