New tests.
[mono.git] / mcs / class / corlib / System / Exception.cs
1 //
2 // System.Exception.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Patrik Torstensson
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Collections;
32 using System.Diagnostics;
33 using System.Reflection;
34 using System.Text;
35 using System.Runtime.InteropServices;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.Serialization;
38 using System.Security.Permissions;
39
40 namespace System
41 {
42         [Serializable]
43         [ComVisible(true)]
44         [ComDefaultInterface (typeof (_Exception))]
45         [ClassInterface (ClassInterfaceType.None)]
46         public class Exception : ISerializable, _Exception
47         {
48 #pragma warning disable 169, 649
49                 #region Sync with object-internals.h
50                 /* Stores the IPs and the generic sharing infos
51                    (vtable/MRGCTX) of the frames. */
52                 IntPtr [] trace_ips;
53                 Exception inner_exception;
54                 internal string message;
55                 string help_link;
56                 string class_name;
57                 string stack_trace;
58                 // formerly known as remote_stack_trace (see #425512):
59                 string _remoteStackTraceString;
60                 int remote_stack_index;
61                 internal int hresult = -2146233088;
62                 string source;
63                 IDictionary _data;
64                 #endregion
65 #pragma warning restore 169, 649                
66
67                 public Exception ()
68                 {
69                 }
70
71                 public Exception (string message)
72                 {
73                         this.message = message;
74                 }
75
76                 protected Exception (SerializationInfo info, StreamingContext context)
77                 {
78                         if (info == null)
79                                 throw new ArgumentNullException ("info");
80
81                         class_name          = info.GetString ("ClassName");
82                         message             = info.GetString ("Message");
83                         help_link           = info.GetString ("HelpURL");
84                         stack_trace         = info.GetString ("StackTraceString");
85                         _remoteStackTraceString  = info.GetString ("RemoteStackTraceString");
86                         remote_stack_index  = info.GetInt32  ("RemoteStackIndex");
87                         hresult             = info.GetInt32  ("HResult");
88                         source              = info.GetString ("Source");
89                         inner_exception     = (Exception) info.GetValue ("InnerException", typeof (Exception));
90
91                         try {
92                                 _data = (IDictionary) info.GetValue ("Data", typeof (IDictionary));
93                         } catch (SerializationException) {
94                                 // member did not exist in .NET 1.x
95                         }
96                 }
97
98                 public Exception (string message, Exception innerException)
99                 {
100                         inner_exception = innerException;
101                         this.message = message;
102                 }
103
104                 public Exception InnerException {
105                         get { return inner_exception; }
106                 }
107
108                 public virtual string HelpLink {
109                         get { return help_link; }
110                         set { help_link = value; }
111                 }
112
113                 protected int HResult {
114                         get { return hresult; }
115                         set { hresult = value; }
116                 }
117
118                 internal void SetMessage (string s)
119                 {
120                         message = s;
121                 }
122
123                 internal void SetStackTrace (string s)
124                 {
125                         stack_trace = s;
126                 }
127
128                 string ClassName {
129                         get {
130                                 if (class_name == null)
131                                         class_name = GetType ().ToString ();
132                                 return class_name;
133                         }
134                 }
135
136                 public virtual string Message {
137                         get {
138                                 if (message == null)
139                                         message = string.Format (Locale.GetText ("Exception of type '{0}' was thrown."),
140                                                 ClassName);
141
142                                 return message;
143                         }
144                 }
145
146                 public virtual string Source {
147                         get {
148                                 if (source == null) {
149                                         StackTrace st = new StackTrace (this, true);
150                                         if (st.FrameCount > 0) {
151                                                 StackFrame sf = st.GetFrame (0);
152                                                 if (st != null) {
153                                                         MethodBase method = sf.GetMethod ();
154                                                         if (method != null) {
155                                                                 source = method.DeclaringType.Assembly.UnprotectedGetName ().Name;
156                                                         }
157                                                 }
158                                         }
159                                 }
160
161                                 // source can be null
162                                 return source;
163                         }
164
165                         set {
166                                 source = value;
167                         }
168                 }
169
170                 public virtual string StackTrace {
171                         get {
172                                 if (stack_trace == null) {
173                                         if (trace_ips == null)
174                                                 /* Not thrown yet */
175                                                 return null;
176
177                                         StackTrace st = new StackTrace (this, 0, true, true);
178
179                                         StringBuilder sb = new StringBuilder ();
180
181                                         string newline = String.Format ("{0}  {1} ", Environment.NewLine, Locale.GetText ("at"));
182                                         string unknown = Locale.GetText ("<unknown method>");
183
184                                         for (int i = 0; i < st.FrameCount; i++) {
185                                                 StackFrame frame = st.GetFrame (i);
186                                                 if (i == 0)
187                                                         sb.AppendFormat ("  {0} ", Locale.GetText ("at"));
188                                                 else
189                                                         sb.Append (newline);
190
191                                                 if (frame.GetMethod () == null) {
192                                                         string internal_name = frame.GetInternalMethodName ();
193                                                         if (internal_name != null)
194                                                                 sb.Append (internal_name);
195                                                         else
196                                                                 sb.AppendFormat ("<0x{0:x5}> {1}", frame.GetNativeOffset (), unknown);
197                                                 } else {
198                                                         GetFullNameForStackTrace (sb, frame.GetMethod ());
199
200                                                         if (frame.GetILOffset () == -1)
201                                                                 sb.AppendFormat (" <0x{0:x5}> ", frame.GetNativeOffset ());
202                                                         else
203                                                                 sb.AppendFormat (" [0x{0:x5}] ", frame.GetILOffset ());
204
205                                                         sb.AppendFormat ("in {0}:{1} ", frame.GetSecureFileName (), 
206                                                                 frame.GetFileLineNumber ());
207                                                 }
208                                         }
209                                         stack_trace = sb.ToString ();
210                                 }
211
212                                 return stack_trace;
213                         }
214                 }
215
216                 public MethodBase TargetSite {
217                         get {
218                                 StackTrace st = new StackTrace (this, true);
219                                 if (st.FrameCount > 0)
220                                         return st.GetFrame (0).GetMethod ();
221                                 
222                                 return null;
223                         }
224                 }
225
226                 public virtual IDictionary Data {
227                         get {
228                                 if (_data == null) {
229                                         // default to empty dictionary
230                                         _data = (IDictionary) new Hashtable ();
231                                 }
232                                 return _data;
233                         }
234                 }
235
236                 public virtual Exception GetBaseException ()
237                 {
238                         Exception inner = inner_exception;
239                                 
240                         while (inner != null)
241                         {
242                                 if (inner.InnerException != null)
243                                         inner = inner.InnerException;
244                                 else
245                                         return inner;
246                         }
247
248                         return this;
249                 }
250
251                 [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
252                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
253                 {
254                         if (info == null)
255                                 throw new ArgumentNullException ("info");
256
257                         info.AddValue ("ClassName", ClassName);
258                         info.AddValue ("Message", message);
259                         info.AddValue ("InnerException", inner_exception);
260                         info.AddValue ("HelpURL", help_link);
261                         info.AddValue ("StackTraceString", StackTrace);
262                         info.AddValue ("RemoteStackTraceString", _remoteStackTraceString);
263                         info.AddValue ("RemoteStackIndex", remote_stack_index);
264                         info.AddValue ("HResult", hresult);
265 #if !MOONLIGHT
266                         info.AddValue ("Source", Source);
267 #else
268                         info.AddValue ("Source", null);
269 #endif
270                         info.AddValue ("ExceptionMethod", null);
271                         info.AddValue ("Data", _data, typeof (IDictionary));
272                 }
273
274                 public override string ToString ()
275                 {
276                         System.Text.StringBuilder result = new System.Text.StringBuilder (ClassName);
277                         result.Append (": ").Append (Message);
278
279                         if (null != _remoteStackTraceString)
280                                 result.Append (_remoteStackTraceString);
281                                 
282                         if (inner_exception != null) 
283                         {
284                                 result.Append (" ---> ").Append (inner_exception.ToString ());
285                                 result.Append (Environment.NewLine);
286                                 result.Append (Locale.GetText ("  --- End of inner exception stack trace ---"));
287                         }
288
289                         if (StackTrace != null)
290                                 result.Append (Environment.NewLine).Append (StackTrace);
291                         return result.ToString();
292                 }
293
294                 internal Exception FixRemotingException ()
295                 {
296                         string message = (0 == remote_stack_index) ?
297                                 Locale.GetText ("{0}{0}Server stack trace: {0}{1}{0}{0}Exception rethrown at [{2}]: {0}") :
298                                 Locale.GetText ("{1}{0}{0}Exception rethrown at [{2}]: {0}");
299                         string tmp = String.Format (message, Environment.NewLine, StackTrace, remote_stack_index);
300
301                         _remoteStackTraceString = tmp;
302                         remote_stack_index++;
303
304                         stack_trace = null;
305
306                         return this;
307                 }
308
309                 internal void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
310                 {
311                         ParameterInfo[] p = mi.GetParameters ();
312                         sb.Append (mi.DeclaringType.ToString ());
313                         sb.Append (".");
314                         sb.Append (mi.Name);
315
316                         if (mi.IsGenericMethod) {
317                                 Type[] gen_params = mi.GetGenericArguments ();
318                                 sb.Append ("[");
319                                 for (int j = 0; j < gen_params.Length; j++) {
320                                         if (j > 0)
321                                                 sb.Append (",");
322                                         sb.Append (gen_params [j].Name);
323                                 }
324                                 sb.Append ("]");
325                         }
326
327                         sb.Append (" (");
328                         for (int i = 0; i < p.Length; ++i) {
329                                 if (i > 0)
330                                         sb.Append (", ");
331                                 Type pt = p[i].ParameterType;
332                                 if (pt.IsClass && pt.Namespace != String.Empty) {
333                                         sb.Append (pt.Namespace);
334                                         sb.Append (".");
335                                 }
336                                 sb.Append (pt.Name);
337                                 if (p [i].Name != null) {
338                                         sb.Append (" ");
339                                         sb.Append (p [i].Name);
340                                 }
341                         }
342                         sb.Append (")");
343                 }
344
345                 //
346                 // The documentation states that this is available in 1.x,
347                 // but it was not available (MemberRefing this would fail)
348                 // and it states the signature is `override sealed', but the
349                 // correct value is `newslot' 
350                 //
351                 public new Type GetType ()
352                 {
353                         return base.GetType ();
354                 }
355         }
356 }