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