2 // report.cs: report errors and warnings.
4 // Author: Miguel de Icaza (miguel@ximian.com)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Copyright 2001 Ximian, Inc. (http://www.ximian.com)
13 using System.Collections;
14 using System.Collections.Specialized;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
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;
47 /// Whether to dump a stack trace on errors.
49 static public bool Stacktrace;
51 static public TextWriter Stderr = Console.Error;
54 // If the 'expected' error code is reported then the
55 // compilation succeeds.
57 // Used for the test suite to excercise the error codes
59 static int expected_error = 0;
62 // Keeps track of the warnings that we are ignoring
64 public static Hashtable warning_ignore_table;
66 static Hashtable warning_regions_table;
69 // This is used to save/restore the error state. When the
70 // error stack contains elements, warnings and errors are not
71 // reported to the user. This is used by the Lambda expression
72 // support to compile the code with various parameter values.
73 // A stack because of `Report.Errors == errors;'
75 static Stack error_stack;
76 static Stack warning_stack;
77 static bool reporting_disabled;
79 static int warning_level;
82 /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
84 static ArrayList extra_information = new ArrayList ();
87 // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
89 public static readonly int[] AllWarnings = new int[] {
91 105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
92 219, 251, 252, 253, 278, 282,
93 419, 420, 429, 436, 440, 465, 467, 469, 472,
94 612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675,
97 1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
98 1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692,
102 3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009,
103 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019,
104 3021, 3022, 3023, 3026, 3027,
106 402, 414, 458, 464, 693, 1058, 1700, 3024
112 // Just to be sure that binary search is working
113 Array.Sort (AllWarnings);
116 public static void Reset ()
118 Errors = Warnings = 0;
119 WarningsAreErrors = false;
120 warning_ignore_table = null;
121 warning_regions_table = null;
122 reporting_disabled = false;
123 error_stack = warning_stack = null;
126 public static void DisableReporting ()
128 if (error_stack == null)
129 error_stack = new Stack ();
130 error_stack.Push (Errors);
133 if (warning_stack == null)
134 warning_stack = new Stack ();
135 warning_stack.Push (Warnings);
138 reporting_disabled = true;
141 public static void EnableReporting ()
143 if (warning_stack != null && warning_stack.Count > 0)
144 Warnings = (int) warning_stack.Pop ();
148 Errors = (int) error_stack.Pop ();
149 if (error_stack.Count == 0) {
150 reporting_disabled = false;
154 public static IMessageRecorder msg_recorder;
156 public static IMessageRecorder SetMessageRecorder (IMessageRecorder recorder)
158 IMessageRecorder previous = msg_recorder;
159 msg_recorder = recorder;
163 public interface IMessageRecorder
165 bool IsEmpty { get; }
167 void AddMessage (AbstractMessage msg);
168 bool PrintMessages ();
172 // Default message recorder, it uses two types of message groups.
173 // Common messages: messages reported in all sessions.
174 // Merged messages: union of all messages in all sessions.
176 public struct MessageRecorder : IMessageRecorder
178 ArrayList session_messages;
180 // A collection of exactly same messages reported in all sessions
182 ArrayList common_messages;
185 // A collection of unique messages reported in all sessions
187 ArrayList merged_messages;
189 public void EndSession ()
191 if (session_messages == null)
195 // Handles the first session
197 if (common_messages == null) {
198 common_messages = new ArrayList (session_messages);
199 merged_messages = session_messages;
200 session_messages = null;
205 // Store common messages if any
207 for (int i = 0; i < common_messages.Count; ++i) {
208 AbstractMessage cmsg = (AbstractMessage) common_messages [i];
209 bool common_msg_found = false;
210 foreach (AbstractMessage msg in session_messages) {
211 if (cmsg.Equals (msg)) {
212 common_msg_found = true;
217 if (!common_msg_found)
218 common_messages.RemoveAt (i);
222 // Merge session and previous messages
224 for (int i = 0; i < session_messages.Count; ++i) {
225 AbstractMessage msg = (AbstractMessage) session_messages [i];
226 bool msg_found = false;
227 for (int ii = 0; ii < merged_messages.Count; ++ii) {
228 if (msg.Equals (merged_messages [ii])) {
235 merged_messages.Add (msg);
239 public void AddMessage (AbstractMessage msg)
241 if (session_messages == null)
242 session_messages = new ArrayList ();
244 session_messages.Add (msg);
247 public bool IsEmpty {
249 return merged_messages == null && common_messages == null;
254 // Prints collected messages, common messages have a priority
256 public bool PrintMessages ()
258 ArrayList messages_to_print = merged_messages;
259 if (common_messages != null && common_messages.Count > 0) {
260 messages_to_print = common_messages;
263 if (messages_to_print == null)
266 foreach (AbstractMessage msg in messages_to_print)
273 public abstract class AbstractMessage
275 readonly string[] extra_info;
276 protected readonly int code;
277 protected readonly Location location;
278 readonly string message;
280 protected AbstractMessage (int code, Location loc, string msg, ArrayList extraInfo)
284 this.code = 8000 - code;
288 if (extraInfo.Count != 0) {
289 this.extra_info = (string[])extraInfo.ToArray (typeof (string));
293 protected AbstractMessage (AbstractMessage aMsg)
295 this.code = aMsg.code;
296 this.location = aMsg.location;
297 this.message = aMsg.message;
298 this.extra_info = aMsg.extra_info;
301 static void Check (int code)
303 if (code == expected_error) {
304 Environment.Exit (0);
308 public override bool Equals (object obj)
310 AbstractMessage msg = obj as AbstractMessage;
314 return code == msg.code && location.Equals (msg.location) && message == msg.message;
317 public override int GetHashCode ()
319 return code.GetHashCode ();
322 public abstract bool IsWarning { get; }
324 public abstract string MessageType { get; }
326 public virtual void Print ()
328 if (msg_recorder != null) {
330 // This line is useful when debugging messages recorder
332 // Console.WriteLine ("RECORDING: {0} {1} {2}", code, location, message);
333 msg_recorder.AddMessage (this);
337 if (reporting_disabled)
340 StringBuilder msg = new StringBuilder ();
341 if (!location.IsNull) {
342 msg.Append (location.ToString ());
345 msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, message);
349 if (Stderr == Console.Error)
350 Stderr.WriteLine (ColorFormat (msg.ToString ()));
352 Stderr.WriteLine (msg.ToString ());
354 if (extra_info != null) {
355 foreach (string s in extra_info)
356 Stderr.WriteLine (s + MessageType + ")");
360 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
363 if (!IsWarning || WarningsAreErrors)
364 throw new Exception (message);
370 protected virtual string ColorFormat (string s)
376 sealed class WarningMessage : AbstractMessage
380 public WarningMessage (int code, int level, Location loc, string message, ArrayList extra_info)
381 : base (code, loc, message, extra_info)
386 public override bool IsWarning {
392 if (WarningLevel < Level)
395 if (warning_ignore_table != null) {
396 if (warning_ignore_table.Contains (code)) {
401 if (warning_regions_table == null || location.IsNull)
404 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
408 return regions.IsWarningEnabled (code, location.Row);
411 public override void Print ()
416 if (WarningsAreErrors) {
417 new ErrorMessage (this).Print ();
425 public override string MessageType {
432 static int NameToCode (string s)
457 // maps a color name to its xterm color code
459 static string GetForeground (string s)
463 if (s.StartsWith ("bright")){
469 return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m";
472 static string GetBackground (string s)
474 return "\x001b[" + (40 + NameToCode (s)).ToString () + "m";
477 sealed class ErrorMessage : AbstractMessage
479 static string prefix, postfix;
481 [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
482 extern static int _isatty (int fd);
484 static bool isatty (int fd)
487 return _isatty (fd) == 1;
493 static ErrorMessage ()
495 string term = Environment.GetEnvironmentVariable ("TERM");
496 bool xterm_colors = false;
502 if (Environment.GetEnvironmentVariable ("COLORTERM") != null){
514 if (!(isatty (1) && isatty (2)))
517 string config = Environment.GetEnvironmentVariable ("MCS_COLORS");
519 config = "errors=red";
520 //config = "brightwhite,red";
523 if (config == "disable")
526 if (!config.StartsWith ("errors="))
529 config = config.Substring (7);
531 int p = config.IndexOf (",");
533 prefix = GetForeground (config);
535 prefix = GetBackground (config.Substring (p+1)) + GetForeground (config.Substring (0, p));
536 postfix = "\x001b[0m";
539 public ErrorMessage (int code, Location loc, string message, ArrayList extraInfo)
540 : base (code, loc, message, extraInfo)
544 public ErrorMessage (AbstractMessage aMsg)
549 protected override string ColorFormat (string s)
552 return prefix + s + postfix;
556 public override void Print()
562 public override bool IsWarning {
563 get { return false; }
566 public override string MessageType {
573 public static void FeatureIsNotAvailable (Location loc, string feature)
576 switch (RootContext.Version) {
577 case LanguageVersion.ISO_1:
580 case LanguageVersion.ISO_2:
583 case LanguageVersion.Default_MCS:
584 Report.Error (1644, loc, "Feature `{0}' is not available in Mono mcs1 compiler. Consider using the `gmcs' compiler instead",
588 throw new InternalErrorException ("Invalid feature version", RootContext.Version);
591 Report.Error (1644, loc,
592 "Feature `{0}' cannot be used because it is not part of the C# {1} language specification",
596 public static string FriendlyStackTrace (Exception e)
598 return FriendlyStackTrace (new StackTrace (e, true));
601 static string FriendlyStackTrace (StackTrace t)
603 StringBuilder sb = new StringBuilder ();
605 bool foundUserCode = false;
607 for (int i = 0; i < t.FrameCount; i++) {
608 StackFrame f = t.GetFrame (i);
609 MethodBase mb = f.GetMethod ();
611 if (!foundUserCode && mb.ReflectedType == typeof (Report))
614 foundUserCode = true;
618 if (f.GetFileLineNumber () > 0)
619 sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
621 sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
624 foreach (ParameterInfo pi in mb.GetParameters ()) {
629 sb.Append (TypeManager.CSharpName (pi.ParameterType));
634 return sb.ToString ();
637 public static void StackTrace ()
639 Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
642 public static bool IsValidWarning (int code)
644 return Array.BinarySearch (AllWarnings, code) >= 0;
647 static public void RuntimeMissingSupport (Location loc, string feature)
649 Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
653 /// In most error cases is very useful to have information about symbol that caused the error.
654 /// Call this method before you call Report.Error when it makes sense.
656 static public void SymbolRelatedToPreviousError (Location loc, string symbol)
658 SymbolRelatedToPreviousError (loc.ToString (), symbol);
661 static public void SymbolRelatedToPreviousError (MemberInfo mi)
663 if (reporting_disabled)
666 Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType);
667 if (TypeManager.IsDelegateType (dt)) {
668 SymbolRelatedToPreviousError (dt);
672 DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt);
673 if (temp_ds == null) {
674 SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi));
676 MethodBase mb = mi as MethodBase;
678 mb = TypeManager.DropGenericMethodArguments (mb);
679 IMethodData md = TypeManager.GetMethod (mb);
680 SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
684 MemberCore mc = temp_ds.GetDefinition (mi.Name);
685 SymbolRelatedToPreviousError (mc);
689 static public void SymbolRelatedToPreviousError (MemberCore mc)
691 SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
694 static public void SymbolRelatedToPreviousError (Type type)
696 if (reporting_disabled)
699 type = TypeManager.DropGenericTypeArguments (type);
701 if (TypeManager.IsGenericParameter (type)) {
702 TypeParameter tp = TypeManager.LookupTypeParameter (type);
704 SymbolRelatedToPreviousError (tp.Location, "");
709 if (type is TypeBuilder) {
710 DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
711 SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
712 } else if (TypeManager.HasElementType (type)) {
713 SymbolRelatedToPreviousError (type.GetElementType ());
715 SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
719 static void SymbolRelatedToPreviousError (string loc, string symbol)
721 extra_information.Add (String.Format ("{0} (Location of the symbol related to previous ", loc));
724 public static void ExtraInformation (Location loc, string msg)
726 extra_information.Add (String.Format ("{0} {1}", loc, msg));
729 public static WarningRegions RegisterWarningRegion (Location location)
731 if (warning_regions_table == null)
732 warning_regions_table = new Hashtable ();
734 WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
735 if (regions == null) {
736 regions = new WarningRegions ();
737 warning_regions_table.Add (location.Name, regions);
742 static public void Warning (int code, int level, Location loc, string message)
744 WarningMessage w = new WarningMessage (code, level, loc, message, extra_information);
745 extra_information.Clear ();
749 static public void Warning (int code, int level, Location loc, string format, string arg)
751 WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg), extra_information);
752 extra_information.Clear ();
756 static public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
758 WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg1, arg2), extra_information);
759 extra_information.Clear ();
763 static public void Warning (int code, int level, Location loc, string format, params object[] args)
765 WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, args), extra_information);
766 extra_information.Clear ();
770 static public void Warning (int code, int level, string message)
772 Warning (code, level, Location.Null, message);
775 static public void Warning (int code, int level, string format, string arg)
777 Warning (code, level, Location.Null, format, arg);
780 static public void Warning (int code, int level, string format, string arg1, string arg2)
782 Warning (code, level, Location.Null, format, arg1, arg2);
785 static public void Warning (int code, int level, string format, params string[] args)
787 Warning (code, level, Location.Null, String.Format (format, args));
790 static public void Error (int code, Location loc, string error)
792 new ErrorMessage (code, loc, error, extra_information).Print ();
793 extra_information.Clear ();
796 static public void Error (int code, Location loc, string format, string arg)
798 new ErrorMessage (code, loc, String.Format (format, arg), extra_information).Print ();
799 extra_information.Clear ();
802 static public void Error (int code, Location loc, string format, string arg1, string arg2)
804 new ErrorMessage (code, loc, String.Format (format, arg1, arg2), extra_information).Print ();
805 extra_information.Clear ();
808 static public void Error (int code, Location loc, string format, params object[] args)
810 Error (code, loc, String.Format (format, args));
813 static public void Error (int code, string error)
815 Error (code, Location.Null, error);
818 static public void Error (int code, string format, string arg)
820 Error (code, Location.Null, format, arg);
823 static public void Error (int code, string format, string arg1, string arg2)
825 Error (code, Location.Null, format, arg1, arg2);
828 static public void Error (int code, string format, params string[] args)
830 Error (code, Location.Null, String.Format (format, args));
833 static public void SetIgnoreWarning (int code)
835 if (warning_ignore_table == null)
836 warning_ignore_table = new Hashtable ();
838 warning_ignore_table [code] = true;
841 static public int ExpectedError {
843 expected_error = value;
846 return expected_error;
850 public static int WarningLevel {
852 return warning_level;
855 warning_level = value;
859 public static int DebugFlags = 0;
861 [Conditional ("MCS_DEBUG")]
862 static public void Debug (string message, params object[] args)
864 Debug (4, message, args);
867 [Conditional ("MCS_DEBUG")]
868 static public void Debug (int category, string message, params object[] args)
870 if ((category & DebugFlags) == 0)
873 StringBuilder sb = new StringBuilder (message);
875 if ((args != null) && (args.Length > 0)) {
879 foreach (object arg in args) {
886 else if (arg is ICollection)
887 sb.Append (PrintCollection ((ICollection) arg));
893 Console.WriteLine (sb.ToString ());
896 static public string PrintCollection (ICollection collection)
898 StringBuilder sb = new StringBuilder ();
900 sb.Append (collection.GetType ());
904 foreach (object o in collection) {
913 return sb.ToString ();
917 public enum TimerType {
927 public enum CounterType {
936 static DateTime[] timer_start;
937 static TimeSpan[] timers;
938 static long[] timer_counters;
939 static long[] counters;
943 timer_start = new DateTime [(int) TimerType.CountTimers];
944 timers = new TimeSpan [(int) TimerType.CountTimers];
945 timer_counters = new long [(int) TimerType.CountTimers];
946 counters = new long [(int) CounterType.CountCounters];
948 for (int i = 0; i < (int) TimerType.CountTimers; i++) {
949 timer_start [i] = DateTime.Now;
950 timers [i] = TimeSpan.Zero;
954 [Conditional("TIMER")]
955 static public void IncrementCounter (CounterType which)
957 ++counters [(int) which];
960 [Conditional("TIMER")]
961 static public void StartTimer (TimerType which)
963 timer_start [(int) which] = DateTime.Now;
966 [Conditional("TIMER")]
967 static public void StopTimer (TimerType which)
969 timers [(int) which] += DateTime.Now - timer_start [(int) which];
970 ++timer_counters [(int) which];
973 [Conditional("TIMER")]
974 static public void ShowTimers ()
976 ShowTimer (TimerType.FindMembers, "- FindMembers timer");
977 ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
978 ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
979 ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
980 ShowTimer (TimerType.CacheInit, "- Cache init");
981 ShowTimer (TimerType.MiscTimer, "- Misc timer");
983 ShowCounter (CounterType.FindMembers, "- Find members");
984 ShowCounter (CounterType.MemberCache, "- Member cache");
985 ShowCounter (CounterType.MiscCounter, "- Misc counter");
988 static public void ShowCounter (CounterType which, string msg)
990 Console.WriteLine ("{0} {1}", counters [(int) which], msg);
993 static public void ShowTimer (TimerType which, string msg)
996 "[{0:00}:{1:000}] {2} (used {3} times)",
997 (int) timers [(int) which].TotalSeconds,
998 timers [(int) which].Milliseconds, msg,
999 timer_counters [(int) which]);
1003 public class InternalErrorException : Exception {
1004 public InternalErrorException (MemberCore mc, Exception e)
1005 : base (mc.Location + " " + mc.GetSignatureForError (), e)
1009 public InternalErrorException ()
1010 : base ("Internal error")
1014 public InternalErrorException (string message)
1019 public InternalErrorException (string message, params object[] args)
1020 : base (String.Format (message, args))
1023 public InternalErrorException (Exception e, Location loc)
1024 : base (loc.ToString (), e)
1030 /// Handles #pragma warning
1032 public class WarningRegions {
1034 abstract class PragmaCmd
1038 protected PragmaCmd (int line)
1043 public abstract bool IsEnabled (int code, bool previous);
1046 class Disable : PragmaCmd
1049 public Disable (int line, int code)
1055 public override bool IsEnabled (int code, bool previous)
1057 return this.code == code ? false : previous;
1061 class DisableAll : PragmaCmd
1063 public DisableAll (int line)
1066 public override bool IsEnabled(int code, bool previous)
1072 class Enable : PragmaCmd
1075 public Enable (int line, int code)
1081 public override bool IsEnabled(int code, bool previous)
1083 return this.code == code ? true : previous;
1087 class EnableAll : PragmaCmd
1089 public EnableAll (int line)
1092 public override bool IsEnabled(int code, bool previous)
1099 ArrayList regions = new ArrayList ();
1101 public void WarningDisable (int line)
1103 regions.Add (new DisableAll (line));
1106 public void WarningDisable (Location location, int code)
1108 if (CheckWarningCode (code, location))
1109 regions.Add (new Disable (location.Row, code));
1112 public void WarningEnable (int line)
1114 regions.Add (new EnableAll (line));
1117 public void WarningEnable (Location location, int code)
1119 if (CheckWarningCode (code, location))
1120 regions.Add (new Enable (location.Row, code));
1123 public bool IsWarningEnabled (int code, int src_line)
1126 foreach (PragmaCmd pragma in regions) {
1127 if (src_line < pragma.Line)
1130 result = pragma.IsEnabled (code, result);
1135 static bool CheckWarningCode (int code, Location loc)
1137 if (Report.IsValidWarning (code))
1140 Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code.ToString ());