| %module csharp_exceptions | |
| // throw is invalid in C++17 and later, only SWIG to use it | |
| #define TESTCASE_THROW1(T1) throw(T1) | |
| %{ | |
| #define TESTCASE_THROW1(T1) | |
| %} | |
| %include <exception.i> | |
| %inline %{ | |
| class Ex { | |
| const char *message; | |
| public: | |
| Ex(const char *msg) : message(msg) {} | |
| const char *what() { return message; } | |
| }; | |
| %} | |
| %exception ThrowByValue() { | |
| try { | |
| $action | |
| } catch(Ex e) { | |
| SWIG_exception(SWIG_DivisionByZero, e.what()); | |
| } | |
| } | |
| %exception ThrowByReference() { | |
| try { | |
| $action | |
| } catch(Ex &e) { | |
| SWIG_exception(SWIG_DivisionByZero, e.what()); | |
| } | |
| } | |
| %csnothrowexception NoThrowException() { | |
| try { | |
| $action | |
| } catch(Ex) { | |
| // swallowed | |
| } | |
| } | |
| %inline %{ | |
| // %exception tests | |
| void ThrowByValue() { throw Ex("ThrowByValue"); } | |
| void ThrowByReference() { throw Ex("ThrowByReference"); } | |
| // %csnothrowexception | |
| void NoThrowException() { throw Ex("NoThrowException"); } | |
| // exception specifications | |
| void ExceptionSpecificationValue() TESTCASE_THROW1(Ex) { throw Ex("ExceptionSpecificationValue"); } | |
| void ExceptionSpecificationReference() TESTCASE_THROW1(Ex&) { throw Ex("ExceptionSpecificationReference"); } | |
| void ExceptionSpecificationString() TESTCASE_THROW1(const char *) { throw "ExceptionSpecificationString"; } | |
| void ExceptionSpecificationInteger() TESTCASE_THROW1(int) { throw 20; } | |
| %} | |
| // test exceptions in the default typemaps | |
| // null reference exceptions | |
| %inline %{ | |
| void NullReference(Ex& e) {} | |
| void NullValue(Ex e) {} | |
| %} | |
| // enums | |
| %inline %{ | |
| enum TestEnum {TestEnumItem}; | |
| void ExceptionSpecificationEnumValue() TESTCASE_THROW1(TestEnum) { throw TestEnumItem; } | |
| void ExceptionSpecificationEnumReference() TESTCASE_THROW1(TestEnum&) { throw TestEnumItem; } | |
| %} | |
| // std::string | |
| %include <std_string.i> | |
| %inline %{ | |
| void ExceptionSpecificationStdStringValue() TESTCASE_THROW1(std::string) { throw std::string("ExceptionSpecificationStdStringValue"); } | |
| void ExceptionSpecificationStdStringReference() TESTCASE_THROW1(const std::string&) { throw std::string("ExceptionSpecificationStdStringReference"); } | |
| void NullStdStringValue(std::string s) {} | |
| void NullStdStringReference(std::string &s) {} | |
| %} | |
| // Memory leak check (The C++ exception stack was never unwound in the original approach to throwing exceptions from unmanaged code) | |
| %exception MemoryLeakCheck() { | |
| Counter destructor_should_be_called; | |
| try { | |
| $action | |
| } catch(Ex e) { | |
| SWIG_exception(SWIG_DivisionByZero, e.what()); | |
| } | |
| } | |
| %inline %{ | |
| struct Counter { | |
| static int count; | |
| Counter() { count++; } | |
| ~Counter() { count--; } | |
| }; | |
| int Counter::count = 0; | |
| void MemoryLeakCheck() { | |
| throw Ex("testing memory leaks when throwing exceptions"); | |
| } | |
| %} | |
| // test exception pending in the csconstruct typemap | |
| %inline %{ | |
| struct constructor { | |
| constructor(std::string s) {} | |
| constructor() TESTCASE_THROW1(int) { throw 10; } | |
| }; | |
| %} | |
| // test exception pending in the csout typemaps | |
| %typemap(out, canthrow=1) unsigned short ushorttest %{ | |
| $result = $1; | |
| if ($result == 100) { | |
| SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "don't like 100"); | |
| return $null; | |
| } | |
| %} | |
| %inline %{ | |
| unsigned short ushorttest() { return 100; } | |
| %} | |
| // test exception pending in the csvarout/csvarin typemaps and canthrow attribute in unmanaged code typemaps | |
| %typemap(check, canthrow=1) int numberin, int InOutStruct::staticnumberin %{ | |
| if ($1 < 0) { | |
| SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "too small"); | |
| return $null; | |
| } | |
| %} | |
| %typemap(out, canthrow=1) int numberout, int InOutStruct::staticnumberout %{ | |
| $result = $1; | |
| if ($result > 10) { | |
| SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "too big"); | |
| return $null; | |
| } | |
| %} | |
| %inline %{ | |
| int numberin; | |
| int numberout; | |
| struct InOutStruct { | |
| int numberin; | |
| int numberout; | |
| static int staticnumberin; | |
| static int staticnumberout; | |
| }; | |
| int InOutStruct::staticnumberin; | |
| int InOutStruct::staticnumberout; | |
| %} | |
| // test exception pending in %exceptionvar code, which has the canthrow attribute | |
| %exceptionvar exceptionvar_number { | |
| $action | |
| if (exceptionvar_number < 0) { | |
| SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "exceptionvar_number negative"); | |
| return $null; | |
| } | |
| } | |
| %exceptionvar ExceptionVarStruct::staticnumber { | |
| $action | |
| if (ExceptionVarStruct::staticnumber < 0) { | |
| SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "staticnumber negative"); | |
| return $null; | |
| } | |
| } | |
| %inline %{ | |
| int exceptionvar_number = 0; | |
| struct ExceptionVarStruct { | |
| static int staticnumber; | |
| }; | |
| int ExceptionVarStruct::staticnumber = 0; | |
| %} | |
| // test SWIG_exception macro - it must return from unmanaged code without executing any further unmanaged code | |
| %typemap(check, canthrow=1) int macrotest { | |
| if ($1 < 0) { | |
| SWIG_exception(SWIG_IndexError, "testing SWIG_exception macro"); | |
| } | |
| } | |
| %inline %{ | |
| bool exception_macro_run_flag = false; | |
| void exceptionmacrotest(int macrotest) { | |
| exception_macro_run_flag = true; | |
| } | |
| %} | |
| // test all the types of exceptions | |
| %typemap(check, canthrow=1) UnmanagedExceptions { | |
| switch($1) { | |
| case UnmanagedApplicationException: SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, "msg"); return $null; break; | |
| case UnmanagedArithmeticException: SWIG_CSharpSetPendingException(SWIG_CSharpArithmeticException, "msg"); return $null; break; | |
| case UnmanagedDivideByZeroException: SWIG_CSharpSetPendingException(SWIG_CSharpDivideByZeroException, "msg"); return $null; break; | |
| case UnmanagedIndexOutOfRangeException: SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "msg"); return $null; break; | |
| case UnmanagedInvalidCastException: SWIG_CSharpSetPendingException(SWIG_CSharpInvalidCastException, "msg"); return $null; break; | |
| case UnmanagedInvalidOperationException: SWIG_CSharpSetPendingException(SWIG_CSharpInvalidOperationException, "msg"); return $null; break; | |
| case UnmanagedIOException: SWIG_CSharpSetPendingException(SWIG_CSharpIOException, "msg"); return $null; break; | |
| case UnmanagedNullReferenceException: SWIG_CSharpSetPendingException(SWIG_CSharpNullReferenceException, "msg"); return $null; break; | |
| case UnmanagedOutOfMemoryException: SWIG_CSharpSetPendingException(SWIG_CSharpOutOfMemoryException, "msg"); return $null; break; | |
| case UnmanagedOverflowException: SWIG_CSharpSetPendingException(SWIG_CSharpOverflowException, "msg"); return $null; break; | |
| case UnmanagedSystemException: SWIG_CSharpSetPendingException(SWIG_CSharpSystemException, "msg"); return $null; break; | |
| case UnmanagedArgumentException: SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentException, "msg", "parm"); return $null; break; | |
| case UnmanagedArgumentNullException: SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "msg", "parm"); return $null; break; | |
| case UnmanagedArgumentOutOfRangeException: SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException, "msg", "parm"); return $null; break; | |
| } | |
| } | |
| %inline %{ | |
| enum UnmanagedExceptions { | |
| UnmanagedApplicationException, | |
| UnmanagedArithmeticException, | |
| UnmanagedDivideByZeroException, | |
| UnmanagedIndexOutOfRangeException, | |
| UnmanagedInvalidCastException, | |
| UnmanagedInvalidOperationException, | |
| UnmanagedIOException, | |
| UnmanagedNullReferenceException, | |
| UnmanagedOutOfMemoryException, | |
| UnmanagedOverflowException, | |
| UnmanagedSystemException, | |
| UnmanagedArgumentException, | |
| UnmanagedArgumentNullException, | |
| UnmanagedArgumentOutOfRangeException | |
| }; | |
| void check_exception(UnmanagedExceptions e) { | |
| } | |
| %} | |
| // exceptions in multiple threads test | |
| %exception ThrowsClass::ThrowException(long long input) { | |
| try { | |
| $action | |
| } catch (long long d) { | |
| char message[64]; | |
| sprintf(message, "caught:%lld", d); | |
| SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException, message, "input"); | |
| } | |
| } | |
| %inline %{ | |
| struct ThrowsClass { | |
| double dub; | |
| ThrowsClass(double d) : dub(d) {} | |
| long long ThrowException(long long input) { | |
| throw input; | |
| return input; | |
| } | |
| }; | |
| %} | |
| // test inner exceptions | |
| %exception InnerExceptionTest() { | |
| try { | |
| $action | |
| } catch(Ex &e) { | |
| SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, e.what()); | |
| SWIG_CSharpSetPendingException(SWIG_CSharpInvalidOperationException, "My OuterException message"); | |
| } | |
| } | |
| %inline %{ | |
| void InnerExceptionTest() { throw Ex("My InnerException message"); } | |
| %} | |