2 // report.cs: report errors and warnings.
4 // Author: Miguel de Icaza (miguel@ximian.com)
6 // (C) 2001 Ximian, Inc. (http://www.ximian.com)
10 // FIXME: currently our class library does not support custom number format strings
15 using System.Collections;
16 using System.Collections.Specialized;
17 using System.Diagnostics;
18 using System.Reflection;
19 using System.Reflection.Emit;
21 namespace Mono.CSharp {
24 /// This class is used to report errors and warnings t te user.
28 /// Errors encountered so far
30 static public int Errors;
33 /// Warnings encountered so far
35 static public int Warnings;
38 /// Whether errors should be throw an exception
40 static public bool Fatal;
43 /// Whether warnings should be considered errors
45 static public bool WarningsAreErrors;
48 /// Whether to dump a stack trace on errors.
50 static public bool Stacktrace;
52 static public TextWriter Stderr = Console.Error;
55 // If the 'expected' error code is reported then the
56 // compilation succeeds.
58 // Used for the test suite to excercise the error codes
60 static int expected_error = 0;
63 // Keeps track of the warnings that we are ignoring
65 public static Hashtable warning_ignore_table;
67 static Hashtable warning_regions_table;
70 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
72 static StringCollection extra_information = new StringCollection ();
74 public static void Reset ()
76 Errors = Warnings = 0;
77 WarningsAreErrors = false;
78 warning_ignore_table = null;
79 warning_regions_table = null;
82 abstract class AbstractMessage {
84 static void Check (int code)
86 if (code == expected_error) {
91 public abstract bool IsWarning { get; }
93 public abstract string MessageType { get; }
95 public virtual void Print (int code, string location, string text)
100 StringBuilder msg = new StringBuilder ();
101 if (location.Length != 0) {
102 msg.Append (location);
105 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
106 Stderr.WriteLine (msg.ToString ());
108 foreach (string s in extra_information)
109 Stderr.WriteLine (s + MessageType);
111 extra_information.Clear ();
114 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
117 if (!IsWarning || WarningsAreErrors)
118 throw new Exception (text);
124 public virtual void Print (int code, Location location, string text)
126 if (location.IsNull) {
127 Print (code, "", text);
130 Print (code, location.ToString (), text);
134 sealed class WarningMessage: AbstractMessage {
135 Location loc = Location.Null;
138 public WarningMessage ():
141 public WarningMessage (int level)
146 public override bool IsWarning {
150 bool IsEnabled (int code)
152 if (RootContext.WarningLevel < Level)
155 if (warning_ignore_table != null) {
156 if (warning_ignore_table.Contains (code)) {
161 if (warning_regions_table == null || loc.Equals (Location.Null))
164 WarningRegions regions = (WarningRegions)warning_regions_table [loc.Name];
168 return regions.IsWarningEnabled (code, loc.Row);
171 public override void Print(int code, string location, string text)
173 if (!IsEnabled (code)) {
174 extra_information.Clear ();
178 if (WarningsAreErrors) {
179 new ErrorMessage ().Print (code, location, text);
184 base.Print (code, location, text);
187 public override void Print(int code, Location location, string text)
190 base.Print (code, location, text);
193 public override string MessageType {
200 sealed class ErrorMessage: AbstractMessage {
202 public override void Print(int code, string location, string text)
205 base.Print (code, location, text);
208 public override bool IsWarning {
209 get { return false; }
212 public override string MessageType {
220 public static void FeatureIsNotStandardized (Location loc, string feature)
222 Report.Error (1644, loc, "Feature `{0}' cannot be used because it is not part of the standardized ISO C# language specification", feature);
225 public static string FriendlyStackTrace (Exception e)
227 return FriendlyStackTrace (new StackTrace (e, true));
230 static string FriendlyStackTrace (StackTrace t)
232 StringBuilder sb = new StringBuilder ();
234 bool foundUserCode = false;
236 for (int i = 0; i < t.FrameCount; i++) {
237 StackFrame f = t.GetFrame (i);
238 MethodBase mb = f.GetMethod ();
240 if (!foundUserCode && mb.ReflectedType == typeof (Report))
243 foundUserCode = true;
247 if (f.GetFileLineNumber () > 0)
248 sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
250 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
253 foreach (ParameterInfo pi in mb.GetParameters ()) {
258 sb.Append (TypeManager.CSharpName (pi.ParameterType));
263 return sb.ToString ();
266 public static void StackTrace ()
268 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
271 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
272 // IF YOU ADD A NEW WARNING YOU HAVE TO DUPLICATE ITS ID HERE
274 public static bool IsValidWarning (int code)
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, 3005
281 foreach (int i in all_warnings) {
288 static public void LocationOfPreviousError (Location loc)
290 Stderr.WriteLine (String.Format ("{0} (Location of symbol related to previous error)", loc));
293 static public void RuntimeMissingSupport (Location loc, string feature)
295 Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
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.
302 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
304 SymbolRelatedToPreviousError (loc.ToString (), symbol);
307 static public void SymbolRelatedToPreviousError (MemberInfo mi)
309 TypeContainer temp_ds = TypeManager.LookupGenericTypeContainer (mi.DeclaringType);
310 if (temp_ds == null) {
311 SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
313 MethodBase mb = mi as MethodBase;
315 while (mb.Mono_IsInflatedMethod)
316 mb = mb.GetGenericMethodDefinition ();
317 IMethodData md = TypeManager.GetMethod (mb);
318 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
322 MemberCore mc = temp_ds.GetDefinition (mi.Name);
323 SymbolRelatedToPreviousError (mc);
327 static public void SymbolRelatedToPreviousError (MemberCore mc)
329 SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
332 static public void SymbolRelatedToPreviousError (Type type)
334 if (type.IsGenericInstance)
335 type = type.GetGenericTypeDefinition ();
336 if (type is TypeBuilder) {
337 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
338 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
339 } else if (type.HasElementType) {
340 SymbolRelatedToPreviousError (type.GetElementType ());
342 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
346 static void SymbolRelatedToPreviousError (string loc, string symbol)
348 extra_information.Add (String.Format ("{0}: `{1}' (name of symbol related to previous ", loc, symbol));
351 public static void ExtraInformation (Location loc, string msg)
353 extra_information.Add (String.Format ("{0} {1}", loc, msg));
356 public static WarningRegions RegisterWarningRegion (Location location)
358 if (warning_regions_table == null)
359 warning_regions_table = new Hashtable ();
361 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
362 if (regions == null) {
363 regions = new WarningRegions ();
364 warning_regions_table.Add (location.Name, regions);
369 static public void Warning (int code, int level, Location loc, string format, params object[] args)
371 WarningMessage w = new WarningMessage (level);
372 w.Print (code, loc, String.Format (format, args));
375 static public void Warning (int code, Location loc, string format, params object[] args)
377 WarningMessage w = new WarningMessage ();
378 w.Print (code, loc, String.Format (format, args));
381 static public void Warning (int code, string format, params object[] args)
383 Warning (code, Location.Null, String.Format (format, args));
387 /// Did you test your WarningLevel, that you use this method
389 static public void Warning (int code, string text)
391 Warning (code, Location.Null, text);
394 static public void Error (int code, string format, params object[] args)
396 Error (code, Location.Null, String.Format (format, args));
399 static public void Error (int code, Location loc, string format, params object[] args)
401 Error (code, loc, String.Format (format, args));
404 static public void Error (int code, Location loc, string error)
406 new ErrorMessage ().Print (code, loc, error);
409 static public void SetIgnoreWarning (int code)
411 if (warning_ignore_table == null)
412 warning_ignore_table = new Hashtable ();
414 warning_ignore_table [code] = true;
417 static public int ExpectedError {
419 expected_error = value;
422 return expected_error;
426 public static int DebugFlags = 0;
428 [Conditional ("MCS_DEBUG")]
429 static public void Debug (string message, params object[] args)
431 Debug (4, message, args);
434 [Conditional ("MCS_DEBUG")]
435 static public void Debug (int category, string message, params object[] args)
437 if ((category & DebugFlags) == 0)
440 StringBuilder sb = new StringBuilder (message);
442 if ((args != null) && (args.Length > 0)) {
446 foreach (object arg in args) {
453 else if (arg is ICollection)
454 sb.Append (PrintCollection ((ICollection) arg));
460 Console.WriteLine (sb.ToString ());
463 static public string PrintCollection (ICollection collection)
465 StringBuilder sb = new StringBuilder ();
467 sb.Append (collection.GetType ());
471 foreach (object o in collection) {
480 return sb.ToString ();
484 public enum TimerType {
494 public enum CounterType {
503 static DateTime[] timer_start;
504 static TimeSpan[] timers;
505 static long[] timer_counters;
506 static long[] counters;
510 timer_start = new DateTime [(int) TimerType.CountTimers];
511 timers = new TimeSpan [(int) TimerType.CountTimers];
512 timer_counters = new long [(int) TimerType.CountTimers];
513 counters = new long [(int) CounterType.CountCounters];
515 for (int i = 0; i < (int) TimerType.CountTimers; i++) {
516 timer_start [i] = DateTime.Now;
517 timers [i] = TimeSpan.Zero;
521 [Conditional("TIMER")]
522 static public void IncrementCounter (CounterType which)
524 ++counters [(int) which];
527 [Conditional("TIMER")]
528 static public void StartTimer (TimerType which)
530 timer_start [(int) which] = DateTime.Now;
533 [Conditional("TIMER")]
534 static public void StopTimer (TimerType which)
536 timers [(int) which] += DateTime.Now - timer_start [(int) which];
537 ++timer_counters [(int) which];
540 [Conditional("TIMER")]
541 static public void ShowTimers ()
543 ShowTimer (TimerType.FindMembers, "- FindMembers timer");
544 ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
545 ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
546 ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
547 ShowTimer (TimerType.CacheInit, "- Cache init");
548 ShowTimer (TimerType.MiscTimer, "- Misc timer");
550 ShowCounter (CounterType.FindMembers, "- Find members");
551 ShowCounter (CounterType.MemberCache, "- Member cache");
552 ShowCounter (CounterType.MiscCounter, "- Misc counter");
555 static public void ShowCounter (CounterType which, string msg)
557 Console.WriteLine ("{0} {1}", counters [(int) which], msg);
560 static public void ShowTimer (TimerType which, string msg)
563 "[{0:00}:{1:000}] {2} (used {3} times)",
564 (int) timers [(int) which].TotalSeconds,
565 timers [(int) which].Milliseconds, msg,
566 timer_counters [(int) which]);
570 public class InternalErrorException : Exception {
571 public InternalErrorException ()
572 : base ("Internal error")
576 public InternalErrorException (string message)
583 /// Handles #pragma warning
585 public class WarningRegions {
587 abstract class PragmaCmd
591 protected PragmaCmd (int line)
596 public abstract bool IsEnabled (int code, bool previous);
599 class Disable: PragmaCmd
602 public Disable (int line, int code)
608 public override bool IsEnabled (int code, bool previous)
610 return this.code == code ? false : previous;
614 class DisableAll: PragmaCmd
616 public DisableAll (int line)
619 public override bool IsEnabled(int code, bool previous)
625 class Enable: PragmaCmd
628 public Enable (int line, int code)
634 public override bool IsEnabled(int code, bool previous)
636 return this.code == code ? true : previous;
640 class EnableAll: PragmaCmd
642 public EnableAll (int line)
645 public override bool IsEnabled(int code, bool previous)
652 ArrayList regions = new ArrayList ();
654 public void WarningDisable (int line)
656 regions.Add (new DisableAll (line));
659 public void WarningDisable (Location location, int code)
661 if (CheckWarningCode (code, location))
662 regions.Add (new Disable (location.Row, code));
665 public void WarningEnable (int line)
667 regions.Add (new EnableAll (line));
670 public void WarningEnable (Location location, int code)
672 if (CheckWarningCode (code, location))
673 regions.Add (new Enable (location.Row, code));
676 public bool IsWarningEnabled (int code, int src_line)
679 foreach (PragmaCmd pragma in regions) {
680 if (src_line < pragma.Line)
683 result = pragma.IsEnabled (code, result);
688 bool CheckWarningCode (int code, Location loc)
690 if (Report.IsValidWarning (code))
693 Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code);