bluebonnet/Baselib/src/System/Exception.cs
2020-08-26 11:23:24 +03:00

331 lines
10 KiB
C#

namespace system
{
[System.Serializable]
public class Exception : java.lang.Exception, System.Runtime.Serialization.ISerializable
{
[java.attr.RetainType] private bool fillInStackTraceWasIgnoredOnce;
[java.attr.RetainType] private int _HResult = unchecked((int)0x80131500); // COR_E_EXCEPTION
// some derived exceptions (e.g. TypeLoadException) reference this field directly
public string _message;
public Exception() : base()
{
}
public Exception(string message) : base(message)
{
_message = message;
}
public Exception(string message, java.lang.Throwable innerException)
: base(message, innerException)
{
_message = message;
}
protected Exception(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
throw new System.NotImplementedException();
}
//
// there is a circular dependency where the java.lang.Throwable imported by
// DotNetImporter.cs is made a subtype of System.Exception, and here we have
// system.Exception as a subtype of java.lang.Exception. we have to decorate
// some methods with [java.attr.RetainName] to prevent method renaming due to
// shadowing, as done by CilMethod.cs MethodIsShadowing().
//
//new public virtual System.Collections.IDictionary Data { [java.attr.RetainName] get; }
new public virtual string HelpLink { [java.attr.RetainName] get; [java.attr.RetainName] set; }
new protected int HResult
{
[java.attr.RetainName] get => _HResult;
[java.attr.RetainName] set => _HResult = value;
}
new public System.Exception InnerException { [java.attr.RetainName] get => base.getCause(); }
new public virtual string Message
{
[java.attr.RetainName] get
{
if (_message != null)
return _message;
// xxx translate to GetResourceString ?
return base.getMessage() ??
("Exception of type '" + GetClassName() + "' was thrown.");
}
}
new public virtual string Source { [java.attr.RetainName] get; [java.attr.RetainName] set; }
new public virtual string StackTrace
{
[java.attr.RetainName] get => get_StackTrace(this);
}
//public System.Reflection.MethodBase TargetSite { get; }
public static string get_HelpLink(java.lang.Throwable exc)
{
if (exc is system.Exception clrExc)
return clrExc.HelpLink;
else
return "";
}
public static int get_HResult(java.lang.Throwable exc)
{
if (exc is system.Exception clrExc)
return clrExc.HResult;
else
return unchecked((int)0x80131500); // COR_E_EXCEPTION
}
public static System.Exception get_InnerException(java.lang.Throwable exc)
{
if (exc is system.Exception clrExc)
return clrExc.InnerException;
else
return exc.getCause();
}
public static string get_Message(java.lang.Throwable exc)
{
if (exc is system.Exception clrExc)
return clrExc.Message;
else
return exc.getMessage();
}
public static string get_Source(java.lang.Throwable exc)
{
if (exc is system.Exception clrExc)
return clrExc.Source;
else
return "";
}
public static string get_StackTrace(java.lang.Throwable exc)
{
var elems = exc.getStackTrace();
int n = elems?.Length ?? 0;
if (n == 0)
return null;
var sb = new java.lang.StringBuilder();
for (int i = 0; i < n; i++)
{
var elem = elems[i];
if (i > 0)
sb.append("\n");
sb.append(" at ");
sb.append(elem.getClassName());
sb.append(".");
sb.append(elem.getMethodName());
sb.append("() in ");
sb.append(elem.getFileName());
sb.append(":line ");
sb.append(elem.getLineNumber());
}
return sb.ToString();
}
/*internal static void SetErrorCode(java.lang.Throwable exc, int hr)
{
if (exc is system.Exception clrExc)
clrExc.HResult = hr;
}*/
[java.attr.RetainName] internal void SetErrorCode(int hr) => HResult = hr;
public override java.lang.Throwable fillInStackTrace()
{
//
// java collects the stack trace when the exception is allocated,
// from the java.lang.Throwable constructor. but cil collects the
// stack trace only when the exception is thrown.
//
// our cil exceptions inherit from Throwable, so we need to ignore
// the initial call to fillInStackTrace. our implementation of the
// cil 'throw' instruction calls fillInStackTrace.
//
if (fillInStackTraceWasIgnoredOnce)
return base.fillInStackTrace();
fillInStackTraceWasIgnoredOnce = true;
return this;
}
public override string ToString()
{
string s = GetClassName() + ": " + this.Message;
string t = this.StackTrace;
if (t != null)
s += "\n" + t;
var e = InnerException;
if (! object.ReferenceEquals(e, null))
s += "\nInner exception: " + e;
return s;
}
[java.attr.RetainName]
private string GetClassName() => ((java.lang.Object) (object) this).GetType().FullName;
//
// System.Exception includes the following method, to prevent compiler
// from making System.Object::GetType() virtual. we need the same
// workaround, because exception objects have a circular chain of inheritance:
//
// SomeException -> system.Exception -> java.lang.Exception ...
// ... -> java.lang.Throwable -> System.Exception -> System.Object
//
// System.Exception references the System.Runtime.InteropServices::_Exception
// interface, and our InterfaceBuilder::CollectMethods sees the method
// System.Exception::GetType() as an appropriate implementation. so we are
// required to actually provide such a method as system.Exception::GetType().
//
new public System.Type GetType() => ((java.lang.Object) (object) this).GetType();
}
/*
*
* Util Helpers
*
*/
public static partial class Util
{
[java.attr.RetainType] private static java.util.concurrent.ConcurrentHashMap exceptionMap =
new java.util.concurrent.ConcurrentHashMap();
internal delegate System.Exception ExceptionTranslator(java.lang.Throwable exc);
internal static void DefineException(java.lang.Class type, ExceptionTranslator dlg)
{
exceptionMap.put(type, dlg);
}
public static java.lang.Throwable TranslateException(java.lang.Throwable exc)
{
System.Exception newExc = null;
if (exc is system.Exception)
return exc;
var dlg = (ExceptionTranslator) exceptionMap.get(
((java.lang.Object) (object) exc).getClass());
if (dlg != null)
newExc = dlg(exc);
if (newExc == null)
{
if (exc is java.lang.NullPointerException)
newExc = new System.NullReferenceException();
/*if (exc is java.lang.IllegalArgumentException)
newExc = new System.ArgumentException();*/
if (exc is java.lang.ArithmeticException && exc.getMessage() == "/ by zero")
newExc = new System.DivideByZeroException(); // "Attempted to divide by zero."
// also: IndexOutOfRangeException. define in Array? not necessarily.
// fixme: move these to specialized exceptionMap ?
if (newExc == null)
return exc;
/*if (newExc == null)
{
// any throwable not deriving from system.Exception is assumed
// to be coming from the JVM or java code. If it was not mapped
// to some known .NET exception, wrap it in an ExternalException
// newExc = new Exception("Java exception: " + exc.GetType());
// fixme System.Runtime.InteropServices.ExternalException ???
Console.WriteLine("Created New Exception: ");
Console.WriteLine(newExc);
Console.WriteLine("Continuing...");
}*/
}
java.lang.Throwable newThrowable = (java.lang.Throwable) newExc;
newThrowable.setStackTrace(exc.getStackTrace());
return newThrowable;
}
}
public class TryCatchLeaveTarget : java.lang.VirtualMachineError
{
// this fake-exception is used in the implementation of
// 'leave' instruction, when there is also a 'finally' clause.
// see also: Translate_Leave in CodeExcept.
private int Target;
public override java.lang.Throwable fillInStackTrace() => this;
private TryCatchLeaveTarget(int _target) { Target = _target; }
public static java.lang.Throwable New(int _target) => new TryCatchLeaveTarget(_target);
public static int Get(java.lang.Throwable t) => t is TryCatchLeaveTarget t1 ? t1.Target : -1;
}
}