BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / corlib / System.Diagnostics / StackTrace.cs
index 808c71dad3e35287ef61a425396d7a5fc271dc01..5fd14cc6d717a8f5b03fb12c7529400674f9e729 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System.Collections;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Security;
 using System.Security.Permissions;
 using System.Text;
 using System.Threading;
@@ -40,21 +41,23 @@ using System.Threading;
 namespace System.Diagnostics {
 
        [Serializable]
-       [MonoTODO ("Fix serialization compatibility with MS.NET")]
+       [ComVisible (true)]
+       [MonoTODO ("Serialized objects are not compatible with .NET")]
        public class StackTrace {
 
                public const int METHODS_TO_SKIP = 0;
 
                private StackFrame[] frames;
+               private bool debug_info;
 
                public StackTrace ()
                {
                        init_frames (METHODS_TO_SKIP, false);
                }
 
-               public StackTrace (bool needFileInfo)
+               public StackTrace (bool fNeedFileInfo)
                {
-                       init_frames (METHODS_TO_SKIP, needFileInfo);
+                       init_frames (METHODS_TO_SKIP, fNeedFileInfo);
                }
 
                public StackTrace (int skipFrames)
@@ -62,41 +65,42 @@ namespace System.Diagnostics {
                        init_frames (skipFrames, false);
                }
 
-               public StackTrace (int skipFrames, bool needFileInfo)
+               public StackTrace (int skipFrames, bool fNeedFileInfo)
                {
-                       init_frames (skipFrames, needFileInfo);
+                       init_frames (skipFrames, fNeedFileInfo);
                }
 
-               void init_frames (int skipFrames, bool needFileInfo)
+               void init_frames (int skipFrames, bool fNeedFileInfo)
                {
                        if (skipFrames < 0)
                                throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
 
                        StackFrame sf;
-                       ArrayList al = new ArrayList ();
+                       var l = new List<StackFrame> ();
 
                        skipFrames += 2;
                        
-                       while ((sf = new StackFrame (skipFrames, needFileInfo)) != null &&
+                       while ((sf = new StackFrame (skipFrames, fNeedFileInfo)) != null &&
                               sf.GetMethod () != null) {
                                
-                               al.Add (sf);
+                               l.Add (sf);
                                skipFrames++;
                        };
 
-                       frames = (StackFrame [])al.ToArray (typeof (StackFrame));       
+                       debug_info = fNeedFileInfo;
+                       frames = l.ToArray ();
                }
                
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static StackFrame [] get_trace (Exception e, int skipFrames, bool needFileInfo);
+               extern static StackFrame [] get_trace (Exception e, int skipFrames, bool fNeedFileInfo);
 
                public StackTrace (Exception e)
                        : this (e, METHODS_TO_SKIP, false)
                {
                }
 
-               public StackTrace (Exception e, bool needFileInfo)
-                       : this (e, METHODS_TO_SKIP, needFileInfo)
+               public StackTrace (Exception e, bool fNeedFileInfo)
+                       : this (e, METHODS_TO_SKIP, fNeedFileInfo)
                {
                }
 
@@ -105,31 +109,52 @@ namespace System.Diagnostics {
                {
                }
 
-               public StackTrace (Exception e, int skipFrames, bool needFileInfo)
+               public StackTrace (Exception e, int skipFrames, bool fNeedFileInfo)
+                       : this (e, skipFrames, fNeedFileInfo, false)
+               {
+               }
+
+               internal StackTrace (Exception e, int skipFrames, bool fNeedFileInfo, bool returnNativeFrames)
                {
                        if (e == null)
                                throw new ArgumentNullException ("e");
                        if (skipFrames < 0)
                                throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
 
-                       frames = get_trace (e, skipFrames, needFileInfo);
+                       frames = get_trace (e, skipFrames, fNeedFileInfo);
+
+                       if (!returnNativeFrames) {
+                               bool resize = false;
+                               for (int i = 0; i < frames.Length; ++i)
+                                       if (frames [i].GetMethod () == null)
+                                               resize = true;
+
+                               if (resize) {
+                                       var l = new List<StackFrame> ();
+
+                                       for (int i = 0; i < frames.Length; ++i)
+                                               if (frames [i].GetMethod () != null)
+                                                       l.Add (frames [i]);
+
+                                       frames = l.ToArray ();
+                               }
+                       }
                }
 
-#if ONLY_1_1
-               [ReflectionPermission (SecurityAction.Demand, TypeInformation = true)]
-#endif
                public StackTrace (StackFrame frame)
                {
                        this.frames = new StackFrame [1];
                        this.frames [0] = frame;
                }
 
-#if ONLY_1_1
-               [ReflectionPermission (SecurityAction.Demand, TypeInformation = true)]
-#endif
-               [MonoTODO]
+               [MonoLimitation ("Not possible to create StackTraces from other threads")]
                public StackTrace (Thread targetThread, bool needFileInfo)
                {
+                       if (targetThread == Thread.CurrentThread){
+                               init_frames (METHODS_TO_SKIP, needFileInfo);
+                               return;
+                       }
+                       
                        throw new NotImplementedException ();
                }
 
@@ -148,37 +173,62 @@ namespace System.Diagnostics {
                        return frames [index];
                }
 
-#if NET_2_0
                [ComVisibleAttribute (false)]
-               public virtual
-#else
-               // used for CAS implementation (before Fx 2.0)
-               internal
-#endif
-               StackFrame[] GetFrames ()
+               public virtual StackFrame[] GetFrames ()
                {
                        return frames;
                }
 
                public override string ToString ()
                {
-                       string newline = String.Format ("{0}\t {1} ", Environment.NewLine, Locale.GetText ("at"));
+                       string newline = String.Format ("{0}   {1} ", Environment.NewLine, Locale.GetText ("at"));
                        string unknown = Locale.GetText ("<unknown method>");
+                       string debuginfo = Locale.GetText (" in {0}:line {1}");
                        StringBuilder sb = new StringBuilder ();
                        for (int i = 0; i < FrameCount; i++) {
                                StackFrame frame = GetFrame (i);
-                               sb.Append (newline);
+                               if (i > 0)
+                                       sb.Append (newline);
+                               else
+                                       sb.AppendFormat ("   {0} ", Locale.GetText ("at"));
                                MethodBase method = frame.GetMethod ();
                                if (method != null) {
                                        // Method information available
-                                       sb.AppendFormat ("{0}.{1} ()", method.DeclaringType.FullName, method.Name);
+                                       sb.AppendFormat ("{0}.{1}", method.DeclaringType.FullName, method.Name);
+                                       /* Append parameter information */
+                                       sb.Append ("(");
+                                       ParameterInfo[] p = method.GetParameters ();
+                                       for (int j = 0; j < p.Length; ++j) {
+                                               if (j > 0)
+                                                       sb.Append (", ");
+                                               Type pt = p[j].ParameterType;
+                                               bool byref = pt.IsByRef;
+                                               if (byref)
+                                                       pt = pt.GetElementType ();
+                                               if (pt.IsClass && pt.Namespace != String.Empty) {
+                                                       sb.Append (pt.Namespace);
+                                                       sb.Append (".");
+                                               }
+                                               sb.Append (pt.Name);
+                                               if (byref)
+                                                       sb.Append (" ByRef");
+                                               sb.AppendFormat (" {0}", p [j].Name);
+                                       }
+                                       sb.Append (")");
                                }
                                else {
                                        // Method information not available
                                        sb.Append (unknown);
                                }
-                       }
 
+                               if (debug_info) {
+                                       // we were asked for debugging informations
+                                       // but that doesn't mean we have the debug information available
+                                       string fname = frame.GetSecureFileName ();
+                                       if (fname != "<filename unknown>")
+                                               sb.AppendFormat (debuginfo, fname, frame.GetFileLineNumber ());
+                               }
+                       }
                        return sb.ToString ();
                }
        }