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
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
20 namespace Mono.CSharp {
23 /// This class is used to report errors and warnings t te user.
27 /// Errors encountered so far
29 static public int Errors;
32 /// Warnings encountered so far
34 static public int Warnings;
37 /// Whether errors should be throw an exception
39 static public bool Fatal;
42 /// Whether warnings should be considered errors
44 static public bool WarningsAreErrors;
47 /// Whether to dump a stack trace on errors.
49 static public bool Stacktrace;
52 // If the 'expected' error code is reported then the
53 // compilation succeeds.
55 // Used for the test suite to excercise the error codes
57 static int expected_error = 0;
60 // Keeps track of the warnings that we are ignoring
62 public static Hashtable warning_ignore_table;
64 static Hashtable warning_regions_table;
67 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
69 static StringCollection extra_information = new StringCollection ();
71 public static void Reset ()
73 Errors = Warnings = 0;
74 WarningsAreErrors = false;
75 warning_ignore_table = null;
76 warning_regions_table = null;
79 abstract class AbstractMessage {
81 static void Check (int code)
83 if (code == expected_error) {
88 public abstract bool IsWarning { get; }
90 public abstract string MessageType { get; }
92 public virtual void Print (int code, string location, string text)
97 StringBuilder msg = new StringBuilder ();
98 if (location.Length != 0) {
99 msg.Append (location);
102 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
103 Console.Error.WriteLine (msg.ToString ());
105 foreach (string s in extra_information)
106 Console.Error.WriteLine (s + MessageType);
108 extra_information.Clear ();
111 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
114 if (!IsWarning || WarningsAreErrors)
115 throw new Exception (text);
121 public virtual void Print (int code, Location location, string text)
123 if (location.Equals (Location.Null)) {
124 Print (code, "", text);
127 Print (code, String.Format ("{0}({1})", location.Name, location.Row), text);
131 sealed class WarningMessage: AbstractMessage {
132 Location loc = Location.Null;
135 public WarningMessage ():
138 public WarningMessage (int level)
143 public override bool IsWarning {
147 bool IsEnabled (int code)
149 if (RootContext.WarningLevel < Level)
152 if (warning_ignore_table != null) {
153 if (warning_ignore_table.Contains (code)) {
158 if (warning_regions_table == null || loc.Equals (Location.Null))
161 WarningRegions regions = (WarningRegions)warning_regions_table [loc.Name];
165 return regions.IsWarningEnabled (code, loc.Row);
168 public override void Print(int code, string location, string text)
170 if (!IsEnabled (code)) {
171 extra_information.Clear ();
175 if (WarningsAreErrors) {
176 new ErrorMessage ().Print (code, location, text);
181 base.Print (code, location, text);
184 public override void Print(int code, Location location, string text)
187 base.Print (code, location, text);
190 public override string MessageType {
197 sealed class ErrorMessage: AbstractMessage {
199 public override void Print(int code, string location, string text)
202 base.Print (code, location, text);
205 public override bool IsWarning {
206 get { return false; }
209 public override string MessageType {
217 public static void FeatureIsNotStandardized (Location loc, string feature)
219 Report.Error (1644, loc, "Feature '{0}' cannot be used because it is not part of the standardized ISO C# language specification", feature);
222 public static string FriendlyStackTrace (Exception e)
224 return FriendlyStackTrace (new StackTrace (e, true));
227 static string FriendlyStackTrace (StackTrace t)
229 StringBuilder sb = new StringBuilder ();
231 bool foundUserCode = false;
233 for (int i = 0; i < t.FrameCount; i++) {
234 StackFrame f = t.GetFrame (i);
235 MethodBase mb = f.GetMethod ();
237 if (!foundUserCode && mb.ReflectedType == typeof (Report))
240 foundUserCode = true;
244 if (f.GetFileLineNumber () > 0)
245 sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
247 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
250 foreach (ParameterInfo pi in mb.GetParameters ()) {
255 sb.Append (TypeManager.CSharpName (pi.ParameterType));
260 return sb.ToString ();
263 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
264 // IF YOU ADD A NEW WARNING YOU HAVE TO DUPLICATE ITS ID HERE
266 public static bool IsValidWarning (int code)
268 int[] all_warnings = new int[] {
269 28, 67, 78, 105, 108, 109, 114, 192, 168, 169, 183, 184, 219, 251, 612, 618, 626, 628, 642, 649,
270 659, 660, 661, 672, 1030, 1522, 1616, 1691, 1692, 1901, 2002, 2023, 3012, 3019, 8024, 8028
273 foreach (int i in all_warnings) {
280 static public void LocationOfPreviousError (Location loc)
282 Console.Error.WriteLine (String.Format ("{0}({1}) (Location of symbol related to previous error)", loc.Name, loc.Row));
285 static public void RuntimeMissingSupport (Location loc, string feature)
287 Report.Error (-88, loc, "Your .NET Runtime does not support '{0}'. Please use the latest Mono runtime instead.", feature);
291 /// In most error cases is very useful to have information about symbol that caused the error.
292 /// Call this method before you call Report.Error when it makes sense.
294 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
296 SymbolRelatedToPreviousError (String.Format ("{0}({1})", loc.Name, loc.Row), symbol);
299 static public void SymbolRelatedToPreviousError (MemberInfo mi)
301 TypeContainer temp_ds = TypeManager.LookupTypeContainer (mi.DeclaringType);
302 if (temp_ds == null) {
303 SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
305 if (mi is MethodBase) {
306 IMethodData md = TypeManager.GetMethod ((MethodBase)mi);
307 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError (temp_ds));
311 MemberCore mc = temp_ds.GetDefinition (mi.Name);
312 SymbolRelatedToPreviousError (mc);
316 static public void SymbolRelatedToPreviousError (MemberCore mc)
318 SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
321 static public void SymbolRelatedToPreviousError (Type type)
323 if (type is TypeBuilder) {
324 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
325 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
326 } else if (type.HasElementType) {
327 SymbolRelatedToPreviousError (type.GetElementType ());
329 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
333 static void SymbolRelatedToPreviousError (string loc, string symbol)
335 extra_information.Add (String.Format ("{0}: '{1}' (name of symbol related to previous ", loc, symbol));
338 public static void ExtraInformation (Location loc, string msg)
340 extra_information.Add (String.Format ("{0}({1}) {2}", loc.Name, loc.Row, msg));
343 public static WarningRegions RegisterWarningRegion (Location location)
345 if (warning_regions_table == null)
346 warning_regions_table = new Hashtable ();
348 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
349 if (regions == null) {
350 regions = new WarningRegions ();
351 warning_regions_table.Add (location.Name, regions);
356 static public void Warning (int code, int level, Location loc, string format, params object[] args)
358 WarningMessage w = new WarningMessage (level);
359 w.Print (code, loc, String.Format (format, args));
362 static public void Warning (int code, Location loc, string format, params object[] args)
364 WarningMessage w = new WarningMessage ();
365 w.Print (code, loc, String.Format (format, args));
368 static public void Warning (int code, string format, params object[] args)
370 Warning (code, Location.Null, String.Format (format, args));
374 /// Did you test your WarningLevel, that you use this method
376 static public void Warning (int code, string text)
378 Warning (code, Location.Null, text);
381 static public void Error (int code, string format, params object[] args)
383 Error (code, Location.Null, String.Format (format, args));
386 static public void Error (int code, Location loc, string format, params object[] args)
388 ErrorMessage e = new ErrorMessage ();
389 e.Print (code, loc, String.Format (format, args));
392 static public void SetIgnoreWarning (int code)
394 if (warning_ignore_table == null)
395 warning_ignore_table = new Hashtable ();
397 warning_ignore_table [code] = true;
400 static public int ExpectedError {
402 expected_error = value;
405 return expected_error;
409 public static int DebugFlags = 0;
411 [Conditional ("MCS_DEBUG")]
412 static public void Debug (string message, params object[] args)
414 Debug (4, message, args);
417 [Conditional ("MCS_DEBUG")]
418 static public void Debug (int category, string message, params object[] args)
420 if ((category & DebugFlags) == 0)
423 StringBuilder sb = new StringBuilder (message);
425 if ((args != null) && (args.Length > 0)) {
429 foreach (object arg in args) {
436 else if (arg is ICollection)
437 sb.Append (PrintCollection ((ICollection) arg));
443 Console.WriteLine (sb.ToString ());
446 static public string PrintCollection (ICollection collection)
448 StringBuilder sb = new StringBuilder ();
450 sb.Append (collection.GetType ());
454 foreach (object o in collection) {
463 return sb.ToString ();
467 public enum TimerType {
477 public enum CounterType {
486 static DateTime[] timer_start;
487 static TimeSpan[] timers;
488 static long[] timer_counters;
489 static long[] counters;
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];
498 for (int i = 0; i < (int) TimerType.CountTimers; i++) {
499 timer_start [i] = DateTime.Now;
500 timers [i] = TimeSpan.Zero;
504 [Conditional("TIMER")]
505 static public void IncrementCounter (CounterType which)
507 ++counters [(int) which];
510 [Conditional("TIMER")]
511 static public void StartTimer (TimerType which)
513 timer_start [(int) which] = DateTime.Now;
516 [Conditional("TIMER")]
517 static public void StopTimer (TimerType which)
519 timers [(int) which] += DateTime.Now - timer_start [(int) which];
520 ++timer_counters [(int) which];
523 [Conditional("TIMER")]
524 static public void ShowTimers ()
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");
533 ShowCounter (CounterType.FindMembers, "- Find members");
534 ShowCounter (CounterType.MemberCache, "- Member cache");
535 ShowCounter (CounterType.MiscCounter, "- Misc counter");
538 static public void ShowCounter (CounterType which, string msg)
540 Console.WriteLine ("{0} {1}", counters [(int) which], msg);
543 static public void ShowTimer (TimerType which, string msg)
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]);
553 public class InternalErrorException : Exception {
554 public InternalErrorException ()
555 : base ("Internal error")
559 public InternalErrorException (string message)
566 /// Handles #pragma warning
568 public class WarningRegions {
570 abstract class PragmaCmd
574 protected PragmaCmd (int line)
579 public abstract bool IsEnabled (int code, bool previous);
582 class Disable: PragmaCmd
585 public Disable (int line, int code)
591 public override bool IsEnabled (int code, bool previous)
593 return this.code == code ? false : previous;
597 class DisableAll: PragmaCmd
599 public DisableAll (int line)
602 public override bool IsEnabled(int code, bool previous)
608 class Enable: PragmaCmd
611 public Enable (int line, int code)
617 public override bool IsEnabled(int code, bool previous)
619 return this.code == code ? true : previous;
623 class EnableAll: PragmaCmd
625 public EnableAll (int line)
628 public override bool IsEnabled(int code, bool previous)
635 ArrayList regions = new ArrayList ();
637 public void WarningDisable (int line)
639 regions.Add (new DisableAll (line));
642 public void WarningDisable (Location location, int code)
644 if (CheckWarningCode (code, location))
645 regions.Add (new Disable (location.Row, code));
648 public void WarningEnable (int line)
650 regions.Add (new EnableAll (line));
653 public void WarningEnable (Location location, int code)
655 if (CheckWarningCode (code, location))
656 regions.Add (new Enable (location.Row, code));
659 public bool IsWarningEnabled (int code, int src_line)
662 foreach (PragmaCmd pragma in regions) {
663 if (src_line < pragma.Line)
666 result = pragma.IsEnabled (code, result);
671 bool CheckWarningCode (int code, Location loc)
673 if (Report.IsValidWarning (code))
676 Report.Warning (1691, 1, loc, "'{0}' is not a valid warning number", code);