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;
19 namespace Mono.CSharp {
22 /// This class is used to report errors and warnings t te user.
26 /// Errors encountered so far
28 static public int Errors;
31 /// Warnings encountered so far
33 static public int Warnings;
36 /// Whether errors should be throw an exception
38 static public bool Fatal;
41 /// Whether warnings should be considered errors
43 static public bool WarningsAreErrors;
46 /// Whether to dump a stack trace on errors.
48 static public bool Stacktrace;
51 // If the 'expected' error code is reported then the
52 // compilation succeeds.
54 // Used for the test suite to excercise the error codes
56 static int expected_error = 0;
59 // Keeps track of the warnings that we are ignoring
61 static Hashtable warning_ignore_table;
63 static Hashtable warning_regions_table;
66 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
68 static StringCollection related_symbols = new StringCollection ();
70 abstract class AbstractMessage {
72 static void Check (int code)
74 if (code == expected_error) {
79 public abstract bool IsWarning { get; }
81 public abstract string MessageType { get; }
83 public virtual void Print (int code, string location, string text)
88 StringBuilder msg = new StringBuilder ();
89 if (location.Length != 0) {
90 msg.Append (location);
93 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
94 Console.Error.WriteLine (msg.ToString ());
96 foreach (string s in related_symbols) {
97 Console.Error.WriteLine (String.Concat (s, MessageType, ')'));
99 related_symbols.Clear ();
102 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
105 if (!IsWarning || WarningsAreErrors)
106 throw new Exception (text);
112 public virtual void Print (int code, Location location, string text)
114 if (location.Equals (Location.Null)) {
115 Print (code, "", text);
118 Print (code, String.Format ("{0}({1})", location.Name, location.Row), text);
122 sealed class WarningMessage: AbstractMessage {
123 Location loc = Location.Null;
126 public WarningMessage ():
129 public WarningMessage (int level)
134 public override bool IsWarning {
138 bool IsEnabled (int code)
140 if (RootContext.WarningLevel < Level)
143 if (warning_ignore_table != null) {
144 if (warning_ignore_table.Contains (code)) {
149 if (warning_regions_table == null || loc.Equals (Location.Null))
152 WarningRegions regions = (WarningRegions)warning_regions_table [loc.Name];
153 return regions.IsWarningEnabled (code, loc.Row);
156 public override void Print(int code, string location, string text)
158 if (!IsEnabled (code)) {
159 related_symbols.Clear ();
163 if (WarningsAreErrors) {
164 new ErrorMessage ().Print (code, location, text);
169 base.Print (code, location, text);
172 public override void Print(int code, Location location, string text)
175 base.Print (code, location, text);
178 public override string MessageType {
185 sealed class ErrorMessage: AbstractMessage {
187 public override void Print(int code, string location, string text)
190 base.Print (code, location, text);
193 public override bool IsWarning {
194 get { return false; }
197 public override string MessageType {
205 public static void FeatureIsNotStandardized (Location loc, string feature)
207 Report.Error (1644, loc, "Feature '{0}' cannot be used because it is not part of the standardized ISO C# language specification", feature);
210 public static string FriendlyStackTrace (Exception e)
212 return FriendlyStackTrace (new StackTrace (e, true));
215 static string FriendlyStackTrace (StackTrace t)
217 StringBuilder sb = new StringBuilder ();
219 bool foundUserCode = false;
221 for (int i = 0; i < t.FrameCount; i++) {
222 StackFrame f = t.GetFrame (i);
223 MethodBase mb = f.GetMethod ();
225 if (!foundUserCode && mb.ReflectedType == typeof (Report))
228 foundUserCode = true;
232 if (f.GetFileLineNumber () > 0)
233 sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
235 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
238 foreach (ParameterInfo pi in mb.GetParameters ()) {
243 sb.Append (TypeManager.CSharpName (pi.ParameterType));
248 return sb.ToString ();
251 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
252 // IF YOU ADD A NEW WARNING YOU HAVE TO DUPLICATE ITS ID HERE
254 public static bool IsValidWarning (int code)
256 int[] all_warnings = new int[] {
257 28, 67, 78, 105, 108, 109, 114, 192, 168, 169, 183, 184, 219, 251, 612, 618, 626, 628, 642, 649,
258 659, 660, 661, 672, 1030, 1522, 1616, 1691, 1692, 1901, 2002, 2023, 3012, 3019, 8024, 8028
261 foreach (int i in all_warnings) {
268 static public void LocationOfPreviousError (Location loc)
270 Console.Error.WriteLine (String.Format ("{0}({1}) (Location of symbol related to previous error)", loc.Name, loc.Row));
273 static public void RuntimeMissingSupport (Location loc, string feature)
275 Report.Error (-88, loc, "Your .NET Runtime does not support '{0}'. Please use the latest Mono runtime instead.", feature);
279 /// In most error cases is very useful to have information about symbol that caused the error.
280 /// Call this method before you call Report.Error when it makes sense.
282 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
284 SymbolRelatedToPreviousError (String.Format ("{0}({1})", loc.Name, loc.Row), symbol);
287 static public void SymbolRelatedToPreviousError (MemberInfo mi)
289 TypeContainer temp_ds = TypeManager.LookupTypeContainer (mi.DeclaringType);
290 if (temp_ds == null) {
291 SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
293 if (mi is MethodBase) {
294 IMethodData md = TypeManager.GetMethod ((MethodBase)mi);
295 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError (temp_ds));
299 string name = String.Concat (temp_ds.Name, ".", mi.Name);
300 MemberCore mc = temp_ds.GetDefinition (name);
301 SymbolRelatedToPreviousError (mc);
305 static public void SymbolRelatedToPreviousError (MemberCore mc)
307 SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
310 static public void SymbolRelatedToPreviousError (Type type)
312 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
314 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
316 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
319 static void SymbolRelatedToPreviousError (string loc, string symbol)
321 related_symbols.Add (String.Format ("{0}: '{1}' (name of symbol related to previous ", loc, symbol));
324 public static WarningRegions RegisterWarningRegion (Location location)
326 if (warning_regions_table == null)
327 warning_regions_table = new Hashtable ();
329 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
330 if (regions == null) {
331 regions = new WarningRegions ();
332 warning_regions_table.Add (location.Name, regions);
337 static public void Warning (int code, int level, Location loc, string format, params object[] args)
339 WarningMessage w = new WarningMessage (level);
340 w.Print (code, loc, String.Format (format, args));
343 static public void Warning (int code, Location loc, string format, params object[] args)
345 WarningMessage w = new WarningMessage ();
346 w.Print (code, loc, String.Format (format, args));
349 static public void Warning (int code, string format, params object[] args)
351 Warning (code, Location.Null, String.Format (format, args));
355 /// Did you test your WarningLevel, that you use this method
357 static public void Warning (int code, string text)
359 Warning (code, Location.Null, text);
362 static public void Error (int code, string format, params object[] args)
364 Error (code, Location.Null, String.Format (format, args));
367 static public void Error (int code, Location loc, string format, params object[] args)
369 ErrorMessage e = new ErrorMessage ();
370 e.Print (code, loc, String.Format (format, args));
373 static public void SetIgnoreWarning (int code)
375 if (warning_ignore_table == null)
376 warning_ignore_table = new Hashtable ();
378 warning_ignore_table [code] = true;
381 static public int ExpectedError {
383 expected_error = value;
386 return expected_error;
390 public static int DebugFlags = 0;
392 [Conditional ("MCS_DEBUG")]
393 static public void Debug (string message, params object[] args)
395 Debug (4, message, args);
398 [Conditional ("MCS_DEBUG")]
399 static public void Debug (int category, string message, params object[] args)
401 if ((category & DebugFlags) == 0)
404 StringBuilder sb = new StringBuilder (message);
406 if ((args != null) && (args.Length > 0)) {
410 foreach (object arg in args) {
417 else if (arg is ICollection)
418 sb.Append (PrintCollection ((ICollection) arg));
424 Console.WriteLine (sb.ToString ());
427 static public string PrintCollection (ICollection collection)
429 StringBuilder sb = new StringBuilder ();
431 sb.Append (collection.GetType ());
435 foreach (object o in collection) {
444 return sb.ToString ();
448 public enum TimerType {
458 public enum CounterType {
467 static DateTime[] timer_start;
468 static TimeSpan[] timers;
469 static long[] timer_counters;
470 static long[] counters;
474 timer_start = new DateTime [(int) TimerType.CountTimers];
475 timers = new TimeSpan [(int) TimerType.CountTimers];
476 timer_counters = new long [(int) TimerType.CountTimers];
477 counters = new long [(int) CounterType.CountCounters];
479 for (int i = 0; i < (int) TimerType.CountTimers; i++) {
480 timer_start [i] = DateTime.Now;
481 timers [i] = TimeSpan.Zero;
485 [Conditional("TIMER")]
486 static public void IncrementCounter (CounterType which)
488 ++counters [(int) which];
491 [Conditional("TIMER")]
492 static public void StartTimer (TimerType which)
494 timer_start [(int) which] = DateTime.Now;
497 [Conditional("TIMER")]
498 static public void StopTimer (TimerType which)
500 timers [(int) which] += DateTime.Now - timer_start [(int) which];
501 ++timer_counters [(int) which];
504 [Conditional("TIMER")]
505 static public void ShowTimers ()
507 ShowTimer (TimerType.FindMembers, "- FindMembers timer");
508 ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
509 ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
510 ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
511 ShowTimer (TimerType.CacheInit, "- Cache init");
512 ShowTimer (TimerType.MiscTimer, "- Misc timer");
514 ShowCounter (CounterType.FindMembers, "- Find members");
515 ShowCounter (CounterType.MemberCache, "- Member cache");
516 ShowCounter (CounterType.MiscCounter, "- Misc counter");
519 static public void ShowCounter (CounterType which, string msg)
521 Console.WriteLine ("{0} {1}", counters [(int) which], msg);
524 static public void ShowTimer (TimerType which, string msg)
527 "[{0:00}:{1:000}] {2} (used {3} times)",
528 (int) timers [(int) which].TotalSeconds,
529 timers [(int) which].Milliseconds, msg,
530 timer_counters [(int) which]);
534 public class InternalErrorException : Exception {
535 public InternalErrorException ()
536 : base ("Internal error")
540 public InternalErrorException (string message)
547 /// Handles #pragma warning
549 public class WarningRegions {
551 abstract class PragmaCmd
555 protected PragmaCmd (int line)
560 public abstract bool IsEnabled (int code, bool previous);
563 class Disable: PragmaCmd
566 public Disable (int line, int code)
572 public override bool IsEnabled (int code, bool previous)
574 return this.code == code ? false : previous;
578 class DisableAll: PragmaCmd
580 public DisableAll (int line)
583 public override bool IsEnabled(int code, bool previous)
589 class Enable: PragmaCmd
592 public Enable (int line, int code)
598 public override bool IsEnabled(int code, bool previous)
600 return this.code == code ? true : previous;
604 class EnableAll: PragmaCmd
606 public EnableAll (int line)
609 public override bool IsEnabled(int code, bool previous)
616 ArrayList regions = new ArrayList ();
618 public void WarningDisable (int line)
620 regions.Add (new DisableAll (line));
623 public void WarningDisable (Location location, int code)
625 if (CheckWarningCode (code, location))
626 regions.Add (new Disable (location.Row, code));
629 public void WarningEnable (int line)
631 regions.Add (new EnableAll (line));
634 public void WarningEnable (Location location, int code)
636 if (CheckWarningCode (code, location))
637 regions.Add (new Enable (location.Row, code));
640 public bool IsWarningEnabled (int code, int src_line)
643 foreach (PragmaCmd pragma in regions) {
644 if (src_line < pragma.Line)
647 result = pragma.IsEnabled (code, result);
652 bool CheckWarningCode (int code, Location loc)
654 if (Report.IsValidWarning (code))
657 Report.Warning (1691, 1, loc, "'{0}' is not a valid warning number", code);