C# exception handling improvements - they are robust and don't leak anymore. Requires typemap modifications using attribute canthrow in any unmanaged code typemaps that throw an exception and excode attribute in csout and csconstruct typemaps.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@6934 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2005-02-02 22:44:32 +00:00
commit bac8f43f79
12 changed files with 288 additions and 156 deletions

View file

@ -2,11 +2,16 @@
%include "exception.i"
#ifdef SWIGCSHARP
#undef %exception
#define %exception %csexception
#endif
/*
last resource, catch everything but don't override
user's throw declarations.
*/
%exception {
try {
$action
@ -31,7 +36,7 @@
struct A
{
/* catched by the user's throw definition */
/* caught by the user's throw definition */
int foo() throw(E1)
{
throw E1();
@ -44,7 +49,7 @@
return 0;
}
/* catched by the %postexception */
/* caught by %postexception */
int foobar()
{
throw E3();

View file

@ -10,7 +10,13 @@
%include "exception.i"
%exception std::deque::getitem {
#ifdef SWIGCSHARP
#define %genericexception %csexception
#else
#define %genericexception %exception
#endif
%genericexception std::deque::getitem {
try {
$action
} catch (std::out_of_range& e) {
@ -18,7 +24,7 @@
}
}
%exception std::deque::setitem {
%genericexception std::deque::setitem {
try {
$action
} catch (std::out_of_range& e) {
@ -26,7 +32,7 @@
}
}
%exception std::deque::delitem {
%genericexception std::deque::delitem {
try {
$action
} catch (std::out_of_range& e) {
@ -34,6 +40,8 @@
}
}
#undef %genericexception
/* This macro defines all of the standard methods for a deque. This
is defined as a macro to simplify the task of specialization. For
example,

View file

@ -66,9 +66,18 @@ If you have used typedef to change type-names, you can also do this :
%include exception.i
#ifdef SWIGCSHARP
// Required attribute for C# exception handling
#define SWIGCSHARPCANTHROW , canthrow=1
#else
#define SWIGCSHARPCANTHROW
#endif
// Positive numbers
%typemap(check) int POSITIVE,
%typemap(check SWIGCSHARPCANTHROW)
int POSITIVE,
short POSITIVE,
long POSITIVE,
unsigned int POSITIVE,
@ -87,7 +96,8 @@ If you have used typedef to change type-names, you can also do this :
// Negative numbers
%typemap(check) int NEGATIVE,
%typemap(check SWIGCSHARPCANTHROW)
int NEGATIVE,
short NEGATIVE,
long NEGATIVE,
unsigned int NEGATIVE,
@ -106,7 +116,8 @@ If you have used typedef to change type-names, you can also do this :
// Nonzero numbers
%typemap(check) int NONZERO,
%typemap(check SWIGCSHARPCANTHROW)
int NONZERO,
short NONZERO,
long NONZERO,
unsigned int NONZERO,
@ -125,7 +136,8 @@ If you have used typedef to change type-names, you can also do this :
// Nonnegative numbers
%typemap(check) int NONNEGATIVE,
%typemap(check SWIGCSHARPCANTHROW)
int NONNEGATIVE,
short NONNEGATIVE,
long NONNEGATIVE,
unsigned int NONNEGATIVE,
@ -144,7 +156,8 @@ If you have used typedef to change type-names, you can also do this :
// Nonpositive numbers
%typemap(check) int NONPOSITIVE,
%typemap(check SWIGCSHARPCANTHROW)
int NONPOSITIVE,
short NONPOSITIVE,
long NONPOSITIVE,
unsigned int NONPOSITIVE,
@ -163,7 +176,8 @@ If you have used typedef to change type-names, you can also do this :
// Non-NULL pointer
%typemap(check) void * NONNULL,
%typemap(check SWIGCSHARPCANTHROW)
void * NONNULL,
Pointer NONNULL
{
if (!$1) {
@ -173,7 +187,8 @@ If you have used typedef to change type-names, you can also do this :
// Aligned pointers
%typemap(check) void * ALIGN8,
%typemap(check SWIGCSHARPCANTHROW)
void * ALIGN8,
Pointer ALIGN8
{
long tmp;
@ -183,7 +198,8 @@ If you have used typedef to change type-names, you can also do this :
}
}
%typemap(check) void * ALIGN4,
%typemap(check SWIGCSHARPCANTHROW)
void * ALIGN4,
Pointer ALIGN4
{
long tmp;
@ -193,7 +209,8 @@ If you have used typedef to change type-names, you can also do this :
}
}
%typemap(check) void * ALIGN2,
%typemap(check SWIGCSHARPCANTHROW)
void * ALIGN2,
Pointer ALIGN2
{
long tmp;

View file

@ -165,7 +165,7 @@ $1 = &temp; %}
%typemap(out) const double & %{ $result = *$1; %}
/* Default handling. Object passed by value. Convert to a pointer */
%typemap(in) SWIGTYPE ($&1_type argp)
%typemap(in, canthrow=1) SWIGTYPE ($&1_type argp)
%{ argp = ($&1_ltype)$input;
if (!argp) {
SWIG_CSharpThrowException(SWIG_CSharpNullReferenceException, "Attempt to dereference null $1_type");
@ -185,7 +185,7 @@ $1 = &temp; %}
/* Generic pointers and references */
%typemap(in) SWIGTYPE * %{ $1 = ($1_ltype)$input; %}
%typemap(in) SWIGTYPE (CLASS::*) %{ $1 = *($&1_ltype)&$input; %}
%typemap(in) SWIGTYPE & %{ $1 = ($1_ltype)$input;
%typemap(in, canthrow=1) SWIGTYPE & %{ $1 = ($1_ltype)$input;
if(!$1) {
SWIG_CSharpThrowException(SWIG_CSharpNullReferenceException, "$1_type reference is null");
} %}
@ -285,7 +285,7 @@ $1 = &temp; %}
/* Exception handling */
%typemap(throws) int,
%typemap(throws, canthrow=1) int,
long,
short,
unsigned int,
@ -296,12 +296,12 @@ $1 = &temp; %}
SWIG_CSharpThrowException(SWIG_CSharpException, error_msg);
}
%typemap(throws) SWIGTYPE, SWIGTYPE &, SWIGTYPE *, SWIGTYPE [ANY] %{
%typemap(throws, canthrow=1) SWIGTYPE, SWIGTYPE &, SWIGTYPE *, SWIGTYPE [ANY] %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(throws) char * %{
%typemap(throws, canthrow=1) char * %{
SWIG_CSharpThrowException(SWIG_CSharpException, $1);
%}
@ -330,39 +330,95 @@ $1 = &temp; %}
%typemap(csin) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], SWIGTYPE (CLASS::*) "$csclassname.getCPtr($csinput)"
/* The csout typemap is used for converting function return types from the return type
* used in the PInvoke class to the type returned by the proxy, module or type wrapper class. */
%typemap(csout) bool, const bool &,
char, const char &,
signed char, const signed char &,
unsigned char, const unsigned char &,
short, const short &,
unsigned short, const unsigned short &,
int, const int &,
unsigned int, const unsigned int &,
long, const long &,
unsigned long, const unsigned long &,
long long, const long long &,
unsigned long long, const unsigned long long &,
float, const float &,
double, const double & {
return $imcall;
* used in the PInvoke class to the type returned by the proxy, module or type wrapper class.
* The $excode special variable is replaced by the excode typemap attribute code if the
* method can throw any exceptions, otherwise replaced by nothing. */
// Macro used by the $excode special variable
%define SWIGEXCODE "\n if ($modulePINVOKE.ExceptionPending) throw $modulePINVOKE.RetrievePendingException();" %enddef
%typemap(csout, excode=SWIGEXCODE) bool, const bool & {
bool ret = $imcall;$excode
return ret;
}
%typemap(csout) char *, char[ANY], char[] {
return $imcall;
%typemap(csout, excode=SWIGEXCODE) char, const char & {
char ret = $imcall;$excode
return ret;
}
%typemap(csout) void {
$imcall;
%typemap(csout, excode=SWIGEXCODE) signed char, const signed char & {
sbyte ret = $imcall;$excode
return ret;
}
%typemap(csout) SWIGTYPE {
return new $&csclassname($imcall, true);
%typemap(csout, excode=SWIGEXCODE) unsigned char, const unsigned char & {
byte ret = $imcall;$excode
return ret;
}
%typemap(csout) SWIGTYPE & {
return new $csclassname($imcall, $owner);
%typemap(csout, excode=SWIGEXCODE) short, const short & {
short ret = $imcall;$excode
return ret;
}
%typemap(csout) SWIGTYPE *, SWIGTYPE [], SWIGTYPE (CLASS::*) {
%typemap(csout, excode=SWIGEXCODE) unsigned short, const unsigned short & {
ushort ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) int, const int & {
int ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) unsigned int, const unsigned int & {
uint ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) long, const long & {
int ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) unsigned long, const unsigned long & {
uint ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) long long, const long long & {
long ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) unsigned long long, const unsigned long long & {
ulong ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) float, const float & {
float ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) double, const double & {
double ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) char *, char[ANY], char[] {
string ret = $imcall;$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) void {
$imcall;$excode
}
%typemap(csout, excode=SWIGEXCODE) SWIGTYPE {
$&csclassname ret = new $&csclassname($imcall, true);$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) SWIGTYPE & {
$csclassname ret = new $csclassname($imcall, $owner);$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) SWIGTYPE *, SWIGTYPE [], SWIGTYPE (CLASS::*) {
IntPtr cPtr = $imcall;
return (cPtr == IntPtr.Zero) ? null : new $csclassname(cPtr, $owner);
$csclassname ret = (cPtr == IntPtr.Zero) ? null : new $csclassname(cPtr, $owner);$excode
return ret;
}
%typemap(csout, excode=SWIGEXCODE) SWIGTYPE *, SWIGTYPE [], SWIGTYPE (CLASS::*) {
IntPtr cPtr = $imcall;
$csclassname ret = (cPtr == IntPtr.Zero) ? null : new $csclassname(cPtr, $owner);$excode
return ret;
}
/* Properties */
%typemap(csvarin) SWIGTYPE, SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], SWIGTYPE (CLASS::*) %{
@ -484,8 +540,8 @@ $1 = &temp; %}
}
%}
%typemap(csconstruct) SWIGTYPE %{: this(IntPtr.Zero, false) {
swigSetup($imcall, true);
%typemap(csconstruct, excode=SWIGEXCODE) SWIGTYPE %{: this(IntPtr.Zero, false) {
swigSetup($imcall, true);$excode
}
%}
@ -514,6 +570,8 @@ $1 = &temp; %}
#define %csconstvalue(value) %feature("cs:constvalue",value)
#define %csenum(wrapapproach) %feature("cs:enum","wrapapproach")
#define %csmethodmodifiers %feature("cs:methodmodifiers")
#define %csexception %feature("except",canthrow=1)
#define %nocsexception %feature("except","")
%pragma(csharp) imclassclassmodifiers="class"
%pragma(csharp) moduleclassmodifiers="public class"
@ -555,8 +613,9 @@ using System.Runtime.InteropServices;
%typemap(imtype) char *, char[ANY], char[] "IntPtr"
%typemap(out) char[ANY], char[] %{ $result = $1; %}
%typemap(csin) char *, char[ANY], char[] "new $modulePINVOKE.SWIGStringMarshal($csinput).ptr"
%typemap(csout) char *, char[ANY], char[] {
return System.Runtime.InteropServices.Marshal.PtrToStringAnsi($imcall);
%typemap(csout, excode=SWIGEXCODE) char *, char[ANY], char[] {
string ret = System.Runtime.InteropServices.Marshal.PtrToStringAnsi($imcall);$excode
return ret;
}
%typemap(csvarin) char *, char[ANY], char[] %{
set {

View file

@ -122,6 +122,41 @@ DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_$module(SWIG_CSharpExc
}
static SWIGExceptionHelper exceptionHelper = new SWIGExceptionHelper();
[ThreadStatic]
private static Exception pendingException = null;
private static int numExceptionsPending = 0;
public static bool ExceptionPending {
get {
bool pending = false;
if (numExceptionsPending > 0)
if (pendingException != null)
pending = true;
return pending;
}
}
public static void SetPendingException(Exception e) {
pendingException = e;
lock(typeof($modulePINVOKE)) {
numExceptionsPending++;
}
}
public static Exception RetrievePendingException() {
Exception e = null;
if (numExceptionsPending > 0) {
if (pendingException != null) {
e = pendingException;
pendingException = null;
lock(typeof($modulePINVOKE)) {
numExceptionsPending--;
}
}
}
return e;
}
%}
%insert(runtime) %{

View file

@ -15,14 +15,15 @@
%typecheck(SWIG_TYPECHECK_POINTER) const enum SWIGTYPE & ""
%typemap(throws) const enum SWIGTYPE & %{
%typemap(throws, canthrow=1) const enum SWIGTYPE & %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(csin) const enum SWIGTYPE & "(int)$csinput"
%typemap(csout) const enum SWIGTYPE & {
return ($*csclassname)$imcall;
%typemap(csout, excode=SWIGEXCODE) const enum SWIGTYPE & {
$*csclassname ret = ($*csclassname)$imcall;$excode
return ret;
}
%typemap(csvarout) const enum SWIGTYPE & %{
@ -41,14 +42,15 @@
%typecheck(SWIG_TYPECHECK_POINTER) enum SWIGTYPE ""
%typemap(throws) enum SWIGTYPE %{
%typemap(throws, canthrow=1) enum SWIGTYPE %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(csin) enum SWIGTYPE "(int)$csinput"
%typemap(csout) enum SWIGTYPE {
return ($csclassname)$imcall;
%typemap(csout, excode=SWIGEXCODE) enum SWIGTYPE {
$csclassname ret = ($csclassname)$imcall;$excode
return ret;
}
%typemap(csvarout) enum SWIGTYPE %{

View file

@ -17,14 +17,15 @@
%typecheck(SWIG_TYPECHECK_INT32) const enum SWIGTYPE & ""
%typemap(throws) const enum SWIGTYPE & %{
%typemap(throws, canthrow=1) const enum SWIGTYPE & %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(csin) const enum SWIGTYPE & "$csinput"
%typemap(csout) const enum SWIGTYPE & {
return $imcall;
%typemap(csout, excode=SWIGEXCODE) const enum SWIGTYPE & {
int ret = $imcall;$excode
return ret;
}
%typemap(csvarout) const enum SWIGTYPE & %{
@ -43,14 +44,15 @@
%typecheck(SWIG_TYPECHECK_INT32) enum SWIGTYPE ""
%typemap(throws) enum SWIGTYPE %{
%typemap(throws, canthrow=1) enum SWIGTYPE %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(csin) enum SWIGTYPE "$csinput"
%typemap(csout) enum SWIGTYPE {
return $imcall;
%typemap(csout, excode=SWIGEXCODE) enum SWIGTYPE {
int ret = $imcall;$excode
return ret;
}
%typemap(csvarout) enum SWIGTYPE %{

View file

@ -16,14 +16,15 @@
%typecheck(SWIG_TYPECHECK_POINTER) const enum SWIGTYPE & ""
%typemap(throws) const enum SWIGTYPE & %{
%typemap(throws, canthrow=1) const enum SWIGTYPE & %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(csin) const enum SWIGTYPE & "$csinput.swigValue"
%typemap(csout) const enum SWIGTYPE & {
return $*csclassname.swigToEnum($imcall);
%typemap(csout, excode=SWIGEXCODE) const enum SWIGTYPE & {
$*csclassname ret = $*csclassname.swigToEnum($imcall);$excode
return ret;
}
%typemap(csvarout) const enum SWIGTYPE & %{
@ -42,14 +43,15 @@
%typecheck(SWIG_TYPECHECK_POINTER) enum SWIGTYPE ""
%typemap(throws) enum SWIGTYPE %{
%typemap(throws, canthrow=1) enum SWIGTYPE %{
(void)$1;
SWIG_CSharpThrowException(SWIG_CSharpException, "C++ $1_type exception thrown");
%}
%typemap(csin) enum SWIGTYPE "$csinput.swigValue"
%typemap(csout) enum SWIGTYPE {
return $csclassname.swigToEnum($imcall);
%typemap(csout, excode=SWIGEXCODE) enum SWIGTYPE {
$csclassname ret = $csclassname.swigToEnum($imcall);$excode
return ret;
}
%typemap(csvarout) enum SWIGTYPE %{

View file

@ -26,14 +26,15 @@ class string;
%typemap(imtype) string "string"
%typemap(cstype) string "string"
%typemap(in) string
%typemap(in, canthrow=1) string
%{ if (!$input) SWIG_CSharpThrowException(SWIG_CSharpNullReferenceException, "null string");
$1 = std::string($input); %}
%typemap(out) string %{ $result = SWIG_csharp_string_callback($1.c_str()); %}
%typemap(csin) string "$csinput"
%typemap(csout) string {
return $imcall;
%typemap(csout, excode=SWIGEXCODE) string {
string ret = $imcall;$excode
return ret;
}
%typemap(csvarin) string %{
@ -47,7 +48,7 @@ class string;
%typemap(typecheck) string = char *;
%typemap(throws) string %{
%typemap(throws, canthrow=1) string %{
SWIG_CSharpThrowException(SWIG_CSharpException, $1.c_str());
%}
@ -56,15 +57,16 @@ class string;
%typemap(imtype) const string & "string"
%typemap(cstype) const string & "string"
%typemap(in) const string &
%typemap(in, canthrow=1) const string &
%{ if (!$input) SWIG_CSharpThrowException(SWIG_CSharpNullReferenceException, "null string");
std::string $1_str($input);
$1 = &$1_str; %}
%typemap(out) const string & %{ $result = SWIG_csharp_string_callback($1->c_str()); %}
%typemap(csin) const string & "$csinput"
%typemap(csout) const string & {
return $imcall;
%typemap(csout, excode=SWIGEXCODE) const string & {
string ret = $imcall;$excode
return ret;
}
%typemap(csvarin) const string & %{
@ -78,7 +80,7 @@ class string;
%typemap(typecheck) const string & = char *;
%typemap(throws) const string & %{
%typemap(throws, canthrow=1) const string & %{
SWIG_CSharpThrowException(SWIG_CSharpException, $1.c_str());
%}

View file

@ -327,7 +327,7 @@ namespace std {
// Methods which can throw an Exception
%exception std::vector::vector(int capacity) {
%csexception std::vector::vector(int capacity) {
try {
$action
} catch (std::out_of_range& e) {
@ -335,7 +335,7 @@ namespace std {
}
}
%exception std::vector::getitemcopy {
%csexception std::vector::getitemcopy {
try {
$action
} catch (std::out_of_range& e) {
@ -343,7 +343,7 @@ namespace std {
}
}
%exception std::vector::getitem {
%csexception std::vector::getitem {
try {
$action
} catch (std::out_of_range& e) {
@ -351,7 +351,7 @@ namespace std {
}
}
%exception std::vector::setitem {
%csexception std::vector::setitem {
try {
$action
} catch (std::out_of_range& e) {
@ -359,7 +359,7 @@ namespace std {
}
}
%exception std::vector::GetRange {
%csexception std::vector::GetRange {
try {
$action
} catch (std::out_of_range& e) {
@ -369,7 +369,7 @@ namespace std {
}
}
%exception std::vector::Insert {
%csexception std::vector::Insert {
try {
$action
} catch (std::out_of_range& e) {
@ -377,7 +377,7 @@ namespace std {
}
}
%exception std::vector::InsertRange {
%csexception std::vector::InsertRange {
try {
$action
} catch (std::out_of_range& e) {
@ -385,7 +385,7 @@ namespace std {
}
}
%exception std::vector::RemoveAt {
%csexception std::vector::RemoveAt {
try {
$action
} catch (std::out_of_range& e) {
@ -393,7 +393,7 @@ namespace std {
}
}
%exception std::vector::Repeat {
%csexception std::vector::Repeat {
try {
$action
} catch (std::out_of_range& e) {
@ -401,7 +401,7 @@ namespace std {
}
}
%exception std::vector::RemoveRange {
%csexception std::vector::RemoveRange {
try {
$action
} catch (std::out_of_range& e) {
@ -411,7 +411,7 @@ namespace std {
}
}
%exception std::vector::Reverse(int index, int count) {
%csexception std::vector::Reverse(int index, int count) {
try {
$action
} catch (std::out_of_range& e) {
@ -421,7 +421,7 @@ namespace std {
}
}
%exception std::vector::SetRange {
%csexception std::vector::SetRange {
try {
$action
} catch (std::out_of_range& e) {

View file

@ -205,6 +205,8 @@
#define WARN_CSHARP_TYPEMAP_CSDIRECTOROUT_UNDEF 840
#define WARN_CSHARP_COVARIANT_RET 842
#define WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF 843
#define WARN_CSHARP_EXCODE 844
#define WARN_CSHARP_CANTHROW 845
/* please leave 830-849 free for C# */

View file

@ -593,7 +593,7 @@ class CSHARP : public Language {
// Get typemap for this argument
if ((tm = Getattr(p,"tmap:in"))) {
addThrows(n, "tmap:in", p);
canThrow(n, "in", p);
Replaceall(tm,"$source",arg); /* deprecated */
Replaceall(tm,"$target",ln); /* deprecated */
Replaceall(tm,"$arg",arg); /* deprecated? */
@ -614,7 +614,7 @@ class CSHARP : public Language {
/* Insert constraint checking code */
for (p = l; p;) {
if ((tm = Getattr(p,"tmap:check"))) {
addThrows(n, "tmap:check", p);
canThrow(n, "check", p);
Replaceall(tm,"$target",Getattr(p,"lname")); /* deprecated */
Replaceall(tm,"$arg",Getattr(p,"emit:input")); /* deprecated? */
Replaceall(tm,"$input",Getattr(p,"emit:input"));
@ -628,7 +628,7 @@ class CSHARP : public Language {
/* Insert cleanup code */
for (p = l; p;) {
if ((tm = Getattr(p,"tmap:freearg"))) {
addThrows(n, "tmap:freearg", p);
canThrow(n, "freearg", p);
Replaceall(tm,"$source",Getattr(p,"emit:input")); /* deprecated */
Replaceall(tm,"$arg",Getattr(p,"emit:input")); /* deprecated? */
Replaceall(tm,"$input",Getattr(p,"emit:input"));
@ -642,7 +642,7 @@ class CSHARP : public Language {
/* Insert argument output code */
for (p = l; p;) {
if ((tm = Getattr(p,"tmap:argout"))) {
addThrows(n, "tmap:argout", p);
canThrow(n, "argout", p);
Replaceall(tm,"$source",Getattr(p,"emit:input")); /* deprecated */
Replaceall(tm,"$target",Getattr(p,"lname")); /* deprecated */
Replaceall(tm,"$arg",Getattr(p,"emit:input")); /* deprecated? */
@ -661,7 +661,7 @@ class CSHARP : public Language {
Swig_typemap_attach_parms("throws", throw_parm_list, f);
for (p = throw_parm_list; p; p=nextSibling(p)) {
if ((tm = Getattr(p,"tmap:throws"))) {
addThrows(n, "tmap:throws", p);
canThrow(n, "throws", p);
}
}
}
@ -685,7 +685,7 @@ class CSHARP : public Language {
/* Return value if necessary */
if(!native_function_flag) {
if ((tm = Swig_typemap_lookup_new("out",n,"result",0))) {
addThrows(n, "tmap:out", n);
canThrow(n, "out", n);
Replaceall(tm,"$source", "result"); /* deprecated */
Replaceall(tm,"$target", "jresult"); /* deprecated */
Replaceall(tm,"$result","jresult");
@ -707,7 +707,7 @@ class CSHARP : public Language {
/* Look to see if there is any newfree cleanup code */
if (Getattr(n,"feature:new")) {
if ((tm = Swig_typemap_lookup_new("newfree",n,"result",0))) {
addThrows(n, "tmap:newfree", n);
canThrow(n, "newfree", n);
Replaceall(tm,"$source","result"); /* deprecated */
Printf(f->code,"%s\n",tm);
}
@ -723,7 +723,6 @@ class CSHARP : public Language {
/* Finish C function and intermediary class function definitions */
Printf(imclass_class_code, ")");
generateThrowsClause(n, imclass_class_code);
Printf(imclass_class_code, ";\n");
Printf(f->def,") {");
@ -744,9 +743,28 @@ class CSHARP : public Language {
Replaceall(f->code,"$null","");
/* Dump the function out */
if(!native_function_flag)
if(!native_function_flag) {
Wrapper_print(f,f_wrappers);
// Handle %csexception which sets the canthrow attribute
if (Getattr(n,"feature:except:canthrow"))
Setattr(n,"csharp:canthrow","1");
// A very simple check (it is not foolproof) to help typemap/feature writers for
// throwing C# exceptions from unmanaged code. It checks for the common methods which
// set a pending C# exception... the 'canthrow' typemap/feature attribute must be set
// so that code which checks for pending exceptions is added in the C# proxy method.
if (!Getattr(n,"csharp:canthrow")) {
if(Strstr(f->code, "SWIG_exception")) {
Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number,
"Unmanaged code contains a call to SWIG_exception and C# code does not handle pending exceptions via the canthrow attribute.\n");
} else if(Strstr(f->code, "SWIG_CSharpThrowException")) {
Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number,
"Unmanaged code contains a call to SWIG_CSharpThrowException and C# code does not handle pending exceptions via the canthrow attribute.\n");
}
}
}
if(!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) {
moduleClassFunctionHandler(n);
}
@ -1571,7 +1589,7 @@ class CSHARP : public Language {
// Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class)
if ((tm = Getattr(p,"tmap:csin"))) {
addThrows(n, "tmap:csin", p);
canThrow(n, "csin", p);
substituteClassname(pt, tm);
Replaceall(tm, "$csinput", arg);
Printv(imcall, tm, NIL);
@ -1597,19 +1615,19 @@ class CSHARP : public Language {
// Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class)
if ((tm = Swig_typemap_lookup_new("csout",n,"",0))) {
addThrows(n, "tmap:csout", n);
canThrow(n, "csout", n);
if (Getattr(n,"feature:new"))
Replaceall(tm,"$owner","true");
else
Replaceall(tm,"$owner","false");
substituteClassname(t, tm);
Replaceall(tm, "$imcall", imcall);
excodeSubstitute(n, tm, "csout", n);
} else {
Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number,
"No csout typemap defined for %s\n", SwigType_str(t,0));
}
generateThrowsClause(n, function_code);
Printf(function_code, " %s\n\n", tm ? (const String *)tm : empty_string);
if(proxy_flag && wrapping_member_flag && !enum_constant_flag) {
@ -1724,7 +1742,7 @@ class CSHARP : public Language {
// Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class)
if ((tm = Getattr(p,"tmap:csin"))) {
addThrows(n, "tmap:csin", p);
canThrow(n, "csin", p);
substituteClassname(pt, tm);
Replaceall(tm, "$csinput", arg);
Printv(imcall, tm, NIL);
@ -1747,11 +1765,14 @@ class CSHARP : public Language {
Printf(imcall, ")");
Printf(function_code, ")");
generateThrowsClause(n, function_code);
Printv(function_code, " ", typemapLookup("csconstruct", Getattr(n,"name"), WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF), NIL);
Node *attributes = NewHash();
Printv(function_code, " ", typemapLookup("csconstruct", Getattr(n,"name"), WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF, attributes), NIL);
Replaceall(function_code, "$imcall", imcall);
excodeSubstitute(n, function_code, "csconstruct", attributes);
Printv(proxy_class_code, function_code, "\n", NIL);
Delete(attributes);
Delete(overloaded_name);
Delete(imcall);
}
@ -1963,7 +1984,7 @@ class CSHARP : public Language {
// Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class)
if ((tm = Getattr(p,"tmap:csin"))) {
addThrows(n, "tmap:csin", p);
canThrow(n, "csin", p);
substituteClassname(pt, tm);
Replaceall(tm, "$csinput", arg);
Printv(imcall, tm, NIL);
@ -1988,19 +2009,19 @@ class CSHARP : public Language {
// Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in module class)
if ((tm = Swig_typemap_lookup_new("csout",n,"",0))) {
addThrows(n, "tmap:csout", n);
canThrow(n, "csout", n);
if (Getattr(n,"feature:new"))
Replaceall(tm,"$owner","true");
else
Replaceall(tm,"$owner","false");
substituteClassname(t, tm);
Replaceall(tm, "$imcall", imcall);
excodeSubstitute(n, tm, "csout", n);
} else {
Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number,
"No csout typemap defined for %s\n", SwigType_str(t,0));
}
generateThrowsClause(n, function_code);
Printf(function_code, " %s\n\n", tm ? (const String *)tm : empty_string);
if (proxy_flag && global_variable_flag) {
@ -2318,65 +2339,42 @@ class CSHARP : public Language {
}
/* -----------------------------------------------------------------------------
* addThrows()
* canThrow()
* Determine whether the code in the typemap can throw a C# exception.
* If so, note it for later when excodeSubstitute() is called.
* ----------------------------------------------------------------------------- */
void addThrows(Node *n, const String *typemap, Node *parameter) {
// Get the comma separated throws clause - held in "throws" attribute in the typemap passed in
String *throws_attribute = NewStringf("%s:throws", typemap);
String *throws = Getattr(parameter,throws_attribute);
if (throws) {
String *throws_list = Getattr(n,"csharp:throwslist");
if (!throws_list) {
throws_list = NewList();
Setattr(n,"csharp:throwslist", throws_list);
}
// Put the exception classes in the throws clause into a temporary List
List *temp_classes_list = Split(throws,',',INT_MAX);
// Add the exception classes to the node throws list, but don't duplicate if already in list
if (temp_classes_list && Len(temp_classes_list) > 0) {
for (Iterator cls = First(temp_classes_list); cls.item; cls = Next(cls)) {
String *exception_class = NewString(cls.item);
Replaceall(exception_class," ",""); // remove spaces
Replaceall(exception_class,"\t",""); // remove tabs
if (Len(exception_class) > 0) {
// $csclassname substitution
SwigType *pt = Getattr(parameter,"type");
substituteClassname(pt, exception_class);
// Don't duplicate the C# exception class in the throws clause
bool found_flag = false;
for (Iterator item = First(throws_list); item.item; item = Next(item)) {
if (Strcmp(item.item, exception_class) == 0)
found_flag = true;
}
if (!found_flag)
Append(throws_list, exception_class);
}
Delete(exception_class);
}
}
Delete(temp_classes_list);
}
Delete(throws_attribute);
void canThrow(Node *n, const String *typemap, Node *parameter) {
String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap);
String *canthrow = Getattr(parameter,canthrow_attribute);
if (canthrow) {
if (!Getattr(n,"csharp:canthrow"))
Setattr(n,"csharp:canthrow", "1");
}
Delete(canthrow_attribute);
}
/* -----------------------------------------------------------------------------
* generateThrowsClause()
* excodeSubstitute()
* If a method can throw a C# exception, additional exception code is added to
* check for the pending exception so that it can then throw the exception. The
* $excode special variable is replaced by the exception code in the excode
* typemap attribute.
* ----------------------------------------------------------------------------- */
void generateThrowsClause(Node *n, String *code) {
// Add the throws clause into code
List *throws_list = Getattr(n,"csharp:throwslist");
if (throws_list) {
Iterator cls = First(throws_list);
Printf(code, " throws %s", cls.item);
while ( (cls = Next(cls)).item)
Printf(code, ", %s", cls.item);
void excodeSubstitute(Node *n, String *code, const String *typemap, Node *parameter) {
String *excode_attribute = NewStringf("tmap:%s:excode", typemap);
String *excode = Getattr(parameter, excode_attribute);
if (Getattr(n,"csharp:canthrow")) {
int count = Replaceall(code, "$excode", excode);
if (count < 1 || !excode) {
Swig_warning(WARN_CSHARP_EXCODE, input_file, line_number,
"C# exception may not be thrown - no $excode or excode attribute in '%s' typemap.\n", typemap);
}
} else {
Replaceall(code, "$excode", empty_string);
}
Delete(excode_attribute);
}
}; /* class CSHARP */