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.Equals (Location.Null)) {
127 Print (code, "", text);
130 Print (code, String.Format ("{0}({1})", location.Name, location.Row), 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 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
267 // IF YOU ADD A NEW WARNING YOU HAVE TO DUPLICATE ITS ID HERE
269 public static bool IsValidWarning (int code)
271 int[] all_warnings = new int[] {
272 28, 67, 78, 105, 108, 109, 114, 192, 168, 169, 183, 184, 219, 251, 612, 618, 626, 628, 642, 649,
273 659, 660, 661, 672, 1030, 1522, 1616, 1691, 1692, 1901, 2002, 2023, 3012, 3019, 8024, 8028
276 foreach (int i in all_warnings) {
283 static public void LocationOfPreviousError (Location loc)
285 Stderr.WriteLine (String.Format ("{0}({1}) (Location of symbol related to previous error)", loc.Name, loc.Row));
288 static public void RuntimeMissingSupport (Location loc, string feature)
290 Report.Error (-88, loc, "Your .NET Runtime does not support '{0}'. Please use the latest Mono runtime instead.", feature);
294 /// In most error cases is very useful to have information about symbol that caused the error.
295 /// Call this method before you call Report.Error when it makes sense.
297 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
299 SymbolRelatedToPreviousError (String.Format ("{0}({1})", loc.Name, loc.Row), symbol);
302 static public void SymbolRelatedToPreviousError (MemberInfo mi)
304 TypeContainer temp_ds = TypeManager.LookupGenericTypeContainer (mi.DeclaringType);
305 if (temp_ds == null) {
306 SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
308 MethodBase mb = mi as MethodBase;
310 while (mb.Mono_IsInflatedMethod)
311 mb = mb.GetGenericMethodDefinition ();
312 IMethodData md = TypeManager.GetMethod (mb);
313 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError (temp_ds));
317 MemberCore mc = temp_ds.GetDefinition (mi.Name);
318 SymbolRelatedToPreviousError (mc);
322 static public void SymbolRelatedToPreviousError (MemberCore mc)
324 SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
327 static public void SymbolRelatedToPreviousError (Type type)
329 if (type is TypeBuilder) {
330 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
331 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
332 } else if (type.HasElementType) {
333 SymbolRelatedToPreviousError (type.GetElementType ());
335 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
339 static void SymbolRelatedToPreviousError (string loc, string symbol)
341 extra_information.Add (String.Format ("{0}: '{1}' (name of symbol related to previous ", loc, symbol));
344 public static void ExtraInformation (Location loc, string msg)
346 extra_information.Add (String.Format ("{0}({1}) {2}", loc.Name, loc.Row, msg));
349 public static WarningRegions RegisterWarningRegion (Location location)
351 if (warning_regions_table == null)
352 warning_regions_table = new Hashtable ();
354 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
355 if (regions == null) {
356 regions = new WarningRegions ();
357 warning_regions_table.Add (location.Name, regions);
362 static public void Warning (int code, int level, Location loc, string format, params object[] args)
364 WarningMessage w = new WarningMessage (level);
365 w.Print (code, loc, String.Format (format, args));
368 static public void Warning (int code, Location loc, string format, params object[] args)
370 WarningMessage w = new WarningMessage ();
371 w.Print (code, loc, String.Format (format, args));
374 static public void Warning (int code, string format, params object[] args)
376 Warning (code, Location.Null, String.Format (format, args));
380 /// Did you test your WarningLevel, that you use this method
382 static public void Warning (int code, string text)
384 Warning (code, Location.Null, text);
387 static public void Error (int code, string format, params object[] args)
389 Error (code, Location.Null, String.Format (format, args));
392 static public void Error (int code, Location loc, string format, params object[] args)
394 ErrorMessage e = new ErrorMessage ();
395 e.Print (code, loc, String.Format (format, args));
398 static public void SetIgnoreWarning (int code)
400 if (warning_ignore_table == null)
401 warning_ignore_table = new Hashtable ();
403 warning_ignore_table [code] = true;
406 static public int ExpectedError {
408 expected_error = value;
411 return expected_error;
415 public static int DebugFlags = 0;
417 [Conditional ("MCS_DEBUG")]
418 static public void Debug (string message, params object[] args)
420 Debug (4, message, args);
423 [Conditional ("MCS_DEBUG")]
424 static public void Debug (int category, string message, params object[] args)
426 if ((category & DebugFlags) == 0)
429 StringBuilder sb = new StringBuilder (message);
431 if ((args != null) && (args.Length > 0)) {
435 foreach (object arg in args) {
442 else if (arg is ICollection)
443 sb.Append (PrintCollection ((ICollection) arg));
449 Console.WriteLine (sb.ToString ());
452 static public string PrintCollection (ICollection collection)
454 StringBuilder sb = new StringBuilder ();
456 sb.Append (collection.GetType ());
460 foreach (object o in collection) {
469 return sb.ToString ();
473 public enum TimerType {
483 public enum CounterType {
492 static DateTime[] timer_start;
493 static TimeSpan[] timers;
494 static long[] timer_counters;
495 static long[] counters;
499 timer_start = new DateTime [(int) TimerType.CountTimers];
500 timers = new TimeSpan [(int) TimerType.CountTimers];
501 timer_counters = new long [(int) TimerType.CountTimers];
502 counters = new long [(int) CounterType.CountCounters];
504 for (int i = 0; i < (int) TimerType.CountTimers; i++) {
505 timer_start [i] = DateTime.Now;
506 timers [i] = TimeSpan.Zero;
510 [Conditional("TIMER")]
511 static public void IncrementCounter (CounterType which)
513 ++counters [(int) which];
516 [Conditional("TIMER")]
517 static public void StartTimer (TimerType which)
519 timer_start [(int) which] = DateTime.Now;
522 [Conditional("TIMER")]
523 static public void StopTimer (TimerType which)
525 timers [(int) which] += DateTime.Now - timer_start [(int) which];
526 ++timer_counters [(int) which];
529 [Conditional("TIMER")]
530 static public void ShowTimers ()
532 ShowTimer (TimerType.FindMembers, "- FindMembers timer");
533 ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
534 ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
535 ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
536 ShowTimer (TimerType.CacheInit, "- Cache init");
537 ShowTimer (TimerType.MiscTimer, "- Misc timer");
539 ShowCounter (CounterType.FindMembers, "- Find members");
540 ShowCounter (CounterType.MemberCache, "- Member cache");
541 ShowCounter (CounterType.MiscCounter, "- Misc counter");
544 static public void ShowCounter (CounterType which, string msg)
546 Console.WriteLine ("{0} {1}", counters [(int) which], msg);
549 static public void ShowTimer (TimerType which, string msg)
552 "[{0:00}:{1:000}] {2} (used {3} times)",
553 (int) timers [(int) which].TotalSeconds,
554 timers [(int) which].Milliseconds, msg,
555 timer_counters [(int) which]);
559 public class InternalErrorException : Exception {
560 public InternalErrorException ()
561 : base ("Internal error")
565 public InternalErrorException (string message)
572 /// Handles #pragma warning
574 public class WarningRegions {
576 abstract class PragmaCmd
580 protected PragmaCmd (int line)
585 public abstract bool IsEnabled (int code, bool previous);
588 class Disable: PragmaCmd
591 public Disable (int line, int code)
597 public override bool IsEnabled (int code, bool previous)
599 return this.code == code ? false : previous;
603 class DisableAll: PragmaCmd
605 public DisableAll (int line)
608 public override bool IsEnabled(int code, bool previous)
614 class Enable: PragmaCmd
617 public Enable (int line, int code)
623 public override bool IsEnabled(int code, bool previous)
625 return this.code == code ? true : previous;
629 class EnableAll: PragmaCmd
631 public EnableAll (int line)
634 public override bool IsEnabled(int code, bool previous)
641 ArrayList regions = new ArrayList ();
643 public void WarningDisable (int line)
645 regions.Add (new DisableAll (line));
648 public void WarningDisable (Location location, int code)
650 if (CheckWarningCode (code, location))
651 regions.Add (new Disable (location.Row, code));
654 public void WarningEnable (int line)
656 regions.Add (new EnableAll (line));
659 public void WarningEnable (Location location, int code)
661 if (CheckWarningCode (code, location))
662 regions.Add (new Enable (location.Row, code));
665 public bool IsWarningEnabled (int code, int src_line)
668 foreach (PragmaCmd pragma in regions) {
669 if (src_line < pragma.Line)
672 result = pragma.IsEnabled (code, result);
677 bool CheckWarningCode (int code, Location loc)
679 if (Report.IsValidWarning (code))
682 Report.Warning (1691, 1, loc, "'{0}' is not a valid warning number", code);