* Version.cs (CompareTo, Equals): Make sure the versions for
[mono-project.git] / mcs / gmcs / report.cs
blobd3a533c83498942f3e6dced42112ed51ccb1267a
1 //
2 // report.cs: report errors and warnings.
3 //
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 //
6 // (C) 2001 Ximian, Inc. (http://www.ximian.com)
7 //
9 //
10 // FIXME: currently our class library does not support custom number format strings
12 using System;
13 using System.Text;
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Diagnostics;
17 using System.Reflection;
19 namespace Mono.CSharp {
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;
30 /// <summary>
31 /// Warnings encountered so far
32 /// </summary>
33 static public int Warnings;
35 /// <summary>
36 /// Whether errors should be throw an exception
37 /// </summary>
38 static public bool Fatal;
40 /// <summary>
41 /// Whether warnings should be considered errors
42 /// </summary>
43 static public bool WarningsAreErrors;
45 /// <summary>
46 /// Whether to dump a stack trace on errors.
47 /// </summary>
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;
65 /// <summary>
66 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
67 /// </summary>
68 static StringCollection extra_information = new StringCollection ();
70 abstract class AbstractMessage {
72 static void Check (int code)
74 if (code == expected_error) {
75 Environment.Exit (0);
79 public abstract bool IsWarning { get; }
81 public abstract string MessageType { get; }
83 public virtual void Print (int code, string location, string text)
85 if (code < 0)
86 code = 8000-code;
88 StringBuilder msg = new StringBuilder ();
89 if (location.Length != 0) {
90 msg.Append (location);
91 msg.Append (' ');
93 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
94 Console.Error.WriteLine (msg.ToString ());
96 foreach (string s in extra_information)
97 Console.Error.WriteLine (s + MessageType);
99 extra_information.Clear ();
101 if (Stacktrace)
102 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
104 if (Fatal) {
105 if (!IsWarning || WarningsAreErrors)
106 throw new Exception (text);
109 Check (code);
112 public virtual void Print (int code, Location location, string text)
114 if (location.Equals (Location.Null)) {
115 Print (code, "", text);
116 return;
118 Print (code, String.Format ("{0}({1})", location.Name, location.Row), text);
122 sealed class WarningMessage: AbstractMessage {
123 Location loc = Location.Null;
124 readonly int Level;
126 public WarningMessage ():
127 this (-1) {}
129 public WarningMessage (int level)
131 Level = level;
134 public override bool IsWarning {
135 get { return true; }
138 bool IsEnabled (int code)
140 if (RootContext.WarningLevel < Level)
141 return false;
143 if (warning_ignore_table != null) {
144 if (warning_ignore_table.Contains (code)) {
145 return false;
149 if (warning_regions_table == null || loc.Equals (Location.Null))
150 return true;
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 extra_information.Clear ();
160 return;
163 if (WarningsAreErrors) {
164 new ErrorMessage ().Print (code, location, text);
165 return;
168 Warnings++;
169 base.Print (code, location, text);
172 public override void Print(int code, Location location, string text)
174 loc = location;
175 base.Print (code, location, text);
178 public override string MessageType {
179 get {
180 return "warning";
185 sealed class ErrorMessage: AbstractMessage {
187 public override void Print(int code, string location, string text)
189 Errors++;
190 base.Print (code, location, text);
193 public override bool IsWarning {
194 get { return false; }
197 public override string MessageType {
198 get {
199 return "error";
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))
226 continue;
228 foundUserCode = true;
230 sb.Append ("\tin ");
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);
237 bool first = true;
238 foreach (ParameterInfo pi in mb.GetParameters ()) {
239 if (!first)
240 sb.Append (", ");
241 first = false;
243 sb.Append (TypeManager.CSharpName (pi.ParameterType));
245 sb.Append (")\n");
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) {
262 if (i == code)
263 return true;
265 return false;
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);
278 /// <summary>
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.
281 /// </summary>
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.LookupGenericTypeContainer (mi.DeclaringType);
290 if (temp_ds == null) {
291 SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
292 } else {
293 MethodBase mb = mi as MethodBase;
294 if (mb != null) {
295 while (mb.Mono_IsInflatedMethod)
296 mb = mb.GetGenericMethodDefinition ();
297 IMethodData md = TypeManager.GetMethod (mb);
298 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError (temp_ds));
299 return;
302 string name = String.Concat (temp_ds.Name, ".", mi.Name);
303 MemberCore mc = temp_ds.GetDefinition (name);
304 SymbolRelatedToPreviousError (mc);
308 static public void SymbolRelatedToPreviousError (MemberCore mc)
310 SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
313 static public void SymbolRelatedToPreviousError (Type type)
315 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
316 if (temp_ds == null)
317 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
318 else
319 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
322 static void SymbolRelatedToPreviousError (string loc, string symbol)
324 extra_information.Add (String.Format ("{0}: '{1}' (name of symbol related to previous ", loc, symbol));
327 public static void ExtraInformation (Location loc, string msg)
329 extra_information.Add (String.Format ("{0}({1}) {2}", loc.Name, loc.Row, msg));
332 public static WarningRegions RegisterWarningRegion (Location location)
334 if (warning_regions_table == null)
335 warning_regions_table = new Hashtable ();
337 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
338 if (regions == null) {
339 regions = new WarningRegions ();
340 warning_regions_table.Add (location.Name, regions);
342 return regions;
345 static public void Warning (int code, int level, Location loc, string format, params object[] args)
347 WarningMessage w = new WarningMessage (level);
348 w.Print (code, loc, String.Format (format, args));
351 static public void Warning (int code, Location loc, string format, params object[] args)
353 WarningMessage w = new WarningMessage ();
354 w.Print (code, loc, String.Format (format, args));
357 static public void Warning (int code, string format, params object[] args)
359 Warning (code, Location.Null, String.Format (format, args));
362 /// <summary>
363 /// Did you test your WarningLevel, that you use this method
364 /// </summary>
365 static public void Warning (int code, string text)
367 Warning (code, Location.Null, text);
370 static public void Error (int code, string format, params object[] args)
372 Error (code, Location.Null, String.Format (format, args));
375 static public void Error (int code, Location loc, string format, params object[] args)
377 ErrorMessage e = new ErrorMessage ();
378 e.Print (code, loc, String.Format (format, args));
381 static public void SetIgnoreWarning (int code)
383 if (warning_ignore_table == null)
384 warning_ignore_table = new Hashtable ();
386 warning_ignore_table [code] = true;
389 static public int ExpectedError {
390 set {
391 expected_error = value;
393 get {
394 return expected_error;
398 public static int DebugFlags = 0;
400 [Conditional ("MCS_DEBUG")]
401 static public void Debug (string message, params object[] args)
403 Debug (4, message, args);
406 [Conditional ("MCS_DEBUG")]
407 static public void Debug (int category, string message, params object[] args)
409 if ((category & DebugFlags) == 0)
410 return;
412 StringBuilder sb = new StringBuilder (message);
414 if ((args != null) && (args.Length > 0)) {
415 sb.Append (": ");
417 bool first = true;
418 foreach (object arg in args) {
419 if (first)
420 first = false;
421 else
422 sb.Append (", ");
423 if (arg == null)
424 sb.Append ("null");
425 else if (arg is ICollection)
426 sb.Append (PrintCollection ((ICollection) arg));
427 else
428 sb.Append (arg);
432 Console.WriteLine (sb.ToString ());
435 static public string PrintCollection (ICollection collection)
437 StringBuilder sb = new StringBuilder ();
439 sb.Append (collection.GetType ());
440 sb.Append ("(");
442 bool first = true;
443 foreach (object o in collection) {
444 if (first)
445 first = false;
446 else
447 sb.Append (", ");
448 sb.Append (o);
451 sb.Append (")");
452 return sb.ToString ();
456 public enum TimerType {
457 FindMembers = 0,
458 TcFindMembers = 1,
459 MemberLookup = 2,
460 CachedLookup = 3,
461 CacheInit = 4,
462 MiscTimer = 5,
463 CountTimers = 6
466 public enum CounterType {
467 FindMembers = 0,
468 MemberCache = 1,
469 MiscCounter = 2,
470 CountCounters = 3
473 public class Timer
475 static DateTime[] timer_start;
476 static TimeSpan[] timers;
477 static long[] timer_counters;
478 static long[] counters;
480 static Timer ()
482 timer_start = new DateTime [(int) TimerType.CountTimers];
483 timers = new TimeSpan [(int) TimerType.CountTimers];
484 timer_counters = new long [(int) TimerType.CountTimers];
485 counters = new long [(int) CounterType.CountCounters];
487 for (int i = 0; i < (int) TimerType.CountTimers; i++) {
488 timer_start [i] = DateTime.Now;
489 timers [i] = TimeSpan.Zero;
493 [Conditional("TIMER")]
494 static public void IncrementCounter (CounterType which)
496 ++counters [(int) which];
499 [Conditional("TIMER")]
500 static public void StartTimer (TimerType which)
502 timer_start [(int) which] = DateTime.Now;
505 [Conditional("TIMER")]
506 static public void StopTimer (TimerType which)
508 timers [(int) which] += DateTime.Now - timer_start [(int) which];
509 ++timer_counters [(int) which];
512 [Conditional("TIMER")]
513 static public void ShowTimers ()
515 ShowTimer (TimerType.FindMembers, "- FindMembers timer");
516 ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
517 ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
518 ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
519 ShowTimer (TimerType.CacheInit, "- Cache init");
520 ShowTimer (TimerType.MiscTimer, "- Misc timer");
522 ShowCounter (CounterType.FindMembers, "- Find members");
523 ShowCounter (CounterType.MemberCache, "- Member cache");
524 ShowCounter (CounterType.MiscCounter, "- Misc counter");
527 static public void ShowCounter (CounterType which, string msg)
529 Console.WriteLine ("{0} {1}", counters [(int) which], msg);
532 static public void ShowTimer (TimerType which, string msg)
534 Console.WriteLine (
535 "[{0:00}:{1:000}] {2} (used {3} times)",
536 (int) timers [(int) which].TotalSeconds,
537 timers [(int) which].Milliseconds, msg,
538 timer_counters [(int) which]);
542 public class InternalErrorException : Exception {
543 public InternalErrorException ()
544 : base ("Internal error")
548 public InternalErrorException (string message)
549 : base (message)
554 /// <summary>
555 /// Handles #pragma warning
556 /// </summary>
557 public class WarningRegions {
559 abstract class PragmaCmd
561 public int Line;
563 protected PragmaCmd (int line)
565 Line = line;
568 public abstract bool IsEnabled (int code, bool previous);
571 class Disable: PragmaCmd
573 int code;
574 public Disable (int line, int code)
575 : base (line)
577 this.code = code;
580 public override bool IsEnabled (int code, bool previous)
582 return this.code == code ? false : previous;
586 class DisableAll: PragmaCmd
588 public DisableAll (int line)
589 : base (line) {}
591 public override bool IsEnabled(int code, bool previous)
593 return false;
597 class Enable: PragmaCmd
599 int code;
600 public Enable (int line, int code)
601 : base (line)
603 this.code = code;
606 public override bool IsEnabled(int code, bool previous)
608 return this.code == code ? true : previous;
612 class EnableAll: PragmaCmd
614 public EnableAll (int line)
615 : base (line) {}
617 public override bool IsEnabled(int code, bool previous)
619 return true;
624 ArrayList regions = new ArrayList ();
626 public void WarningDisable (int line)
628 regions.Add (new DisableAll (line));
631 public void WarningDisable (Location location, int code)
633 if (CheckWarningCode (code, location))
634 regions.Add (new Disable (location.Row, code));
637 public void WarningEnable (int line)
639 regions.Add (new EnableAll (line));
642 public void WarningEnable (Location location, int code)
644 if (CheckWarningCode (code, location))
645 regions.Add (new Enable (location.Row, code));
648 public bool IsWarningEnabled (int code, int src_line)
650 bool result = true;
651 foreach (PragmaCmd pragma in regions) {
652 if (src_line < pragma.Line)
653 break;
655 result = pragma.IsEnabled (code, result);
657 return result;
660 bool CheckWarningCode (int code, Location loc)
662 if (Report.IsValidWarning (code))
663 return true;
665 Report.Warning (1691, 1, loc, "'{0}' is not a valid warning number", code);
666 return false;