In .:
[mono.git] / mcs / gmcs / report.cs
index 3867550c5b81396ea431aee679adacbddcda2e4c..b6f2842e2daffae2e184bbe06a27ee39652168cd 100644 (file)
 // FIXME: currently our class library does not support custom number format strings
 //
 using System;
+using System.IO;
 using System.Text;
 using System.Collections;
+using System.Collections.Specialized;
 using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Emit;
 
 namespace Mono.CSharp {
 
@@ -44,6 +48,8 @@ namespace Mono.CSharp {
                ///   Whether to dump a stack trace on errors. 
                /// </summary>
                static public bool Stacktrace;
+
+               static public TextWriter Stderr = Console.Error;
                
                //
                // If the 'expected' error code is reported then the
@@ -56,129 +62,348 @@ namespace Mono.CSharp {
                //
                // Keeps track of the warnings that we are ignoring
                //
-               static Hashtable warning_ignore_table;
-               
-               static void Check (int code)
+               public static Hashtable warning_ignore_table;
+
+               static Hashtable warning_regions_table;
+
+               /// <summary>
+               /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
+               /// </summary>
+               static StringCollection extra_information = new StringCollection ();
+
+               public static void Reset ()
                {
-                       if (code == expected_error){
-                               if (Fatal)
-                                       throw new Exception ();
-                               
-                               Environment.Exit (0);
+                       Errors = Warnings = 0;
+                       WarningsAreErrors = false;
+                       warning_ignore_table = null;
+                       warning_regions_table = null;
+               }
+
+               abstract class AbstractMessage {
+
+                       static void Check (int code)
+                       {
+                               if (code == expected_error) {
+                                       Environment.Exit (0);
+                               }
+                       }
+
+                       public abstract bool IsWarning { get; }
+
+                       public abstract string MessageType { get; }
+
+                       public virtual void Print (int code, string location, string text)
+                       {
+                               if (code < 0)
+                                       code = 8000-code;
+
+                               StringBuilder msg = new StringBuilder ();
+                               if (location.Length != 0) {
+                                       msg.Append (location);
+                                       msg.Append (' ');
+                               }
+                               msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
+                               Stderr.WriteLine (msg.ToString ());
+
+                               foreach (string s in extra_information) 
+                                       Stderr.WriteLine (s + MessageType);
+
+                               extra_information.Clear ();
+
+                               if (Stacktrace)
+                                       Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
+
+                               if (Fatal) {
+                                       if (!IsWarning || WarningsAreErrors)
+                                               throw new Exception (text);
+                               }
+
+                               Check (code);
+                       }
+
+                       public virtual void Print (int code, Location location, string text)
+                       {
+                               if (location.Equals (Location.Null)) {
+                                       Print (code, "", text);
+                                       return;
+                               }
+                               Print (code, String.Format ("{0}({1})", location.Name, location.Row), text);
                        }
                }
-               
-               static public void RealError (string msg)
-               {
-                       Errors++;
-                       Console.WriteLine (msg);
 
-                       if (Stacktrace)
-                               Console.WriteLine (new StackTrace ().ToString ());
-                       if (Fatal)
-                               throw new Exception (msg);
+               sealed class WarningMessage: AbstractMessage {
+                       Location loc = Location.Null;
+                       readonly int Level;
+
+                       public WarningMessage ():
+                               this (-1) {}
+
+                       public WarningMessage (int level)
+                       {
+                               Level = level;
+                       }
+
+                       public override bool IsWarning {
+                               get { return true; }
+                       }
+
+                       bool IsEnabled (int code)
+                       {
+                               if (RootContext.WarningLevel < Level)
+                                       return false;
+
+                               if (warning_ignore_table != null) {
+                                       if (warning_ignore_table.Contains (code)) {
+                                               return false;
+                                       }
+                               }
+
+                               if (warning_regions_table == null || loc.Equals (Location.Null))
+                                       return true;
+
+                               WarningRegions regions = (WarningRegions)warning_regions_table [loc.Name];
+                               if (regions == null)
+                                       return true;
+
+                               return regions.IsWarningEnabled (code, loc.Row);
+                       }
+
+                       public override void Print(int code, string location, string text)
+                       {
+                               if (!IsEnabled (code)) {
+                                       extra_information.Clear ();
+                                       return;
+                               }
+
+                               if (WarningsAreErrors) {
+                                       new ErrorMessage ().Print (code, location, text);
+                                       return;
+                               }
+
+                               Warnings++;
+                               base.Print (code, location, text);
+                       }
+
+                       public override void Print(int code, Location location, string text)
+                       {
+                               loc = location;
+                               base.Print (code, location, text);
+                       }
+
+                       public override string MessageType {
+                               get {
+                                       return "warning";
+                               }
+                       }
                }
 
-               static public void Error (int code, Location l, string text)
-               {
-                       if (code < 0)
-                               code = 8000-code;
-                       
-                       string msg = String.Format (
-                               "{0}({1}) error CS{2:0000}: {3}", l.Name, l.Row, code, text);
-//                             "{0}({1}) error CS{2}: {3}", l.Name, l.Row, code, text);
-                       
-                       RealError (msg);
-                       Check (code);
+               sealed class ErrorMessage: AbstractMessage {
+
+                       public override void Print(int code, string location, string text)
+                       {
+                               Errors++;
+                               base.Print (code, location, text);
+                       }
+
+                       public override bool IsWarning {
+                               get { return false; }
+                       }
+
+                       public override string MessageType {
+                               get {
+                                       return "error";
+                               }
+                       }
+
                }
 
-               static public void Warning (int code, Location l, string text)
+               public static void FeatureIsNotStandardized (Location loc, string feature)
+               {
+                       Report.Error (1644, loc, "Feature `{0}' cannot be used because it is not part of the standardized ISO C# language specification", feature);
+               }
+               
+               public static string FriendlyStackTrace (Exception e)
                {
-                       if (code < 0)
-                               code = 8000-code;
+                       return FriendlyStackTrace (new StackTrace (e, true));
+               }
+               
+               static string FriendlyStackTrace (StackTrace t)
+               {               
+                       StringBuilder sb = new StringBuilder ();
                        
-                       if (warning_ignore_table != null){
-                               if (warning_ignore_table.Contains (code))
-                                       return;
-                       }
+                       bool foundUserCode = false;
                        
-                       if (WarningsAreErrors)
-                               Error (code, l, text);
-                       else {
-                               string row;
+                       for (int i = 0; i < t.FrameCount; i++) {
+                               StackFrame f = t.GetFrame (i);
+                               MethodBase mb = f.GetMethod ();
                                
-                               if (Location.IsNull (l))
-                                       row = "";
-                               else
-                                       row = l.Row.ToString ();
+                               if (!foundUserCode && mb.ReflectedType == typeof (Report))
+                                       continue;
                                
-                               Console.WriteLine (String.Format (
-                                       "{0}({1}) warning CS{2:0000}: {3}",
-//                                     "{0}({1}) warning CS{2}: {3}",
-                                       l.Name,  row, code, text));
-                               Warnings++;
-                               Check (code);
+                               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");
+                       }
+       
+                       return sb.ToString ();
+               }
 
-                               if (Stacktrace)
-                                       Console.WriteLine (new StackTrace ().ToString ());
+               public static void StackTrace ()
+               {
+                       Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
+               }
+
+               // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+               // IF YOU ADD A NEW WARNING YOU HAVE TO DUPLICATE ITS ID HERE
+               //
+               public static bool IsValidWarning (int code)
+               {
+                       int[] all_warnings = new int[] {
+                               28, 67, 78, 105, 108, 109, 114, 192, 168, 169, 183, 184, 219, 251, 612, 618, 626, 628, 642, 649,
+                               659, 660, 661, 672, 1030, 1522, 1616, 1691, 1692, 1901, 2002, 2023, 3012, 3019, 8024, 8028, 3005
+                       };
+                       
+                       foreach (int i in all_warnings) {
+                               if (i == code)
+                                       return true;
                        }
+                       return false;
                }
                
-               static public void Warning (int code, string text)
+               static public void LocationOfPreviousError (Location loc)
                {
-                       Warning (code, Location.Null, text);
+                       Stderr.WriteLine (String.Format ("{0}({1}) (Location of symbol related to previous error)", loc.Name, loc.Row));
+               }    
+        
+               static public void RuntimeMissingSupport (Location loc, string feature) 
+               {
+                       Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
                }
 
-               static public void Warning (int code, int level, string text)
+               /// <summary>
+               /// 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.
+               /// </summary>
+               static public void SymbolRelatedToPreviousError (Location loc, string symbol)
                {
-                       if (RootContext.WarningLevel >= level)
-                               Warning (code, Location.Null, text);
+                       SymbolRelatedToPreviousError (String.Format ("{0}({1})", loc.Name, loc.Row), symbol);
                }
 
-               static public void Warning (int code, int level, Location l, string text)
+               static public void SymbolRelatedToPreviousError (MemberInfo mi)
                {
-                       if (RootContext.WarningLevel >= level)
-                               Warning (code, l, text);
+                       TypeContainer temp_ds = TypeManager.LookupGenericTypeContainer (mi.DeclaringType);
+                       if (temp_ds == null) {
+                               SymbolRelatedToPreviousError (mi.DeclaringType.Assembly.Location, TypeManager.GetFullNameSignature (mi));
+                       } else {
+                               MethodBase mb = mi as MethodBase;
+                               if (mb != null) {
+                                       while (mb.Mono_IsInflatedMethod)
+                                               mb = mb.GetGenericMethodDefinition ();
+                                       IMethodData md = TypeManager.GetMethod (mb);
+                                       SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
+                                       return;
+                               }
+
+                               MemberCore mc = temp_ds.GetDefinition (mi.Name);
+                               SymbolRelatedToPreviousError (mc);
+                       }
                }
 
-               static public void Error (int code, string text)
+               static public void SymbolRelatedToPreviousError (MemberCore mc)
                {
-                       if (code < 0)
-                               code = 8000-code;
-                       
-                       string msg = String.Format ("error CS{0:0000}: {1}", code, text);
-//                     string msg = String.Format ("error CS{0}: {1}", code, text);
-                       
-                       RealError (msg);
-                       Check (code);
+                       SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
                }
 
-               static public void Error (int code, Location loc, string format, params object[] args)
+               static public void SymbolRelatedToPreviousError (Type type)
                {
-                       Error (code, loc, String.Format (format, args));
+                       if (type.IsGenericInstance)
+                               type = type.GetGenericTypeDefinition ();
+                       if (type is TypeBuilder) {
+                               DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
+                               SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
+                       } else if (type.HasElementType) {
+                               SymbolRelatedToPreviousError (type.GetElementType ());
+                       } else {
+                               SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
+                       }
                }
 
-               static public void Error (int code, string format, params object[] args)
+               static void SymbolRelatedToPreviousError (string loc, string symbol)
+               {
+                       extra_information.Add (String.Format ("{0}: `{1}' (name of symbol related to previous ", loc, symbol));
+               }
+
+               public static void ExtraInformation (Location loc, string msg)
                {
-                       Error (code, String.Format (format, args));
+                       extra_information.Add (String.Format ("{0}({1}) {2}", loc.Name, loc.Row, 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;
+               }
+
+               static public void Warning (int code, int level, Location loc, string format, params object[] args)
+               {
+                       WarningMessage w = new WarningMessage (level);
+                       w.Print (code, loc, String.Format (format, args));
                }
 
                static public void Warning (int code, Location loc, string format, params object[] args)
                {
-                       Warning (code, loc, String.Format (format, args));
+                       WarningMessage w = new WarningMessage ();
+                       w.Print (code, loc, String.Format (format, args));
                }
 
                static public void Warning (int code, string format, params object[] args)
                {
-                       Warning (code, String.Format (format, args));
+                       Warning (code, Location.Null, String.Format (format, args));
                }
 
-               static public void Message (Message m)
+               /// <summary>
+               /// Did you test your WarningLevel, that you use this method
+               /// </summary>
+               static public void Warning (int code, string text)
                {
-                       if (m is ErrorMessage)
-                               Error (m.code, m.text);
-                       else
-                               Warning (m.code, m.text);
+                       Warning (code, Location.Null, text);
+               }
+
+               static public void Error (int code, string format, params object[] args)
+               {
+                       Error (code, Location.Null, String.Format (format, args));
+               }
+
+               static public void Error (int code, Location loc, string format, params object[] args)
+               {
+                       Error (code, loc, String.Format (format, args));
+               }
+
+               static public void Error (int code, Location loc, string error)
+               {
+                       new ErrorMessage ().Print (code, loc, error);
                }
 
                static public void SetIgnoreWarning (int code)
@@ -189,14 +414,14 @@ namespace Mono.CSharp {
                        warning_ignore_table [code] = true;
                }
                
-                static public int ExpectedError {
-                        set {
-                                expected_error = value;
-                        }
-                        get {
-                                return expected_error;
-                        }
-                }
+               static public int ExpectedError {
+                       set {
+                               expected_error = value;
+                       }
+                       get {
+                               return expected_error;
+                       }
+               }
 
                public static int DebugFlags = 0;
 
@@ -227,8 +452,6 @@ namespace Mono.CSharp {
                                                sb.Append ("null");
                                        else if (arg is ICollection)
                                                sb.Append (PrintCollection ((ICollection) arg));
-                                       else if (arg is IntPtr)
-                                               sb.Append (String.Format ("IntPtr(0x{0:x})", ((IntPtr) arg).ToInt32 ()));
                                        else
                                                sb.Append (arg);
                                }
@@ -258,38 +481,6 @@ namespace Mono.CSharp {
                }
        }
 
-       public class Message {
-               public int code;
-               public string text;
-               
-               public Message (int code, string text)
-               {
-                       this.code = code;
-                       this.text = text;
-               }
-       }
-
-       public class WarningMessage : Message {
-               public WarningMessage (int code, string text) : base (code, text)
-               {
-               }
-       }
-
-       public class ErrorMessage : Message {
-               public ErrorMessage (int code, string text) : base (code, text)
-               {
-               }
-
-               //
-               // For compatibility reasons with old code.
-               //
-               public static void report_error (string error)
-               {
-                       Console.Write ("ERROR: ");
-                       Console.WriteLine (error);
-               }
-       }
-
        public enum TimerType {
                FindMembers     = 0,
                TcFindMembers   = 1,
@@ -386,9 +577,121 @@ namespace Mono.CSharp {
                        : base (message)
                {
                }
+       }
+
+       /// <summary>
+       /// Handles #pragma warning
+       /// </summary>
+       public class WarningRegions {
+
+               abstract class PragmaCmd
+               {
+                       public int Line;
+
+                       protected PragmaCmd (int line)
+                       {
+                               Line = line;
+                       }
+
+                       public abstract bool IsEnabled (int code, bool previous);
+               }
+               
+               class Disable: PragmaCmd
+               {
+                       int code;
+                       public Disable (int line, int code)
+                               : base (line)
+                       {
+                               this.code = code;
+                       }
 
-               public InternalErrorException (string format, params object[] args)
-                       : this (String.Format (format, args))
-               { }
+                       public override bool IsEnabled (int code, bool previous)
+                       {
+                               return this.code == code ? false : previous;
+                       }
+               }
+
+               class DisableAll: PragmaCmd
+               {
+                       public DisableAll (int line)
+                               : base (line) {}
+
+                       public override bool IsEnabled(int code, bool previous)
+                       {
+                               return false;
+                       }
+               }
+
+               class Enable: PragmaCmd
+               {
+                       int code;
+                       public Enable (int line, int code)
+                               : base (line)
+                       {
+                               this.code = code;
+                       }
+
+                       public override bool IsEnabled(int code, bool previous)
+                       {
+                               return this.code == code ? true : previous;
+                       }
+               }
+
+               class EnableAll: PragmaCmd
+               {
+                       public EnableAll (int line)
+                               : base (line) {}
+
+                       public override bool IsEnabled(int code, bool previous)
+                       {
+                               return true;
+                       }
+               }
+
+
+               ArrayList regions = new ArrayList ();
+
+               public void WarningDisable (int line)
+               {
+                       regions.Add (new DisableAll (line));
+               }
+
+               public void WarningDisable (Location location, int code)
+               {
+                       if (CheckWarningCode (code, location))
+                               regions.Add (new Disable (location.Row, code));
+               }
+
+               public void WarningEnable (int line)
+               {
+                       regions.Add (new EnableAll (line));
+               }
+
+               public void WarningEnable (Location location, int code)
+               {
+                       if (CheckWarningCode (code, location))
+                               regions.Add (new Enable (location.Row, code));
+               }
+
+               public bool IsWarningEnabled (int code, int src_line)
+               {
+                       bool result = true;
+                       foreach (PragmaCmd pragma in regions) {
+                               if (src_line < pragma.Line)
+                                       break;
+
+                               result = pragma.IsEnabled (code, result);
+                       }
+                       return result;
+               }
+
+               bool CheckWarningCode (int code, Location loc)
+               {
+                       if (Report.IsValidWarning (code))
+                               return true;
+
+                       Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code);
+                       return false;
+               }
        }
 }