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