X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Freport.cs;h=81561a5cb9b387d48df82648e7b83e7b028c09ab;hb=12d16ae4269e9a008863e6718075d6c168d6d16c;hp=2096450fdb10e5c736189deeb22f19470f2d45a1;hpb=217ddc29c40bc8b11f8fbd4800e61db7f4f22bbf;p=mono.git diff --git a/mcs/mcs/report.cs b/mcs/mcs/report.cs index 2096450fdb1..81561a5cb9b 100644 --- a/mcs/mcs/report.cs +++ b/mcs/mcs/report.cs @@ -2,86 +2,51 @@ // report.cs: report errors and warnings. // // Author: Miguel de Icaza (miguel@ximian.com) -// Marek Safar (marek.safar@seznam.cz) +// Marek Safar (marek.safar@gmail.com) // // Copyright 2001 Ximian, Inc. (http://www.ximian.com) +// Copyright 2011 Xamarin, Inc (http://www.xamarin.com) // using System; using System.IO; using System.Text; -using System.Collections; -using System.Collections.Specialized; +using System.Collections.Generic; using System.Diagnostics; -using System.Reflection; -using System.Reflection.Emit; namespace Mono.CSharp { - /// - /// This class is used to report errors and warnings t te user. - /// - public class Report { - /// - /// Errors encountered so far - /// - static public int Errors; - - /// - /// Warnings encountered so far - /// - static public int Warnings; - - /// - /// Whether errors should be throw an exception - /// - static public bool Fatal; - + // + // Errors and warnings manager + // + public class Report + { /// /// Whether warnings should be considered errors /// - static public bool WarningsAreErrors; - static ArrayList warnings_as_error; + public bool WarningsAreErrors; + List warnings_as_error; + List warnings_only; - /// - /// Whether to dump a stack trace on errors. - /// - static public bool Stacktrace; - - static public TextWriter Stderr = Console.Error; - - // - // If the 'expected' error code is reported then the - // compilation succeeds. - // - // Used for the test suite to excercise the error codes - // - static int expected_error = 0; + public const int RuntimeErrorId = 10000; // // Keeps track of the warnings that we are ignoring // - public static Hashtable warning_ignore_table; + HashSet warning_ignore_table; - static Hashtable warning_regions_table; + Dictionary warning_regions_table; - // - // This is used to save/restore the error state. When the - // error stack contains elements, warnings and errors are not - // reported to the user. This is used by the Lambda expression - // support to compile the code with various parameter values. - // A stack because of `Report.Errors == errors;' - // - static Stack error_stack; - static Stack warning_stack; - static bool reporting_disabled; - - static int warning_level; + int warning_level; + + ReportPrinter printer; + + int reporting_disabled; /// /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported. /// - static ArrayList extra_information = new ArrayList (); + List extra_information = new List (); // // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE @@ -90,954 +55,1030 @@ namespace Mono.CSharp { 28, 67, 78, 105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197, 219, 251, 252, 253, 278, 282, - 419, 420, 429, 436, 440, 465, 467, 469, 472, - 612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675, - 809, - 1030, + 402, 414, 419, 420, 429, 436, 437, 440, 458, 464, 465, 467, 469, 472, 473, + 612, 618, 626, 628, 642, 649, 652, 657, 658, 659, 660, 661, 665, 672, 675, 693, + 728, + 809, 824, + 1030, 1058, 1060, 1066, 1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592, - 1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692, - 1717, 1718, 1720, - 1901, + 1607, 1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692, 1695, 1696, 1699, + 1700, 1701, 1702, 1709, 1711, 1717, 1718, 1720, 1735, + 1901, 1956, 1981, 1998, 2002, 2023, 2029, 3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, - 3021, 3022, 3023, 3026, 3027, - - 414, // Non ISO-1 warnings -#if GMCS_SOURCE - 402, 458, 464, 693, 1058, 1700, 3024 -#endif + 3021, 3022, 3023, 3024, 3026, 3027 }; - static Report () + static HashSet AllWarningsHashSet; + + public Report (ReportPrinter printer) { - // Just to be sure that binary search is working - Array.Sort (AllWarnings); + if (printer == null) + throw new ArgumentNullException ("printer"); + + this.printer = printer; + warning_level = 4; } - public static void Reset () + public void DisableReporting () { - Errors = Warnings = 0; - WarningsAreErrors = false; - warning_ignore_table = null; - warning_regions_table = null; - reporting_disabled = false; - error_stack = warning_stack = null; - warnings_as_error = null; + ++reporting_disabled; } - public static void DisableReporting () + public void EnableReporting () { - if (error_stack == null) - error_stack = new Stack (); - error_stack.Push (Errors); + --reporting_disabled; + } - if (Warnings > 0) { - if (warning_stack == null) - warning_stack = new Stack (); - warning_stack.Push (Warnings); + public void FeatureIsNotAvailable (CompilerContext compiler, Location loc, string feature) + { + string version; + switch (compiler.Settings.Version) { + case LanguageVersion.ISO_1: + version = "1.0"; + break; + case LanguageVersion.ISO_2: + version = "2.0"; + break; + case LanguageVersion.V_3: + version = "3.0"; + break; + case LanguageVersion.V_4: + version = "4.0"; + break; + case LanguageVersion.V_5: + version = "5.0"; + break; + default: + throw new InternalErrorException ("Invalid feature version", compiler.Settings.Version); } - reporting_disabled = true; + Error (1644, loc, + "Feature `{0}' cannot be used because it is not part of the C# {1} language specification", + feature, version); } - public static void EnableReporting () + public void FeatureIsNotSupported (Location loc, string feature) { - if (warning_stack != null && warning_stack.Count > 0) - Warnings = (int) warning_stack.Pop (); - else - Warnings = 0; - - Errors = (int) error_stack.Pop (); - if (error_stack.Count == 0) { - reporting_disabled = false; - } + Error (1644, loc, + "Feature `{0}' is not supported in Mono mcs1 compiler. Consider using the `gmcs' compiler instead", + feature); } + + bool IsWarningEnabled (int code, int level, Location loc) + { + if (WarningLevel < level) + return false; - public static IMessageRecorder msg_recorder; + if (IsWarningDisabledGlobally (code)) + return false; - public static IMessageRecorder SetMessageRecorder (IMessageRecorder recorder) - { - IMessageRecorder previous = msg_recorder; - msg_recorder = recorder; - return previous; + if (warning_regions_table == null || loc.IsNull) + return true; + + WarningRegions regions; + if (!warning_regions_table.TryGetValue (loc.File, out regions)) + return true; + + return regions.IsWarningEnabled (code, loc.Row); } - public interface IMessageRecorder + public bool IsWarningDisabledGlobally (int code) { - bool IsEmpty { get; } - void EndSession (); - void AddMessage (AbstractMessage msg); - bool PrintMessages (); + return warning_ignore_table != null && warning_ignore_table.Contains (code); } - // - // Default message recorder, it uses two types of message groups. - // Common messages: messages reported in all sessions. - // Merged messages: union of all messages in all sessions. - // - public struct MessageRecorder : IMessageRecorder + bool IsWarningAsError (int code) { - ArrayList session_messages; - // - // A collection of exactly same messages reported in all sessions - // - ArrayList common_messages; + bool is_error = WarningsAreErrors; - // - // A collection of unique messages reported in all sessions - // - ArrayList merged_messages; + // Check specific list + if (warnings_as_error != null) + is_error |= warnings_as_error.Contains (code); - public void EndSession () - { - if (session_messages == null) - return; - - // - // Handles the first session - // - if (common_messages == null) { - common_messages = new ArrayList (session_messages); - merged_messages = session_messages; - session_messages = null; - return; - } + // Ignore excluded warnings + if (warnings_only != null && warnings_only.Contains (code)) + is_error = false; - // - // Store common messages if any - // - for (int i = 0; i < common_messages.Count; ++i) { - AbstractMessage cmsg = (AbstractMessage) common_messages [i]; - bool common_msg_found = false; - foreach (AbstractMessage msg in session_messages) { - if (cmsg.Equals (msg)) { - common_msg_found = true; - break; - } - } + return is_error; + } + + public void RuntimeMissingSupport (Location loc, string feature) + { + Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature); + } - if (!common_msg_found) - common_messages.RemoveAt (i); - } + /// + /// In most error cases is very useful to have information about symbol that caused the error. + /// Call this method before you call Report.Error when it makes sense. + /// + public void SymbolRelatedToPreviousError (Location loc, string symbol) + { + SymbolRelatedToPreviousError (loc.ToString ()); + } - // - // Merge session and previous messages - // - for (int i = 0; i < session_messages.Count; ++i) { - AbstractMessage msg = (AbstractMessage) session_messages [i]; - bool msg_found = false; - for (int ii = 0; ii < merged_messages.Count; ++ii) { - if (msg.Equals (merged_messages [ii])) { - msg_found = true; - break; - } - } + public void SymbolRelatedToPreviousError (MemberSpec ms) + { + if (reporting_disabled > 0 || !printer.HasRelatedSymbolSupport) + return; - if (!msg_found) - merged_messages.Add (msg); - } + var mc = ms.MemberDefinition as MemberCore; + while (ms is ElementTypeSpec) { + ms = ((ElementTypeSpec) ms).Element; + mc = ms.MemberDefinition as MemberCore; } - public void AddMessage (AbstractMessage msg) - { - if (session_messages == null) - session_messages = new ArrayList (); - - session_messages.Add (msg); - } + if (mc != null) { + SymbolRelatedToPreviousError (mc); + } else { + if (ms.DeclaringType != null) + ms = ms.DeclaringType; - public bool IsEmpty { - get { - return merged_messages == null && common_messages == null; + var imported_type = ms.MemberDefinition as ImportedTypeDefinition; + if (imported_type != null) { + var iad = imported_type.DeclaringAssembly as ImportedAssemblyDefinition; + SymbolRelatedToPreviousError (iad.Location); } } + } - // - // Prints collected messages, common messages have a priority - // - public bool PrintMessages () - { - ArrayList messages_to_print = merged_messages; - if (common_messages != null && common_messages.Count > 0) { - messages_to_print = common_messages; - } - - if (messages_to_print == null) - return false; + public void SymbolRelatedToPreviousError (MemberCore mc) + { + SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ()); + } - foreach (AbstractMessage msg in messages_to_print) - msg.Print (); + public void SymbolRelatedToPreviousError (string loc) + { + string msg = String.Format ("{0} (Location of the symbol related to previous ", loc); + if (extra_information.Contains (msg)) + return; - return true; - } + extra_information.Add (msg); } - - public abstract class AbstractMessage + + public void AddWarningAsError (string warningId) { - readonly string[] extra_info; - protected readonly int code; - protected readonly Location location; - readonly string message; + int id; + try { + id = int.Parse (warningId); + } catch { + CheckWarningCode (warningId, Location.Null); + return; + } - protected AbstractMessage (int code, Location loc, string msg, ArrayList extraInfo) - { - this.code = code; - if (code < 0) - this.code = 8000 - code; + if (!CheckWarningCode (id, Location.Null)) + return; - this.location = loc; - this.message = msg; - if (extraInfo.Count != 0) { - this.extra_info = (string[])extraInfo.ToArray (typeof (string)); - } - } + if (warnings_as_error == null) + warnings_as_error = new List (); + + warnings_as_error.Add (id); + } - protected AbstractMessage (AbstractMessage aMsg) - { - this.code = aMsg.code; - this.location = aMsg.location; - this.message = aMsg.message; - this.extra_info = aMsg.extra_info; + public void RemoveWarningAsError (string warningId) + { + int id; + try { + id = int.Parse (warningId); + } catch { + CheckWarningCode (warningId, Location.Null); + return; } - static void Check (int code) - { - if (code == expected_error) { - Environment.Exit (0); - } - } + if (!CheckWarningCode (id, Location.Null)) + return; - public override bool Equals (object obj) - { - AbstractMessage msg = obj as AbstractMessage; - if (msg == null) - return false; + if (warnings_only == null) + warnings_only = new List (); - return code == msg.code && location.Equals (msg.location) && message == msg.message; - } + warnings_only.Add (id); + } - public override int GetHashCode () - { - return code.GetHashCode (); - } + public bool CheckWarningCode (string code, Location loc) + { + Warning (1691, 1, loc, "`{0}' is not a valid warning number", code); + return false; + } - public abstract bool IsWarning { get; } + public bool CheckWarningCode (int code, Location loc) + { + if (AllWarningsHashSet == null) + AllWarningsHashSet = new HashSet (AllWarnings); - public abstract string MessageType { get; } + if (AllWarningsHashSet.Contains (code)) + return true; - public virtual void Print () - { - if (msg_recorder != null) { - // - // This line is useful when debugging messages recorder - // - // Console.WriteLine ("RECORDING: {0} {1} {2}", code, location, message); - msg_recorder.AddMessage (this); - return; - } + return CheckWarningCode (code.ToString (), loc); + } - if (reporting_disabled) - return; + public void ExtraInformation (Location loc, string msg) + { + extra_information.Add (String.Format ("{0} {1}", loc, msg)); + } - StringBuilder msg = new StringBuilder (); - if (!location.IsNull) { - msg.Append (location.ToString ()); - msg.Append (" "); - } - msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, message); + public WarningRegions RegisterWarningRegion (Location location) + { + WarningRegions regions; + if (warning_regions_table == null) { + regions = null; + warning_regions_table = new Dictionary (); + } else { + warning_regions_table.TryGetValue (location.File, out regions); + } - // - // - if (Stderr == Console.Error) - Stderr.WriteLine (ColorFormat (msg.ToString ())); - else - Stderr.WriteLine (msg.ToString ()); + if (regions == null) { + regions = new WarningRegions (); + warning_regions_table.Add (location.File, regions); + } - if (extra_info != null) { - foreach (string s in extra_info) - Stderr.WriteLine (s + MessageType + ")"); - } + return regions; + } - if (Stacktrace) - Console.WriteLine (FriendlyStackTrace (new StackTrace (true))); + public void Warning (int code, int level, Location loc, string message) + { + if (reporting_disabled > 0) + return; - if (Fatal) { - if (!IsWarning || WarningsAreErrors) - throw new Exception (message); - } + if (!IsWarningEnabled (code, level, loc)) + return; - Check (code); + AbstractMessage msg; + if (IsWarningAsError (code)) { + message = "Warning as Error: " + message; + msg = new ErrorMessage (code, loc, message, extra_information); + } else { + msg = new WarningMessage (code, loc, message, extra_information); } - protected virtual string ColorFormat (string s) - { - return s; - } + extra_information.Clear (); + printer.Print (msg); } - sealed class WarningMessage : AbstractMessage + public void Warning (int code, int level, Location loc, string format, string arg) { - readonly int Level; + Warning (code, level, loc, String.Format (format, arg)); + } - public WarningMessage (int code, int level, Location loc, string message, ArrayList extra_info) - : base (code, loc, message, extra_info) - { - Level = level; - } + public void Warning (int code, int level, Location loc, string format, string arg1, string arg2) + { + Warning (code, level, loc, String.Format (format, arg1, arg2)); + } - public override bool IsWarning { - get { return true; } - } + public void Warning (int code, int level, Location loc, string format, params object[] args) + { + Warning (code, level, loc, String.Format (format, args)); + } - bool IsEnabled () - { - if (WarningLevel < Level) - return false; + public void Warning (int code, int level, string message) + { + Warning (code, level, Location.Null, message); + } - if (warning_ignore_table != null) { - if (warning_ignore_table.Contains (code)) { - return false; - } - } + public void Warning (int code, int level, string format, string arg) + { + Warning (code, level, Location.Null, format, arg); + } - if (warning_regions_table == null || location.IsNull) - return true; + public void Warning (int code, int level, string format, string arg1, string arg2) + { + Warning (code, level, Location.Null, format, arg1, arg2); + } - WarningRegions regions = (WarningRegions)warning_regions_table [location.Name]; - if (regions == null) - return true; + public void Warning (int code, int level, string format, params string[] args) + { + Warning (code, level, Location.Null, String.Format (format, args)); + } - return regions.IsWarningEnabled (code, location.Row); - } + // + // Warnings encountered so far + // + public int Warnings { + get { return printer.WarningsCount; } + } - bool IsErrorWarning { - get { - if (WarningsAreErrors) - return true; + public void Error (int code, Location loc, string error) + { + if (reporting_disabled > 0) + return; - if (warnings_as_error == null) - return false; + ErrorMessage msg = new ErrorMessage (code, loc, error, extra_information); + extra_information.Clear (); - return warnings_as_error.Contains (code); - } - } + printer.Print (msg); + } - public override void Print () - { - if (!IsEnabled ()) - return; + public void Error (int code, Location loc, string format, string arg) + { + Error (code, loc, String.Format (format, arg)); + } - if (IsErrorWarning) { - new ErrorMessage (this).Print (); - return; - } + public void Error (int code, Location loc, string format, string arg1, string arg2) + { + Error (code, loc, String.Format (format, arg1, arg2)); + } - Warnings++; - base.Print (); - } + public void Error (int code, Location loc, string format, params string[] args) + { + Error (code, loc, String.Format (format, args)); + } - public override string MessageType { - get { - return "warning"; - } - } + public void Error (int code, string error) + { + Error (code, Location.Null, error); } - static int NameToCode (string s) + public void Error (int code, string format, string arg) { - switch (s){ - case "black": - return 0; - case "red": - return 1; - case "green": - return 2; - case "yellow": - return 3; - case "blue": - return 4; - case "magenta": - return 5; - case "cyan": - return 6; - case "grey": - case "white": - return 7; - } - return 7; + Error (code, Location.Null, format, arg); } - + + public void Error (int code, string format, string arg1, string arg2) + { + Error (code, Location.Null, format, arg1, arg2); + } + + public void Error (int code, string format, params string[] args) + { + Error (code, Location.Null, String.Format (format, args)); + } + // - // maps a color name to its xterm color code + // Errors encountered so far // - static string GetForeground (string s) + public int Errors { + get { return printer.ErrorsCount; } + } + + public bool IsDisabled { + get { + return reporting_disabled > 0; + } + } + + public ReportPrinter Printer { + get { return printer; } + } + + public void SetIgnoreWarning (int code) { - string highcode; + if (warning_ignore_table == null) + warning_ignore_table = new HashSet (); - if (s.StartsWith ("bright")){ - highcode = "1;"; - s = s.Substring (6); - } else - highcode = ""; + warning_ignore_table.Add (code); + } - return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m"; + public ReportPrinter SetPrinter (ReportPrinter printer) + { + ReportPrinter old = this.printer; + this.printer = printer; + return old; } - static string GetBackground (string s) + public int WarningLevel { + get { + return warning_level; + } + set { + warning_level = value; + } + } + + [Conditional ("MCS_DEBUG")] + static public void Debug (string message, params object[] args) { - return "\x001b[" + (40 + NameToCode (s)).ToString () + "m"; + Debug (4, message, args); } - - sealed class ErrorMessage : AbstractMessage + + [Conditional ("MCS_DEBUG")] + static public void Debug (int category, string message, params object[] args) { - static string prefix, postfix; +// if ((category & DebugFlags) == 0) +// return; - static ErrorMessage () - { - string term = Environment.GetEnvironmentVariable ("TERM"); - bool xterm_colors = false; - - switch (term){ - case "xterm": - case "rxvt": - case "rxvt-unicode": - if (Environment.GetEnvironmentVariable ("COLORTERM") != null){ - xterm_colors = true; - } - break; + StringBuilder sb = new StringBuilder (message); - case "xterm-color": - xterm_colors = true; - break; - } - if (!xterm_colors) - return; + if ((args != null) && (args.Length > 0)) { + sb.Append (": "); - if (!(UnixUtils.isatty (1) && UnixUtils.isatty (2))) - return; - - string config = Environment.GetEnvironmentVariable ("MCS_COLORS"); - if (config == null){ - config = "errors=red"; - //config = "brightwhite,red"; + bool first = true; + foreach (object arg in args) { + if (first) + first = false; + else + sb.Append (", "); + if (arg == null) + sb.Append ("null"); +// else if (arg is ICollection) +// sb.Append (PrintCollection ((ICollection) arg)); + else + sb.Append (arg); } + } - if (config == "disable") - return; + Console.WriteLine (sb.ToString ()); + } +/* + static public string PrintCollection (ICollection collection) + { + StringBuilder sb = new StringBuilder (); - if (!config.StartsWith ("errors=")) - return; + sb.Append (collection.GetType ()); + sb.Append ("("); - config = config.Substring (7); - - int p = config.IndexOf (","); - if (p == -1) - prefix = GetForeground (config); + bool first = true; + foreach (object o in collection) { + if (first) + first = false; else - prefix = GetBackground (config.Substring (p+1)) + GetForeground (config.Substring (0, p)); - postfix = "\x001b[0m"; + sb.Append (", "); + sb.Append (o); } - public ErrorMessage (int code, Location loc, string message, ArrayList extraInfo) - : base (code, loc, message, extraInfo) - { - } + sb.Append (")"); + return sb.ToString (); + } +*/ + } - public ErrorMessage (AbstractMessage aMsg) - : base (aMsg) - { - } + public abstract class AbstractMessage + { + readonly string[] extra_info; + protected readonly int code; + protected readonly Location location; + readonly string message; - protected override string ColorFormat (string s) - { - if (prefix != null) - return prefix + s + postfix; - return s; - } - - public override void Print() - { - Errors++; - base.Print (); - } + protected AbstractMessage (int code, Location loc, string msg, List extraInfo) + { + this.code = code; + if (code < 0) + this.code = 8000 - code; - public override bool IsWarning { - get { return false; } + this.location = loc; + this.message = msg; + if (extraInfo.Count != 0) { + this.extra_info = extraInfo.ToArray (); } + } - public override string MessageType { - get { - return "error"; - } - } + protected AbstractMessage (AbstractMessage aMsg) + { + this.code = aMsg.code; + this.location = aMsg.location; + this.message = aMsg.message; + this.extra_info = aMsg.extra_info; + } + + public int Code { + get { return code; } } - public static void FeatureIsNotAvailable (Location loc, string feature) + public override bool Equals (object obj) { - string version; - switch (RootContext.Version) { - case LanguageVersion.ISO_1: - version = "1.0"; - break; - case LanguageVersion.ISO_2: - version = "2.0"; - break; - case LanguageVersion.Default_MCS: - Report.Error (1644, loc, "Feature `{0}' is not available in Mono mcs1 compiler. Consider using the `gmcs' compiler instead", - feature); - return; - default: - throw new InternalErrorException ("Invalid feature version", RootContext.Version); + AbstractMessage msg = obj as AbstractMessage; + if (msg == null) + return false; + + return code == msg.code && location.Equals (msg.location) && message == msg.message; + } + + public override int GetHashCode () + { + return code.GetHashCode (); + } + + public abstract bool IsWarning { get; } + + public Location Location { + get { return location; } + } + + public abstract string MessageType { get; } + + public string[] RelatedSymbols { + get { return extra_info; } + } + + public string Text { + get { return message; } + } + } + + sealed class WarningMessage : AbstractMessage + { + public WarningMessage (int code, Location loc, string message, List extra_info) + : base (code, loc, message, extra_info) + { + } + + public override bool IsWarning { + get { return true; } + } + + public override string MessageType { + get { + return "warning"; } + } + } - Report.Error (1644, loc, - "Feature `{0}' cannot be used because it is not part of the C# {1} language specification", - feature, version); + sealed class ErrorMessage : AbstractMessage + { + public ErrorMessage (int code, Location loc, string message, List extraInfo) + : base (code, loc, message, extraInfo) + { } - - public static string FriendlyStackTrace (Exception e) + + public ErrorMessage (AbstractMessage aMsg) + : base (aMsg) { - return FriendlyStackTrace (new StackTrace (e, true)); } - - static string FriendlyStackTrace (StackTrace t) - { - StringBuilder sb = new StringBuilder (); - - bool foundUserCode = false; - - for (int i = 0; i < t.FrameCount; i++) { - StackFrame f = t.GetFrame (i); - MethodBase mb = f.GetMethod (); - - if (!foundUserCode && mb.ReflectedType == typeof (Report)) - continue; - - foundUserCode = true; - - sb.Append ("\tin "); - - if (f.GetFileLineNumber () > 0) - sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ()); - - sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name); - - bool first = true; - foreach (ParameterInfo pi in mb.GetParameters ()) { - if (!first) - sb.Append (", "); - first = false; - - sb.Append (TypeManager.CSharpName (pi.ParameterType)); - } - sb.Append (")\n"); + + public override bool IsWarning { + get { return false; } + } + + public override string MessageType { + get { + return "error"; } + } + } + + // + // Generic base for any message writer + // + public abstract class ReportPrinter + { + #region Properties + + public int FatalCounter { get; set; } + + public int ErrorsCount { get; protected set; } - return sb.ToString (); + public bool ShowFullPaths { get; set; } + + // + // Whether to dump a stack trace on errors. + // + public bool Stacktrace { get; set; } + + public int WarningsCount { get; private set; } + + // + // When (symbols related to previous ...) can be used + // + public virtual bool HasRelatedSymbolSupport { + get { return true; } } - public static void StackTrace () + #endregion + + + protected virtual string FormatText (string txt) { - Console.WriteLine (FriendlyStackTrace (new StackTrace (true))); + return txt; } - static bool IsValidWarning (int code) - { - return Array.BinarySearch (AllWarnings, code) >= 0; + public virtual void Print (AbstractMessage msg) + { + if (msg.IsWarning) { + ++WarningsCount; + } else { + ++ErrorsCount; + + if (ErrorsCount == FatalCounter) + throw new Exception (msg.Text); + } } - - static public void RuntimeMissingSupport (Location loc, string feature) + + protected void Print (AbstractMessage msg, TextWriter output) { - Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature); + StringBuilder txt = new StringBuilder (); + if (!msg.Location.IsNull) { + if (ShowFullPaths) + txt.Append (msg.Location.ToStringFullName ()); + else + txt.Append (msg.Location.ToString ()); + + txt.Append (" "); + } + + txt.AppendFormat ("{0} CS{1:0000}: {2}", msg.MessageType, msg.Code, msg.Text); + + if (!msg.IsWarning) + output.WriteLine (FormatText (txt.ToString ())); + else + output.WriteLine (txt.ToString ()); + + if (msg.RelatedSymbols != null) { + foreach (string s in msg.RelatedSymbols) + output.WriteLine (s + msg.MessageType + ")"); + } } - /// - /// In most error cases is very useful to have information about symbol that caused the error. - /// Call this method before you call Report.Error when it makes sense. - /// - static public void SymbolRelatedToPreviousError (Location loc, string symbol) + public void Reset () { - SymbolRelatedToPreviousError (loc.ToString (), symbol); + // HACK: Temporary hack for broken repl flow + ErrorsCount = WarningsCount = 0; } + } + + sealed class NullReportPrinter : ReportPrinter + { + } + + // + // Default message recorder, it uses two types of message groups. + // Common messages: messages reported in all sessions. + // Merged messages: union of all messages in all sessions. + // + // Used by the Lambda expressions to compile the code with various + // parameter values, or by attribute resolver + // + class SessionReportPrinter : ReportPrinter + { + List session_messages; + // + // A collection of exactly same messages reported in all sessions + // + List common_messages; + + // + // A collection of unique messages reported in all sessions + // + List merged_messages; - static public void SymbolRelatedToPreviousError (MemberInfo mi) + public override void Print (AbstractMessage msg) { - if (reporting_disabled) - return; + // + // This line is useful when debugging recorded messages + // + // Console.WriteLine ("RECORDING: {0}", msg.ToString ()); - Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType); - if (TypeManager.IsDelegateType (dt)) { - SymbolRelatedToPreviousError (dt); - return; - } - - DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt); - if (temp_ds == null) { - SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi)); - } else { - MethodBase mb = mi as MethodBase; - if (mb != null) { - mb = TypeManager.DropGenericMethodArguments (mb); - IMethodData md = TypeManager.GetMethod (mb); - SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ()); - return; - } + if (session_messages == null) + session_messages = new List (); - // FIXME: Completely wrong, it has to use FindMembers - MemberCore mc = temp_ds.GetDefinition (mi.Name); - if (mc != null) - SymbolRelatedToPreviousError (mc); - } - } + session_messages.Add (msg); - static public void SymbolRelatedToPreviousError (MemberCore mc) - { - SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ()); + base.Print (msg); } - static public void SymbolRelatedToPreviousError (Type type) + public void EndSession () { - if (reporting_disabled) + if (session_messages == null) return; - type = TypeManager.DropGenericTypeArguments (type); + // + // Handles the first session + // + if (common_messages == null) { + common_messages = new List (session_messages); + merged_messages = session_messages; + session_messages = null; + return; + } - if (TypeManager.IsGenericParameter (type)) { - TypeParameter tp = TypeManager.LookupTypeParameter (type); - if (tp != null) { - SymbolRelatedToPreviousError (tp.Location, ""); - return; + // + // Store common messages if any + // + for (int i = 0; i < common_messages.Count; ++i) { + AbstractMessage cmsg = common_messages[i]; + bool common_msg_found = false; + foreach (AbstractMessage msg in session_messages) { + if (cmsg.Equals (msg)) { + common_msg_found = true; + break; + } } - } - if (type is TypeBuilder) { - DeclSpace temp_ds = TypeManager.LookupDeclSpace (type); - SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type)); - } else if (TypeManager.HasElementType (type)) { - SymbolRelatedToPreviousError (type.GetElementType ()); - } else { - SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type)); + if (!common_msg_found) + common_messages.RemoveAt (i); } - } - static void SymbolRelatedToPreviousError (string loc, string symbol) - { - string msg = String.Format ("{0} (Location of the symbol related to previous ", loc); - if (extra_information.Contains (msg)) - return; + // + // Merge session and previous messages + // + for (int i = 0; i < session_messages.Count; ++i) { + AbstractMessage msg = session_messages[i]; + bool msg_found = false; + for (int ii = 0; ii < merged_messages.Count; ++ii) { + if (msg.Equals (merged_messages[ii])) { + msg_found = true; + break; + } + } - extra_information.Add (msg); + if (!msg_found) + merged_messages.Add (msg); + } } - public static void AddWarningAsError (string warningId) - { - int id; - try { - id = int.Parse (warningId); - } catch { - id = -1; + public bool IsEmpty { + get { + return merged_messages == null && common_messages == null; } - - if (!CheckWarningCode (id, warningId, Location.Null)) - return; - - if (warnings_as_error == null) - warnings_as_error = new ArrayList (); - - warnings_as_error.Add (id); } - public static bool CheckWarningCode (int code, Location loc) + // + // Prints collected messages, common messages have a priority + // + public bool Merge (ReportPrinter dest) { - return CheckWarningCode (code, code.ToString (), loc); - } + var messages_to_print = merged_messages; + if (common_messages != null && common_messages.Count > 0) { + messages_to_print = common_messages; + } - public static bool CheckWarningCode (int code, string scode, Location loc) - { - if (IsValidWarning (code)) - return true; + if (messages_to_print == null) + return false; - Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", scode); - return false; - } + bool error_msg = false; + foreach (AbstractMessage msg in messages_to_print) { + dest.Print (msg); + error_msg |= !msg.IsWarning; + } - public static void ExtraInformation (Location loc, string msg) - { - extra_information.Add (String.Format ("{0} {1}", loc, msg)); + return error_msg; } + } - public static WarningRegions RegisterWarningRegion (Location location) - { - if (warning_regions_table == null) - warning_regions_table = new Hashtable (); - - WarningRegions regions = (WarningRegions)warning_regions_table [location.Name]; - if (regions == null) { - regions = new WarningRegions (); - warning_regions_table.Add (location.Name, regions); - } - return regions; - } + public class StreamReportPrinter : ReportPrinter + { + readonly TextWriter writer; - static public void Warning (int code, int level, Location loc, string message) + public StreamReportPrinter (TextWriter writer) { - WarningMessage w = new WarningMessage (code, level, loc, message, extra_information); - extra_information.Clear (); - w.Print (); + this.writer = writer; } - static public void Warning (int code, int level, Location loc, string format, string arg) + public override void Print (AbstractMessage msg) { - WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg), extra_information); - extra_information.Clear (); - w.Print (); + Print (msg, writer); + base.Print (msg); } + } - static public void Warning (int code, int level, Location loc, string format, string arg1, string arg2) - { - WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, arg1, arg2), extra_information); - extra_information.Clear (); - w.Print (); - } + public class ConsoleReportPrinter : StreamReportPrinter + { + static readonly string prefix, postfix; - static public void Warning (int code, int level, Location loc, string format, params object[] args) + static ConsoleReportPrinter () { - WarningMessage w = new WarningMessage (code, level, loc, String.Format (format, args), extra_information); - extra_information.Clear (); - w.Print (); - } + string term = Environment.GetEnvironmentVariable ("TERM"); + bool xterm_colors = false; + + switch (term){ + case "xterm": + case "rxvt": + case "rxvt-unicode": + if (Environment.GetEnvironmentVariable ("COLORTERM") != null){ + xterm_colors = true; + } + break; - static public void Warning (int code, int level, string message) - { - Warning (code, level, Location.Null, message); - } + case "xterm-color": + case "xterm-256color": + xterm_colors = true; + break; + } + if (!xterm_colors) + return; - static public void Warning (int code, int level, string format, string arg) - { - Warning (code, level, Location.Null, format, arg); - } + if (!(UnixUtils.isatty (1) && UnixUtils.isatty (2))) + return; + + string config = Environment.GetEnvironmentVariable ("MCS_COLORS"); + if (config == null){ + config = "errors=red"; + //config = "brightwhite,red"; + } - static public void Warning (int code, int level, string format, string arg1, string arg2) - { - Warning (code, level, Location.Null, format, arg1, arg2); - } + if (config == "disable") + return; - static public void Warning (int code, int level, string format, params string[] args) - { - Warning (code, level, Location.Null, String.Format (format, args)); - } + if (!config.StartsWith ("errors=")) + return; - static public void Error (int code, Location loc, string error) - { - new ErrorMessage (code, loc, error, extra_information).Print (); - extra_information.Clear (); + config = config.Substring (7); + + int p = config.IndexOf (","); + if (p == -1) + prefix = GetForeground (config); + else + prefix = GetBackground (config.Substring (p+1)) + GetForeground (config.Substring (0, p)); + postfix = "\x001b[0m"; } - static public void Error (int code, Location loc, string format, string arg) + public ConsoleReportPrinter () + : base (Console.Error) { - new ErrorMessage (code, loc, String.Format (format, arg), extra_information).Print (); - extra_information.Clear (); } - static public void Error (int code, Location loc, string format, string arg1, string arg2) + public ConsoleReportPrinter (TextWriter writer) + : base (writer) { - new ErrorMessage (code, loc, String.Format (format, arg1, arg2), extra_information).Print (); - extra_information.Clear (); } - static public void Error (int code, Location loc, string format, params object[] args) + static int NameToCode (string s) { - Error (code, loc, String.Format (format, args)); + switch (s) { + case "black": + return 0; + case "red": + return 1; + case "green": + return 2; + case "yellow": + return 3; + case "blue": + return 4; + case "magenta": + return 5; + case "cyan": + return 6; + case "grey": + case "white": + return 7; + } + return 7; } - static public void Error (int code, string error) + // + // maps a color name to its xterm color code + // + static string GetForeground (string s) { - Error (code, Location.Null, error); - } + string highcode; - static public void Error (int code, string format, string arg) - { - Error (code, Location.Null, format, arg); - } + if (s.StartsWith ("bright")) { + highcode = "1;"; + s = s.Substring (6); + } else + highcode = ""; - static public void Error (int code, string format, string arg1, string arg2) - { - Error (code, Location.Null, format, arg1, arg2); + return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m"; } - static public void Error (int code, string format, params string[] args) + static string GetBackground (string s) { - Error (code, Location.Null, String.Format (format, args)); + return "\x001b[" + (40 + NameToCode (s)).ToString () + "m"; } - static public void SetIgnoreWarning (int code) + protected override string FormatText (string txt) { - if (warning_ignore_table == null) - warning_ignore_table = new Hashtable (); + if (prefix != null) + return prefix + txt + postfix; - warning_ignore_table [code] = true; - } - - static public int ExpectedError { - set { - expected_error = value; - } - get { - return expected_error; - } - } - - public static int WarningLevel { - get { - return warning_level; - } - set { - warning_level = value; - } + return txt; } - public static int DebugFlags = 0; - - [Conditional ("MCS_DEBUG")] - static public void Debug (string message, params object[] args) - { - Debug (4, message, args); - } + static string FriendlyStackTrace (StackTrace t) + { + StringBuilder sb = new StringBuilder (); - [Conditional ("MCS_DEBUG")] - static public void Debug (int category, string message, params object[] args) - { - if ((category & DebugFlags) == 0) - return; - - StringBuilder sb = new StringBuilder (message); - - if ((args != null) && (args.Length > 0)) { - sb.Append (": "); - + bool foundUserCode = false; + + for (int i = 0; i < t.FrameCount; i++) { + StackFrame f = t.GetFrame (i); + var mb = f.GetMethod (); + + if (!foundUserCode && mb.ReflectedType == typeof (Report)) + continue; + + foundUserCode = true; + + sb.Append ("\tin "); + + if (f.GetFileLineNumber () > 0) + sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ()); + + sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name); + bool first = true; - foreach (object arg in args) { - if (first) - first = false; - else + foreach (var pi in mb.GetParameters ()) { + if (!first) sb.Append (", "); - if (arg == null) - sb.Append ("null"); - else if (arg is ICollection) - sb.Append (PrintCollection ((ICollection) arg)); - else - sb.Append (arg); + first = false; + + sb.Append (pi.ParameterType.FullName); } + sb.Append (")\n"); } - - Console.WriteLine (sb.ToString ()); + + return sb.ToString (); } - static public string PrintCollection (ICollection collection) + public override void Print (AbstractMessage msg) { - StringBuilder sb = new StringBuilder (); - - sb.Append (collection.GetType ()); - sb.Append ("("); - - bool first = true; - foreach (object o in collection) { - if (first) - first = false; - else - sb.Append (", "); - sb.Append (o); - } + base.Print (msg); - sb.Append (")"); - return sb.ToString (); + if (Stacktrace) + Console.WriteLine (FriendlyStackTrace (new StackTrace (true))); } - } - public enum TimerType { - FindMembers = 0, - TcFindMembers = 1, - MemberLookup = 2, - CachedLookup = 3, - CacheInit = 4, - MiscTimer = 5, - CountTimers = 6 - } + public static string FriendlyStackTrace (Exception e) + { + return FriendlyStackTrace (new StackTrace (e, true)); + } - public enum CounterType { - FindMembers = 0, - MemberCache = 1, - MiscCounter = 2, - CountCounters = 3 + public static void StackTrace () + { + Console.WriteLine (FriendlyStackTrace (new StackTrace (true))); + } } - public class Timer + class TimeReporter { - static DateTime[] timer_start; - static TimeSpan[] timers; - static long[] timer_counters; - static long[] counters; - - static Timer () + public enum TimerType { - timer_start = new DateTime [(int) TimerType.CountTimers]; - timers = new TimeSpan [(int) TimerType.CountTimers]; - timer_counters = new long [(int) TimerType.CountTimers]; - counters = new long [(int) CounterType.CountCounters]; - - for (int i = 0; i < (int) TimerType.CountTimers; i++) { - timer_start [i] = DateTime.Now; - timers [i] = TimeSpan.Zero; - } + ParseTotal, + AssemblyBuilderSetup, + CreateTypeTotal, + ReferencesLoading, + ReferencesImporting, + PredefinedTypesInit, + ModuleDefinitionTotal, + UsingResolve, + EmitTotal, + CloseTypes, + Resouces, + OutputSave, + DebugSave, } - [Conditional("TIMER")] - static public void IncrementCounter (CounterType which) + readonly Stopwatch[] timers; + Stopwatch total; + + public TimeReporter (bool enabled) { - ++counters [(int) which]; + if (!enabled) + return; + + timers = new Stopwatch[System.Enum.GetValues(typeof (TimerType)).Length]; } - [Conditional("TIMER")] - static public void StartTimer (TimerType which) + public void Start (TimerType type) { - timer_start [(int) which] = DateTime.Now; + if (timers != null) { + var sw = new Stopwatch (); + timers[(int) type] = sw; + sw.Start (); + } } - [Conditional("TIMER")] - static public void StopTimer (TimerType which) + public void StartTotal () { - timers [(int) which] += DateTime.Now - timer_start [(int) which]; - ++timer_counters [(int) which]; + total = new Stopwatch (); + total.Start (); } - [Conditional("TIMER")] - static public void ShowTimers () + public void Stop (TimerType type) { - ShowTimer (TimerType.FindMembers, "- FindMembers timer"); - ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer"); - ShowTimer (TimerType.MemberLookup, "- MemberLookup timer"); - ShowTimer (TimerType.CachedLookup, "- CachedLookup timer"); - ShowTimer (TimerType.CacheInit, "- Cache init"); - ShowTimer (TimerType.MiscTimer, "- Misc timer"); - - ShowCounter (CounterType.FindMembers, "- Find members"); - ShowCounter (CounterType.MemberCache, "- Member cache"); - ShowCounter (CounterType.MiscCounter, "- Misc counter"); + if (timers != null) { + timers[(int) type].Stop (); + } } - static public void ShowCounter (CounterType which, string msg) + public void StopTotal () { - Console.WriteLine ("{0} {1}", counters [(int) which], msg); + total.Stop (); } - static public void ShowTimer (TimerType which, string msg) + public void ShowStats () { - Console.WriteLine ( - "[{0:00}:{1:000}] {2} (used {3} times)", - (int) timers [(int) which].TotalSeconds, - timers [(int) which].Milliseconds, msg, - timer_counters [(int) which]); + if (timers == null) + return; + + Dictionary timer_names = new Dictionary () { + { TimerType.ParseTotal, "Parsing source files" }, + { TimerType.AssemblyBuilderSetup, "Assembly builder setup" }, + { TimerType.CreateTypeTotal, "Compiled types created" }, + { TimerType.ReferencesLoading, "Referenced assemblies loading" }, + { TimerType.ReferencesImporting, "Referenced assemblies importing" }, + { TimerType.PredefinedTypesInit, "Predefined types initialization" }, + { TimerType.ModuleDefinitionTotal, "Module definition" }, + { TimerType.UsingResolve, "Top-level usings resolve" }, + { TimerType.EmitTotal, "Resolving and emitting members blocks" }, + { TimerType.CloseTypes, "Module types closed" }, + { TimerType.Resouces, "Embedding resources" }, + { TimerType.OutputSave, "Writing output file" }, + { TimerType.DebugSave, "Writing debug symbols file" }, + }; + + int counter = 0; + double percentage = (double) total.ElapsedMilliseconds / 100; + long subtotal = total.ElapsedMilliseconds; + foreach (var timer in timers) { + string msg = timer_names[(TimerType) counter++]; + var ms = timer == null ? 0 : timer.ElapsedMilliseconds; + Console.WriteLine ("{0,4:0.0}% {1,5}ms {2}", ms / percentage, ms, msg); + subtotal -= ms; + } + + Console.WriteLine ("{0,4:0.0}% {1,5}ms Other tasks", subtotal / percentage, subtotal); + Console.WriteLine (); + Console.WriteLine ("Total elapsed time: {0}", total.Elapsed); } } @@ -1059,7 +1100,13 @@ namespace Mono.CSharp { public InternalErrorException (string message, params object[] args) : base (String.Format (message, args)) - { } + { + } + + public InternalErrorException (Exception exception, string message, params object[] args) + : base (String.Format (message, args), exception) + { + } public InternalErrorException (Exception e, Location loc) : base (loc.ToString (), e) @@ -1137,14 +1184,14 @@ namespace Mono.CSharp { } - ArrayList regions = new ArrayList (); + List regions = new List (); public void WarningDisable (int line) { regions.Add (new DisableAll (line)); } - public void WarningDisable (Location location, int code) + public void WarningDisable (Location location, int code, Report Report) { if (Report.CheckWarningCode (code, location)) regions.Add (new Disable (location.Row, code)); @@ -1155,10 +1202,15 @@ namespace Mono.CSharp { regions.Add (new EnableAll (line)); } - public void WarningEnable (Location location, int code) + public void WarningEnable (Location location, int code, Report Report) { - if (Report.CheckWarningCode (code, location)) - regions.Add (new Enable (location.Row, code)); + if (!Report.CheckWarningCode (code, location)) + return; + + if (Report.IsWarningDisabledGlobally (code)) + Report.Warning (1635, 1, location, "Cannot restore warning `CS{0:0000}' because it was disabled globally", code); + + regions.Add (new Enable (location.Row, code)); } public bool IsWarningEnabled (int code, int src_line)