2005-12-09 Atsushi Enomoto <atsushi@ximian.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                 /// <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, 282,
79                                                                                                                                  419, 420, 429, 436, 440, 465,
80                                                                                                                                  612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672,
81                                                                                                                                  1030, 1058,
82                                                                                                                                  1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
83                                                                                                                                  1616, 1633, 1634, 1635, 1691, 1692,
84                                                                                                                                  1717, 1718,
85                                                                                                                                  1901,
86                                                                                                                                  2002, 2023,
87                                                                                                                                  3005, 3012, 3019, 3021, 3022, 3023, 3026, 3027
88                                                                                                                          };
89
90                 static Report ()
91                 {
92                         // Just to be sure that binary search is working
93                         Array.Sort (AllWarnings);
94                 }
95
96                 public static void Reset ()
97                 {
98                         Errors = Warnings = 0;
99                         WarningsAreErrors = false;
100                         warning_ignore_table = null;
101                         warning_regions_table = null;
102                 }
103
104                 abstract class AbstractMessage {
105
106                         static void Check (int code)
107                         {
108                                 if (code == expected_error) {
109                                         Environment.Exit (0);
110                                 }
111                         }
112
113                         public abstract bool IsWarning { get; }
114
115                         public abstract string MessageType { get; }
116
117                         public virtual void Print (int code, string location, string text)
118                         {
119                                 if (code < 0)
120                                         code = 8000-code;
121
122                                 StringBuilder msg = new StringBuilder ();
123                                 if (location.Length != 0) {
124                                         msg.Append (location);
125                                         msg.Append (' ');
126                                 }
127                                 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
128                                 Stderr.WriteLine (msg.ToString ());
129
130                                 foreach (string s in extra_information) 
131                                         Stderr.WriteLine (s + MessageType);
132
133                                 extra_information.Clear ();
134
135                                 if (Stacktrace)
136                                         Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
137
138                                 if (Fatal) {
139                                         if (!IsWarning || WarningsAreErrors)
140                                                 throw new Exception (text);
141                                 }
142
143                                 Check (code);
144                         }
145
146                         public virtual void Print (int code, Location location, string text)
147                         {
148                                 if (location.IsNull) {
149                                         Print (code, "", text);
150                                         return;
151                                 }
152                                 Print (code, 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                         TypeContainer temp_ds = TypeManager.LookupTypeContainer (mi.DeclaringType);
312                         if (temp_ds == null) {
313                                 SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
314                         } else {
315                                 if (mi is MethodBase) {
316                                         IMethodData md = TypeManager.GetMethod ((MethodBase)mi);
317                                         SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
318                                         return;
319                                 }
320
321                                 MemberCore mc = temp_ds.GetDefinition (mi.Name);
322                                 SymbolRelatedToPreviousError (mc);
323                         }
324                 }
325
326                 static public void SymbolRelatedToPreviousError (MemberCore mc)
327                 {
328                         SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
329                 }
330
331                 static public void SymbolRelatedToPreviousError (Type type)
332                 {
333                         if (type is TypeBuilder) {
334                                 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
335                                 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
336                         } else if (type.HasElementType) {
337                                 SymbolRelatedToPreviousError (type.GetElementType ());
338                         } else {
339                                 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
340                         }
341                 }
342
343                 static void SymbolRelatedToPreviousError (string loc, string symbol)
344                 {
345                         extra_information.Add (String.Format ("{0}: `{1}', name of symbol related to previous ", loc, symbol));
346                 }
347
348                 public static void ExtraInformation (Location loc, string msg)
349                 {
350                         extra_information.Add (String.Format ("{0} {1}", loc, msg));
351                 }
352
353                 public static WarningRegions RegisterWarningRegion (Location location)
354                 {
355                         if (warning_regions_table == null)
356                                 warning_regions_table = new Hashtable ();
357
358                         WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
359                         if (regions == null) {
360                                 regions = new WarningRegions ();
361                                 warning_regions_table.Add (location.Name, regions);
362                         }
363                         return regions;
364                 }
365
366                 static public void Warning (int code, int level, Location loc, string format, params string[] args)
367                 {
368                         WarningMessage w = new WarningMessage (level);
369                         w.Print (code, loc, String.Format (format, args));
370                 }
371
372                 static public void Warning (int code, int level, string format, params string[] args)
373                 {
374                         Warning (code, level, Location.Null, String.Format (format, args));
375                 }
376
377                 static public void Error (int code, string format, params string[] args)
378                 {
379                         Error (code, Location.Null, String.Format (format, args));
380                 }
381
382                 static public void Error (int code, Location loc, string format, params string[] args)
383                 {
384                         Error (code, loc, String.Format (format, args));
385                 }
386
387                 static void Error (int code, Location loc, string error)
388                 {
389                         new ErrorMessage ().Print (code, loc, error);
390                 }
391
392                 static public void SetIgnoreWarning (int code)
393                 {
394                         if (warning_ignore_table == null)
395                                 warning_ignore_table = new Hashtable ();
396
397                         warning_ignore_table [code] = true;
398                 }
399                 
400                 static public int ExpectedError {
401                         set {
402                                 expected_error = value;
403                         }
404                         get {
405                                 return expected_error;
406                         }
407                 }
408
409                 public static int DebugFlags = 0;
410
411                 [Conditional ("MCS_DEBUG")]
412                 static public void Debug (string message, params object[] args)
413                 {
414                         Debug (4, message, args);
415                 }
416                         
417                 [Conditional ("MCS_DEBUG")]
418                 static public void Debug (int category, string message, params object[] args)
419                 {
420                         if ((category & DebugFlags) == 0)
421                                 return;
422
423                         StringBuilder sb = new StringBuilder (message);
424
425                         if ((args != null) && (args.Length > 0)) {
426                                 sb.Append (": ");
427
428                                 bool first = true;
429                                 foreach (object arg in args) {
430                                         if (first)
431                                                 first = false;
432                                         else
433                                                 sb.Append (", ");
434                                         if (arg == null)
435                                                 sb.Append ("null");
436                                         else if (arg is ICollection)
437                                                 sb.Append (PrintCollection ((ICollection) arg));
438                                         else
439                                                 sb.Append (arg);
440                                 }
441                         }
442
443                         Console.WriteLine (sb.ToString ());
444                 }
445
446                 static public string PrintCollection (ICollection collection)
447                 {
448                         StringBuilder sb = new StringBuilder ();
449
450                         sb.Append (collection.GetType ());
451                         sb.Append ("(");
452
453                         bool first = true;
454                         foreach (object o in collection) {
455                                 if (first)
456                                         first = false;
457                                 else
458                                         sb.Append (", ");
459                                 sb.Append (o);
460                         }
461
462                         sb.Append (")");
463                         return sb.ToString ();
464                 }
465         }
466
467         public enum TimerType {
468                 FindMembers     = 0,
469                 TcFindMembers   = 1,
470                 MemberLookup    = 2,
471                 CachedLookup    = 3,
472                 CacheInit       = 4,
473                 MiscTimer       = 5,
474                 CountTimers     = 6
475         }
476
477         public enum CounterType {
478                 FindMembers     = 0,
479                 MemberCache     = 1,
480                 MiscCounter     = 2,
481                 CountCounters   = 3
482         }
483
484         public class Timer
485         {
486                 static DateTime[] timer_start;
487                 static TimeSpan[] timers;
488                 static long[] timer_counters;
489                 static long[] counters;
490
491                 static Timer ()
492                 {
493                         timer_start = new DateTime [(int) TimerType.CountTimers];
494                         timers = new TimeSpan [(int) TimerType.CountTimers];
495                         timer_counters = new long [(int) TimerType.CountTimers];
496                         counters = new long [(int) CounterType.CountCounters];
497
498                         for (int i = 0; i < (int) TimerType.CountTimers; i++) {
499                                 timer_start [i] = DateTime.Now;
500                                 timers [i] = TimeSpan.Zero;
501                         }
502                 }
503
504                 [Conditional("TIMER")]
505                 static public void IncrementCounter (CounterType which)
506                 {
507                         ++counters [(int) which];
508                 }
509
510                 [Conditional("TIMER")]
511                 static public void StartTimer (TimerType which)
512                 {
513                         timer_start [(int) which] = DateTime.Now;
514                 }
515
516                 [Conditional("TIMER")]
517                 static public void StopTimer (TimerType which)
518                 {
519                         timers [(int) which] += DateTime.Now - timer_start [(int) which];
520                         ++timer_counters [(int) which];
521                 }
522
523                 [Conditional("TIMER")]
524                 static public void ShowTimers ()
525                 {
526                         ShowTimer (TimerType.FindMembers, "- FindMembers timer");
527                         ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
528                         ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
529                         ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
530                         ShowTimer (TimerType.CacheInit, "- Cache init");
531                         ShowTimer (TimerType.MiscTimer, "- Misc timer");
532
533                         ShowCounter (CounterType.FindMembers, "- Find members");
534                         ShowCounter (CounterType.MemberCache, "- Member cache");
535                         ShowCounter (CounterType.MiscCounter, "- Misc counter");
536                 }
537
538                 static public void ShowCounter (CounterType which, string msg)
539                 {
540                         Console.WriteLine ("{0} {1}", counters [(int) which], msg);
541                 }
542
543                 static public void ShowTimer (TimerType which, string msg)
544                 {
545                         Console.WriteLine (
546                                 "[{0:00}:{1:000}] {2} (used {3} times)",
547                                 (int) timers [(int) which].TotalSeconds,
548                                 timers [(int) which].Milliseconds, msg,
549                                 timer_counters [(int) which]);
550                 }
551         }
552
553         public class InternalErrorException : Exception {
554                 public InternalErrorException ()
555                         : base ("Internal error")
556                 {
557                 }
558
559                 public InternalErrorException (string message)
560                         : base (message)
561                 {
562                 }
563         }
564
565         /// <summary>
566         /// Handles #pragma warning
567         /// </summary>
568         public class WarningRegions {
569
570                 abstract class PragmaCmd
571                 {
572                         public int Line;
573
574                         protected PragmaCmd (int line)
575                         {
576                                 Line = line;
577                         }
578
579                         public abstract bool IsEnabled (int code, bool previous);
580                 }
581                 
582                 class Disable : PragmaCmd
583                 {
584                         int code;
585                         public Disable (int line, int code)
586                                 : base (line)
587                         {
588                                 this.code = code;
589                         }
590
591                         public override bool IsEnabled (int code, bool previous)
592                         {
593                                 return this.code == code ? false : previous;
594                         }
595                 }
596
597                 class DisableAll : PragmaCmd
598                 {
599                         public DisableAll (int line)
600                                 : base (line) {}
601
602                         public override bool IsEnabled(int code, bool previous)
603                         {
604                                 return false;
605                         }
606                 }
607
608                 class Enable : PragmaCmd
609                 {
610                         int code;
611                         public Enable (int line, int code)
612                                 : base (line)
613                         {
614                                 this.code = code;
615                         }
616
617                         public override bool IsEnabled(int code, bool previous)
618                         {
619                                 return this.code == code ? true : previous;
620                         }
621                 }
622
623                 class EnableAll : PragmaCmd
624                 {
625                         public EnableAll (int line)
626                                 : base (line) {}
627
628                         public override bool IsEnabled(int code, bool previous)
629                         {
630                                 return true;
631                         }
632                 }
633
634
635                 ArrayList regions = new ArrayList ();
636
637                 public void WarningDisable (int line)
638                 {
639                         regions.Add (new DisableAll (line));
640                 }
641
642                 public void WarningDisable (Location location, int code)
643                 {
644                         if (CheckWarningCode (code, location))
645                                 regions.Add (new Disable (location.Row, code));
646                 }
647
648                 public void WarningEnable (int line)
649                 {
650                         regions.Add (new EnableAll (line));
651                 }
652
653                 public void WarningEnable (Location location, int code)
654                 {
655                         if (CheckWarningCode (code, location))
656                                 regions.Add (new Enable (location.Row, code));
657                 }
658
659                 public bool IsWarningEnabled (int code, int src_line)
660                 {
661                         bool result = true;
662                         foreach (PragmaCmd pragma in regions) {
663                                 if (src_line < pragma.Line)
664                                         break;
665
666                                 result = pragma.IsEnabled (code, result);
667                         }
668                         return result;
669                 }
670
671                 bool CheckWarningCode (int code, Location loc)
672                 {
673                         if (Report.IsValidWarning (code))
674                                 return true;
675
676                         Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code.ToString ());
677                         return false;
678                 }
679         }
680 }