From f0d1d772fa547e2f22ebe11b6e2949babc3a9d94 Mon Sep 17 00:00:00 2001
From: William S Fulton
Date: Wed, 13 Sep 2006 20:55:24 +0000
Subject: [PATCH] - explicitcall feature removed. - Instead of using the
swig_up flag in each director method (Python, Ruby, Ocaml) to indicate
whether the explicit C++ call to the appropriate base class method or a
normal polymorphic C++ call should be made, the new approach makes one of
these calls directly from the wrapper method. - Java/C# recursive director
method calls fixed (no need for explicitcall feature to solve this now)
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@9275 626c5289-ae23-0410-ae9c-e8d60b6d4f22
---
Doc/Manual/Java.html | 57 -------------------
Doc/Manual/SWIGPlus.html | 80 ---------------------------
Source/Modules/csharp.cxx | 50 +++++++++++++++++
Source/Modules/emit.cxx | 17 +-----
Source/Modules/java.cxx | 52 ++++++++++++++++++
Source/Modules/lang.cxx | 112 +++++++++++++++++++++++++++++---------
Source/Modules/ocaml.cxx | 50 ++++++++---------
Source/Modules/python.cxx | 71 +++++++++++-------------
Source/Modules/ruby.cxx | 50 ++++++++---------
Source/Modules/swigmod.h | 3 +
Source/Swig/cwrap.c | 112 +++++++++++++++++++++++++++-----------
Source/Swig/swig.h | 4 +-
12 files changed, 355 insertions(+), 303 deletions(-)
diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html
index 48f7c6d02..03b68d22c 100644
--- a/Doc/Manual/Java.html
+++ b/Doc/Manual/Java.html
@@ -83,7 +83,6 @@
Director classes
Overhead and code bloat
Simple directors example
-Director base method calls
Common customization features
@@ -3204,62 +3203,6 @@ directorDerived::upcall_method() invoked.
-20.5.5 Director base method calls
-
-
-
-There is a limitation with Java directors when calling a base class method from an overridden method.
-A java.lang.StackOverflowError exception will be thrown as the code makes recursive calls from the C++ layer
-to the Java layer and back again in the same method. The explicitcall feature flag
-is one way to work around this problem. Consider the following C++ code:
-
-
-
-
-%feature("director");
-%feature("explicitcall");
-%include <std_string.i>
-
-%inline %{
-struct Thing {
- virtual std::string getit() { return "Thing"; }
- virtual ~Thing() {}
-};
-%}
-
-
-
-
-and the following Java class:
-
-
-
-
-class JavaThing extends Thing {
- public String getit() {
- return "Java" + super.getit();
- }
-}
-
-
-
-
-The overridden JavaThing.getit() method will throw the java.lang.StackOverflowError exception when called.
-Fixing this would impose a performance penalty on all director methods and would not be able to automatically deal with pure
-virtual methods for which a method body is not always defined. Instead, users are advised to use the explicitcall
-feature flag which generates an additional method getitThing(). The modified version will then avoid the recursive calls:
-
-
-
-
-class JavaThing extends Thing {
- public String getit() {
- return "Java" + super.getitThing();
- }
-}
-
-
-
20.6 Common customization features
diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html
index c8c384a27..df9a9a248 100644
--- a/Doc/Manual/SWIGPlus.html
+++ b/Doc/Manual/SWIGPlus.html
@@ -1668,86 +1668,6 @@ functions for virtual members that are already defined in a base
class.
-6.13.1 Explicit base class method calls
-
-
-
-SWIG uses standard C++ polymorphic behaviour to ensure the correct virtual method is called
-when generating wrappers for virtual methods.
-However, in C++ it is possible, albeit rare, to call a particular base class method in the inheritance
-hierarchy. This C++ functionality is available to target languages with the
-explicitcall feature flag directive.
-This feature only works on virtual methods and when it is specified it generates an
-additional wrapper method. By default, the name of this method is the original method name mangled with
-the name of the class as a suffix. However, the name of the method can be controlled by specifying a different
-suffix in the suffix
-feature attribute.
-For example, consider the following code:
-
-
-
-
-%explicitcall; // enable explicitcall feature for all virtual methods
-%feature("explicitcall", suffix="Bambino") Child::describe;
-
-struct Person {
- Person() {}
- virtual const char * describe() { return "Person"; }
- virtual ~Person() {}
-};
-
-struct Child : Person {
- virtual const char * describe() { return "Child"; }
-};
-
-
-
-
-From Python, it is then possible to call explicit methods in the inheritance hierarchy.
-Note the suffix names:
-
-
-
-
-$ python
->>> from example import *
->>> child = Child()
->>> print child.describe() # normal polymorphic call
-Child
->>> print child.describePerson() # explicit Person::describe call
-Person
->>> print child.describeBambino() # explicit Child::describe call
-Child
-
-
-
-
-The pseudo C++ code generated for the Person::describe methods is as follows:
-
-
-
-
-// Normal virtual method wrapper
-const char * Person_talk(Person *obj) {
- const char * ret = obj->describe();
- return ret;
-}
-
-// Additional wrapper due to %explicitcall
-const char * Person_talkPerson(Person *obj) {
- const char * ret = obj->Person::describe();
- return ret;
-}
-
-
-
-
-Please note that if this feature is enabled globally, it will apply to all virtual methods.
-This includes pure virtual methods which may or may not have a body defined.
-If, as is often the case, your pure virtual methods do not have a body defined you might get unresolved linker errors on some platforms.
-%noexplicitcall can then be used to turn this feature off for the problem methods.
-
-
6.14 A brief discussion of multiple inheritance, pointers, and type checking
diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx
index cf4559578..78cde2898 100644
--- a/Source/Modules/csharp.cxx
+++ b/Source/Modules/csharp.cxx
@@ -1859,6 +1859,9 @@ class CSHARP : public Language {
// Wrappers not wanted for some methods where the parameters cannot be overloaded in C#
if (Getattr(n, "overload:ignore")) return;
+ // Don't generate proxy method for additional explicitcall method used in directors
+ if (GetFlag(n, "explicitcall")) return;
+
if (l) {
if (SwigType_type(Getattr(l,"type")) == T_VOID) {
l = nextSibling(l);
@@ -1993,6 +1996,28 @@ class CSHARP : public Language {
else
Replaceall(tm,"$owner","false");
substituteClassname(t, tm);
+
+ // For director methods: generate code to selectively make a normal polymorphic call or
+ // an explicit method call - needed to prevent infinite recursion calls in director methods.
+ Node *explicit_n = Getattr(n,"explicitcallnode");
+ if (explicit_n) {
+ String *ex_overloaded_name = getOverloadedName(explicit_n);
+ String *ex_intermediary_function_name = Swig_name_member(proxy_class_name, ex_overloaded_name);
+
+ String *ex_imcall = Copy(imcall);
+ Replaceall(ex_imcall, intermediary_function_name, ex_intermediary_function_name);
+
+ String *excode = NewString("");
+ if (!Cmp(return_type, "void"))
+ Printf(excode, "if (this.GetType() == typeof(%s)) %s; else %s", proxy_class_name, imcall, ex_imcall);
+ else
+ Printf(excode, "((this.GetType() == typeof(%s)) ? %s : %s)", proxy_class_name, imcall, ex_imcall);
+
+ Clear(imcall);
+ Printv(imcall, excode, NIL);
+ Delete(ex_overloaded_name);
+ Delete(excode);
+ }
Replaceall(tm, "$imcall", imcall);
excodeSubstitute(n, tm, "csout", n);
} else {
@@ -3364,6 +3389,22 @@ class CSHARP : public Language {
Printf(w->code, "}");
+ // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
+ String *inline_extra_method = NewString("");
+ if (dirprot_mode() && !is_public(n) && !pure_virtual)
+ {
+ Printv(inline_extra_method, declaration, NIL);
+ String *extra_method_name = NewStringf("%sSwigPublic", name);
+ Replaceall(inline_extra_method, name, extra_method_name);
+ Replaceall(inline_extra_method, ";\n", " {\n ");
+ if (!is_void)
+ Printf(inline_extra_method, "return ");
+ String *methodcall = Swig_method_call(super, l);
+ Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
+ Delete(methodcall);
+ Delete(extra_method_name);
+ }
+
/* emit code */
if (status == SWIG_OK && output_director) {
if(!is_void) {
@@ -3375,6 +3416,7 @@ class CSHARP : public Language {
if (!Getattr(n,"defaultargs")) {
Wrapper_print(w, f_directors);
Printv(f_directors_h, declaration, NIL);
+ Printv(f_directors_h, inline_extra_method, NIL);
}
}
@@ -3621,6 +3663,14 @@ class CSHARP : public Language {
return SWIG_OK;
}
+ /* -----------------------------------------------------------------------------
+ * extraDirectorProtectedCPPMethodsRequired()
+ * ----------------------------------------------------------------------------- */
+
+ bool extraDirectorProtectedCPPMethodsRequired() const {
+ return false;
+ }
+
/* --------------------------------------------------------------------
* Java_director_declaration()
*
diff --git a/Source/Modules/emit.cxx b/Source/Modules/emit.cxx
index 8974377f3..d545cdc3d 100644
--- a/Source/Modules/emit.cxx
+++ b/Source/Modules/emit.cxx
@@ -394,26 +394,15 @@ void emit_action(Node *n, Wrapper *f) {
action = Getattr(n,"wrap:action");
assert(action != 0);
- if (!(is_public(n)) && is_member_director(n)) {
- /* We need to add an extra dynamic_cast to
- access the director class, where the virtual
- methods are all public */
+ if (!is_public(n) && (is_member_director(n) || GetFlag(n, "explicitcall"))) {
+ /* In order to call protected virtual director methods from the target language, we need
+ * to add an extra dynamic_cast to call the public C++ wrapper in the director class. */
Node* parent = Getattr(n,"parentNode");
String* symname = Getattr(parent, "sym:name");
String* dirname = NewStringf("SwigDirector_%s", symname);
String* dirdecl = NewStringf("%s *darg = 0", dirname);
Wrapper_add_local(f, "darg", dirdecl);
Printf(f->code, "darg = dynamic_cast<%s *>(arg1);\n",dirname);
- Replace(action, "arg1", "darg", DOH_REPLACE_FIRST);
- if (Getattr(n,"qualifier")) {
- /* fix constant casting introduced by a const method decl */
- String* classtype = Getattr(parent, "classtype");
- /*
- String *ccast = NewStringf("((%s const *)darg)",classtype);
- if (Strstr(action,ccast) != 0)
- */
- Replace(action, classtype, dirname, DOH_REPLACE_FIRST);
- }
Delete(dirname);
Delete(dirdecl);
}
diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx
index e7dc03056..e0179c837 100644
--- a/Source/Modules/java.cxx
+++ b/Source/Modules/java.cxx
@@ -1870,6 +1870,9 @@ class JAVA : public Language {
// Wrappers not wanted for some methods where the parameters cannot be overloaded in Java
if (Getattr(n, "overload:ignore")) return;
+ // Don't generate proxy method for additional explicitcall method used in directors
+ if (GetFlag(n, "explicitcall")) return;
+
if (l) {
if (SwigType_type(Getattr(l,"type")) == T_VOID) {
l = nextSibling(l);
@@ -1985,6 +1988,29 @@ class JAVA : public Language {
else
Replaceall(tm,"$owner","false");
substituteClassname(t, tm);
+
+ // For director methods: generate code to selectively make a normal polymorphic call or
+ // an explicit method call - needed to prevent infinite recursion calls in director methods.
+ Node *explicit_n = Getattr(n,"explicitcallnode");
+ if (explicit_n) {
+ String *ex_overloaded_name = getOverloadedName(explicit_n);
+ String *ex_intermediary_function_name = Swig_name_member(proxy_class_name, ex_overloaded_name);
+
+ String *ex_imcall = Copy(imcall);
+ Replaceall(ex_imcall, intermediary_function_name, ex_intermediary_function_name);
+
+ String *excode = NewString("");
+ if (!Cmp(return_type, "void"))
+ Printf(excode, "if (getClass() == %s.class) %s; else %s", proxy_class_name, imcall, ex_imcall);
+ else
+ Printf(excode, "(getClass() == %s.class) ? %s : %s", proxy_class_name, imcall, ex_imcall);
+
+ Clear(imcall);
+ Printv(imcall, excode, NIL);
+ Delete(ex_overloaded_name);
+ Delete(excode);
+ }
+
Replaceall(tm, "$jnicall", imcall);
} else {
Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number,
@@ -3464,6 +3490,22 @@ class JAVA : public Language {
Printf(w->code, "}");
+ // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
+ String *inline_extra_method = NewString("");
+ if (dirprot_mode() && !is_public(n) && !pure_virtual)
+ {
+ Printv(inline_extra_method, declaration, NIL);
+ String *extra_method_name = NewStringf("%sSwigPublic", name);
+ Replaceall(inline_extra_method, name, extra_method_name);
+ Replaceall(inline_extra_method, ";\n", " {\n ");
+ if (!is_void)
+ Printf(inline_extra_method, "return ");
+ String *methodcall = Swig_method_call(super, l);
+ Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
+ Delete(methodcall);
+ Delete(extra_method_name);
+ }
+
/* emit code */
if (status == SWIG_OK && output_director) {
if(!is_void) {
@@ -3475,9 +3517,11 @@ class JAVA : public Language {
if (!Getattr(n,"defaultargs")) {
Wrapper_print(w, f_directors);
Printv(f_directors_h, declaration, NIL);
+ Printv(f_directors_h, inline_extra_method, NIL);
}
}
+ Delete(inline_extra_method);
Delete(qualified_return);
Delete(jnidesc);
Delete(c_ret_type);
@@ -3767,6 +3811,14 @@ class JAVA : public Language {
return SWIG_OK;
}
+ /* -----------------------------------------------------------------------------
+ * extraDirectorProtectedCPPMethodsRequired()
+ * ----------------------------------------------------------------------------- */
+
+ bool extraDirectorProtectedCPPMethodsRequired() const {
+ return false;
+ }
+
/* --------------------------------------------------------------------
* Java_director_declaration()
*
diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx
index 2371ef1fd..4e7a59d05 100644
--- a/Source/Modules/lang.cxx
+++ b/Source/Modules/lang.cxx
@@ -45,6 +45,7 @@ static int InClass = 0; /* Parsing C++ or not */
static String *ClassName = 0; /* This is the real name of the current class */
static String *ClassPrefix = 0; /* Class prefix */
static String *ClassType = 0; /* Fully qualified type name to use */
+static String *DirectorClassName = 0;/* Director name of the current class */
int Abstract = 0;
int ImportMode = 0;
int IsVirtual = 0;
@@ -974,26 +975,27 @@ Language::functionHandler(Node *n) {
globalfunctionHandler(n);
} else {
Node* explicit_n = 0;
- if (GetFlag(n, "feature:explicitcall")) {
- // Add in an explicit wrapper call to virtual methods
- if (Cmp(storage, "virtual") == 0 && (cplus_mode == PUBLIC))
- explicit_n = Copy(n);
+ if (directorsEnabled() && is_member_director(CurrentClass,n) && !Extend && !extraDirectorProtectedCPPMethodsRequired()) {
+ bool virtual_but_not_pure_virtual = (!(Cmp(storage, "virtual")) && (Cmp(Getattr(n, "value"), "0") != 0));
+ if (virtual_but_not_pure_virtual) {
+ // Add additional wrapper which makes an explicit call to the virtual method (ie not a virtual call)
+ explicit_n = Copy(n);
+ String *new_symname = Copy(Getattr(n,"sym:name"));
+ String *suffix = Getattr(parentNode(n),"sym:name");
+ Printv(new_symname, "SwigExplicit", suffix, NIL);
+ Setattr(explicit_n,"sym:name", new_symname);
+ Delattr(explicit_n,"storage");
+ Delattr(explicit_n,"override");
+ Delattr(explicit_n,"hides");
+ SetFlag(explicit_n,"explicitcall");
+ Setattr(n, "explicitcallnode", explicit_n);
+ }
}
-
+
memberfunctionHandler(n);
-
+
if (explicit_n) {
- String *new_symname = Copy(Getattr(n,"sym:name"));
- String *suffix = Getattr(n,"feature:explicitcall:suffix");
- if (!suffix)
- suffix = Getattr(parentNode(n),"sym:name");
- Printv(new_symname, suffix, NIL);
- Setattr(explicit_n,"sym:name", new_symname);
- Delattr(explicit_n,"storage");
- Delattr(explicit_n,"override");
- Delattr(explicit_n,"hides");
- SetFlag(explicit_n,"explicitcall");
- memberfunctionHandler(explicit_n);
+ memberfunctionHandler(explicit_n);
Delattr(explicit_n,"explicitcall");
Delete(explicit_n);
}
@@ -1149,12 +1151,31 @@ Language::memberfunctionHandler(Node *n) {
Setattr(n,"classname",Getattr(CurrentClass,"allocate:smartpointerbase"));
}
}
- /* Transformation */
- Swig_MethodToFunction(n,ClassType, Getattr(n,"template") ? 0 : Extend | SmartPointer);
+
+ // Set up the type for the cast to this class for use when wrapping const director (virtual) methods.
+ // Note: protected director methods only.
+ String* director_type = 0;
+ if (!is_public(n) && (is_member_director(CurrentClass,n) || GetFlag(n, "explicitcall"))) {
+ director_type = Copy(DirectorClassName);
+ String *qualifier = Getattr(n,k_qualifier);
+ if (qualifier)
+ SwigType_push(director_type,qualifier);
+ SwigType_add_pointer(director_type);
+ }
+
+ int DirectorExtraCall = 0;
+ if (directorsEnabled() && is_member_director(CurrentClass,n) && !SmartPointer)
+ if (extraDirectorProtectedCPPMethodsRequired())
+ DirectorExtraCall = CWRAP_DIRECTOR_TWO_CALLS;
+
+ if (GetFlag(n, "explicitcall"))
+ DirectorExtraCall = CWRAP_DIRECTOR_ONE_CALL;
+
+ Swig_MethodToFunction(n, ClassType, Getattr(n,"template") ? 0 : Extend | SmartPointer | DirectorExtraCall, director_type, is_member_director(CurrentClass,n));
Setattr(n,"sym:name",fname);
functionWrapper(n);
- /* DelWrapper(w);*/
+ Delete(director_type);
Delete(fname);
Swig_restore(n);
return SWIG_OK;
@@ -1970,15 +1991,13 @@ int Language::classDirectorDestructor(Node *n) {
*/
File *f_directors = Swig_filebyname("director");
File *f_directors_h = Swig_filebyname("director_h");
- String *classname= Swig_class_name(getCurrentClass());
if (Getattr(n,"throw")) {
- Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname);
- Printf(f_directors, "SwigDirector_%s::~SwigDirector_%s() throw () {\n}\n\n", classname, classname);
+ Printf(f_directors_h, " virtual ~%s() throw ();\n", DirectorClassName);
+ Printf(f_directors, "%s::~%s() throw () {\n}\n\n", DirectorClassName, DirectorClassName);
} else {
- Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname);
- Printf(f_directors, "SwigDirector_%s::~SwigDirector_%s() {\n}\n\n", classname, classname);
+ Printf(f_directors_h, " virtual ~%s();\n", DirectorClassName);
+ Printf(f_directors, "%s::~%s() {\n}\n\n", DirectorClassName, DirectorClassName);
}
- Delete(classname);
return SWIG_OK;
}
@@ -2290,6 +2309,7 @@ int Language::classDeclaration(Node *n) {
}
if (dir) {
+ DirectorClassName = NewStringf("SwigDirector_%s", symname);
classDirector(n);
}
/* check for abstract after resolving directors */
@@ -2306,6 +2326,7 @@ int Language::classDeclaration(Node *n) {
Delete(ClassType); ClassType = 0;
Delete(ClassPrefix); ClassPrefix = 0;
Delete(ClassName); ClassName = 0;
+ Delete(DirectorClassName); DirectorClassName = 0;
Swig_restore(n);
return SWIG_OK;
}
@@ -2340,6 +2361,35 @@ int Language::classHandler(Node *n) {
/* emit director disown method */
if (hasDirector) {
classDirectorDisown(n);
+
+ /* Emit additional protected virtual methods - only needed if the language module
+ * codes logic in the C++ layer instead of the director proxy class method - primarily
+ * to catch public use of protected methods by the sripting languages. */
+ if (dirprot_mode() && extraDirectorProtectedCPPMethodsRequired()) {
+ Node *vtable = Getattr(n, "vtable");
+ String* symname = Getattr(n, "sym:name");
+ Node *item;
+ Iterator k;
+ AccessMode old_mode = cplus_mode;
+ cplus_mode = PROTECTED;
+ for (k = First(vtable); k.key; k = Next(k)) {
+ item = k.item;
+ Node *method = Getattr(item, "methodNode");
+ SwigType *type = Getattr(method,"nodeType");
+ if (Strcmp(type,"cdecl") !=0 ) continue;
+ String* methodname = Getattr(method,"sym:name");
+ String* wrapname = NewStringf("%s_%s", symname,methodname);
+ if (!Getattr(symbols,wrapname) && (!is_public(method))) {
+ Node* m = Copy(method);
+ Setattr(m, "director", "1");
+ Setattr(m,"parentNode", n);
+ cDeclaration(m);
+ Delete(m);
+ }
+ Delete(wrapname);
+ }
+ cplus_mode = old_mode;
+ }
}
return SWIG_OK;
@@ -3049,7 +3099,7 @@ int Language::need_nonpublic_member(Node *n)
needed. */
return 1;
} else {
- /* if the method is pure virtual, we needed it. */
+ /* if the method is pure virtual, we need it. */
int pure_virtual = (Cmp(Getattr(n,"value"),"0") == 0);
return pure_virtual;
}
@@ -3067,6 +3117,14 @@ int Language::is_smart_pointer() const {
return SmartPointer;
}
+/* -----------------------------------------------------------------------------
+ * Language::extraDirectorProtectedCPPMethodsRequired()
+ * ----------------------------------------------------------------------------- */
+
+bool Language::extraDirectorProtectedCPPMethodsRequired() const {
+ return true;
+}
+
/* -----------------------------------------------------------------------------
* Language::is_wrapping_class()
* ----------------------------------------------------------------------------- */
diff --git a/Source/Modules/ocaml.cxx b/Source/Modules/ocaml.cxx
index 276cd1a98..c9aecc055 100755
--- a/Source/Modules/ocaml.cxx
+++ b/Source/Modules/ocaml.cxx
@@ -448,6 +448,7 @@ public:
SwigType *d = Getattr(n,"type");
String *return_type_normalized = normalizeTemplatedClassName(d);
ParmList *l = Getattr(n,"parms");
+ int director_method = 0;
Parm *p;
Wrapper *f = NewWrapper();
@@ -465,10 +466,7 @@ public:
int numreq;
int newobj = GetFlag(n,"feature:new");
String *nodeType = Getattr(n, "nodeType");
- int constructor = !Cmp(nodeType, "constructor");
int destructor = (!Cmp(nodeType, "destructor"));
- String *storage = Getattr(n,"storage");
- int isVirtual = !Cmp(storage,"virtual");
String *overname = 0;
bool isOverloaded = Getattr(n,"sym:overloaded") ? true : false;
@@ -687,18 +685,12 @@ public:
// (the smart-pointer) and the director object (the "pointee") are
// distinct.
- if (directorsEnabled()) {
- if (!is_smart_pointer()) {
- if (/*directorbase &&*/ !constructor && !destructor
- && isVirtual && !Getattr(n,"feature:nodirector")) {
- Wrapper_add_local(f, "director", "Swig::Director *director = 0");
- Printf(f->code, "director = dynamic_cast(arg1);\n");
-
- Printf(f->code,
- "if (director && !director->swig_get_up(false))"
- "director->swig_set_up();\n");
- }
- }
+ director_method = is_member_director(n) && !is_smart_pointer() && !destructor;
+ if (director_method) {
+ Wrapper_add_local(f, "director", "Swig::Director *director = 0");
+ Printf(f->code, "director = dynamic_cast(arg1);\n");
+ Wrapper_add_local(f, "upcall", "bool upcall = false");
+ Append(f->code, "upcall = (director);\n");
}
// Now write code to make the function call
@@ -1665,17 +1657,6 @@ public:
Printv(w->code, "swig_result = Val_unit;\n",0);
Printf(w->code,"args = Val_unit;\n");
- /* direct call to superclass if _up is set */
- if( pure_virtual ) {
- Printf(w->code, "if (swig_get_up()) {\n");
- Printf(w->code, " throw Swig::DirectorPureVirtualException();\n");
- Printf(w->code, "}\n");
- } else {
- Printf(w->code, "if (swig_get_up()) {\n");
- Printf(w->code, "CAMLreturn(%s);\n", Swig_method_call(super,l));
- Printf(w->code, "}\n");
- }
-
/* wrap complex arguments to values */
Printv(w->code, wrap_args, NIL);
@@ -1778,11 +1759,28 @@ public:
Printf(w->code, "}\n");
+ // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
+ String *inline_extra_method = NewString("");
+ if (dirprot_mode() && !is_public(n) && !pure_virtual)
+ {
+ Printv(inline_extra_method, declaration, NIL);
+ String *extra_method_name = NewStringf("%sSwigPublic", name);
+ Replaceall(inline_extra_method, name, extra_method_name);
+ Replaceall(inline_extra_method, ";\n", " {\n ");
+ if (!is_void)
+ Printf(inline_extra_method, "return ");
+ String *methodcall = Swig_method_call(super, l);
+ Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
+ Delete(methodcall);
+ Delete(extra_method_name);
+ }
+
/* emit the director method */
if (status == SWIG_OK) {
if (!Getattr(n,"defaultargs")) {
Wrapper_print(w, f_directors);
Printv(f_directors_h, declaration, NIL);
+ Printv(f_directors_h, inline_extra_method, NIL);
}
}
diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx
index beb485011..4029f0560 100644
--- a/Source/Modules/python.cxx
+++ b/Source/Modules/python.cxx
@@ -1612,7 +1612,6 @@ public:
int constructor = (!Cmp(nodeType, "constructor"));
int destructor = (!Cmp(nodeType, "destructor"));
String *storage = Getattr(n,"storage");
- int isVirtual = (Cmp(storage,"virtual") == 0);
/* Only the first constructor is handled as init method. Others
constructor can be emitted via %rename */
int handled_as_init = 0;
@@ -1946,25 +1945,21 @@ public:
// (the smart-pointer) and the director object (the "pointee") are
// distinct.
- if (directorsEnabled()) {
- if (!is_smart_pointer()) {
- if (/*directorbase &&*/ !constructor && !destructor
- && isVirtual && !Getattr(n,"feature:nodirector")) {
- director_method = 1;
- Wrapper_add_local(f, "director", "Swig::Director *director = 0");
- Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n");
- if (dirprot_mode() && !is_public(n)) {
- Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name);
- Printf(f->code, "SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing protected member %s\");\n", name);
- Append(f->code, "SWIG_fail;\n");
- Append(f->code, "}\n");
- }
- if (funpack) {
- Append(f->code, "if (director && (director->swig_get_self()==swig_obj[0])) director->swig_set_up();\n");
- } else {
- Append(f->code, "if (director && (director->swig_get_self()==obj0)) director->swig_set_up();\n");
- }
- }
+ director_method = is_member_director(n) && !is_smart_pointer() && !destructor;
+ if (director_method) {
+ Wrapper_add_local(f, "director", "Swig::Director *director = 0");
+ Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n");
+ if (dirprot_mode() && !is_public(n)) {
+ Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name);
+ Printf(f->code, "SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing protected member %s\");\n", name);
+ Append(f->code, "SWIG_fail;\n");
+ Append(f->code, "}\n");
+ }
+ Wrapper_add_local(f, "upcall", "bool upcall = false");
+ if (funpack) {
+ Append(f->code, "upcall = (director && (director->swig_get_self()==swig_obj[0]));\n");
+ } else {
+ Append(f->code, "upcall = (director && (director->swig_get_self()==obj0));\n");
}
}
@@ -3570,29 +3565,12 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
p = nextSibling(p);
}
-
-/* add the method name as a PyString */
+ /* add the method name as a PyString */
String *pyname = Getattr(n,"sym:name");
int allow_thread = threads_enable(n);
- /* direct call to superclass if _up is set */
if (allow_thread) thread_begin_block(n, w->code);
- Append(w->code, "if (swig_get_up()) {\n");
- if (pure_virtual) {
- Printf(w->code,
- "Swig::DirectorPureVirtualException::raise(\"%s.\");\n",Swig_method_call(super,l));
- } else {
- if (allow_thread) thread_begin_allow(n, w->code);
- if (is_void) {
- Printf(w->code, "%s;\n", Swig_method_call(super,l));
- Append(w->code, "return;\n");
- } else {
- Printf(w->code, "return %s;\n", Swig_method_call(super,l));
- }
- if (allow_thread) thread_end_allow(n, w->code);
- }
- Append(w->code, "}\n");
/* declare method return value
* if the return value is a reference or const reference, a specialized typemap must
@@ -3784,11 +3762,28 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
}
Append(w->code, "}\n");
+ // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
+ String *inline_extra_method = NewString("");
+ if (dirprot_mode() && !is_public(n) && !pure_virtual)
+ {
+ Printv(inline_extra_method, declaration, NIL);
+ String *extra_method_name = NewStringf("%sSwigPublic", name);
+ Replaceall(inline_extra_method, name, extra_method_name);
+ Replaceall(inline_extra_method, ";\n", " {\n ");
+ if (!is_void)
+ Printf(inline_extra_method, "return ");
+ String *methodcall = Swig_method_call(super, l);
+ Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
+ Delete(methodcall);
+ Delete(extra_method_name);
+ }
+
/* emit the director method */
if (status == SWIG_OK) {
if (!Getattr(n,"defaultargs")) {
Wrapper_print(w, f_directors);
Printv(f_directors_h, declaration, NIL);
+ Printv(f_directors_h, inline_extra_method, NIL);
}
}
diff --git a/Source/Modules/ruby.cxx b/Source/Modules/ruby.cxx
index 16a7f7cf6..f811a17dd 100644
--- a/Source/Modules/ruby.cxx
+++ b/Source/Modules/ruby.cxx
@@ -991,7 +991,6 @@ public:
bool constructor;
bool destructor;
String *storage;
- bool isVirtual;
String *symname = Copy(Getattr(n,"sym:name"));
SwigType *t = Getattr(n,"type");
@@ -1009,7 +1008,6 @@ public:
constructor = (!Cmp(nodeType, "constructor"));
destructor = (!Cmp(nodeType, "destructor"));
storage = Getattr(n, "storage");
- isVirtual = (Cmp(storage, "virtual") == 0);
/* If the C++ class constructor is overloaded, we only want to
* write out the "new" singleton method once since it is always
@@ -1135,16 +1133,12 @@ public:
// (the smart-pointer) and the director object (the "pointee") are
// distinct.
- if (directorsEnabled()) {
- if (!is_smart_pointer()) {
- if (/*directorbase &&*/ !constructor && !destructor
- && isVirtual && !Getattr(n,"feature:nodirector")) {
- director_method = 1;
- Wrapper_add_local(f, "director", "Swig::Director *director = 0");
- Printf(f->code, "director = dynamic_cast(arg1);\n");
- Printf(f->code, "if (director && (director->swig_get_self() == self)) director->swig_set_up();\n");
- }
- }
+ director_method = is_member_director(n) && !is_smart_pointer() && !destructor;
+ if (director_method) {
+ Wrapper_add_local(f, "director", "Swig::Director *director = 0");
+ Printf(f->code, "director = dynamic_cast(arg1);\n");
+ Wrapper_add_local(f, "upcall", "bool upcall = false");
+ Append(f->code, "upcall = (director && (director->swig_get_self() == self));\n");
}
/* Now write code to make the function call */
@@ -2484,20 +2478,6 @@ public:
/* declare Ruby return value */
Wrapper_add_local(w, "result", "VALUE result");
- /* direct call to superclass if _up is set */
- Printf(w->code, "if (swig_get_up()) {\n");
- if (pure_virtual) {
- Printf(w->code, "throw Swig::DirectorPureVirtualException();\n");
- } else {
- if (is_void) {
- Printf(w->code, "%s;\n", Swig_method_call(super,l));
- Printf(w->code, "return;\n");
- } else {
- Printf(w->code, "return %s;\n", Swig_method_call(super,l));
- }
- }
- Printf(w->code, "}\n");
-
/* wrap complex arguments to VALUEs */
Printv(w->code, wrap_args, NIL);
@@ -2588,14 +2568,30 @@ public:
}
Delete(rettype);
}
-
Printf(w->code, "}\n");
+ // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
+ String *inline_extra_method = NewString("");
+ if (dirprot_mode() && !is_public(n) && !pure_virtual)
+ {
+ Printv(inline_extra_method, declaration, NIL);
+ String *extra_method_name = NewStringf("%sSwigPublic", name);
+ Replaceall(inline_extra_method, name, extra_method_name);
+ Replaceall(inline_extra_method, ";\n", " {\n ");
+ if (!is_void)
+ Printf(inline_extra_method, "return ");
+ String *methodcall = Swig_method_call(super, l);
+ Printv(inline_extra_method, methodcall, ";\n }\n", NIL);
+ Delete(methodcall);
+ Delete(extra_method_name);
+ }
+
/* emit the director method */
if (status == SWIG_OK) {
if (!Getattr(n,"defaultargs")) {
Wrapper_print(w, f_directors);
Printv(f_directors_h, declaration, NIL);
+ Printv(f_directors_h, inline_extra_method, NIL);
}
}
diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h
index 966a8068c..3ff14774c 100644
--- a/Source/Modules/swigmod.h
+++ b/Source/Modules/swigmod.h
@@ -272,6 +272,9 @@ protected:
/* Return true if the current method is part of a smart-pointer */
int is_smart_pointer() const;
+ /* Some language modules require additional wrappers for virtual methods not declared in sub-classes */
+ virtual bool extraDirectorProtectedCPPMethodsRequired() const;
+
/* Director subclass comparison test */
String *none_comparison;
diff --git a/Source/Swig/cwrap.c b/Source/Swig/cwrap.c
index e789d9552..d038df009 100644
--- a/Source/Swig/cwrap.c
+++ b/Source/Swig/cwrap.c
@@ -382,7 +382,7 @@ Swig_cfunction_call(String_or_char *name, ParmList *parms) {
* ----------------------------------------------------------------------------- */
static String *
-Swig_cmethod_call(String_or_char *name, ParmList *parms, String_or_char *self, String *explicit_qualifier) {
+Swig_cmethod_call(String_or_char *name, ParmList *parms, String_or_char *self, String *explicit_qualifier, SwigType *director_type) {
String *func, *nname;
int i = 0;
Parm *p = parms;
@@ -402,36 +402,44 @@ Swig_cmethod_call(String_or_char *name, ParmList *parms, String_or_char *self, S
} else {
nname = SwigType_namestr(name);
}
-
- pt = Getattr(p,k_type);
- /* If the method is invoked through a dereferenced pointer, we don't add any casts
- (needed for smart pointers). Otherwise, we cast to the appropriate type */
-
- if (Strstr(func,"*this")) {
- String *pname = Swig_cparm_name(p,0);
- Replaceall(func,"this", pname);
- Delete(pname);
- } else {
- String *pname = Swig_cparm_name(p,0);
- String *rcaststr = SwigType_rcaststr(pt, pname);
+ if (director_type) {
+ const char *pname = "darg";
+ String *rcaststr = SwigType_rcaststr(director_type, pname);
Replaceall(func,"this", rcaststr);
Delete(rcaststr);
- Delete(pname);
+ } else {
+ pt = Getattr(p,k_type);
+
+ /* If the method is invoked through a dereferenced pointer, we don't add any casts
+ (needed for smart pointers). Otherwise, we cast to the appropriate type */
+
+ if (Strstr(func,"*this")) {
+ String *pname = Swig_cparm_name(p,0);
+ Replaceall(func,"this", pname);
+ Delete(pname);
+ } else {
+ String *pname = Swig_cparm_name(p,0);
+ String *rcaststr = SwigType_rcaststr(pt, pname);
+ Replaceall(func,"this", rcaststr);
+ Delete(rcaststr);
+ Delete(pname);
+ }
+
+ /*
+ SWIGTEMPLATEDESIMBUAGATOR is compiler dependent (swiglabels.swg),
+ - SUN Studio 9 requires 'template',
+ - gcc-3.4 forbids the use of 'template' (correctly implementing the ISO C++ standard)
+ the others don't seem to care,
+ */
+ if (SwigType_istemplate(name))
+ Printf(func,"SWIGTEMPLATEDISAMBIGUATOR ");
+
+ if (explicit_qualifier) {
+ Printv(func, explicit_qualifier, "::", NIL);
+ }
}
- /*
- SWIGTEMPLATEDESIMBUAGATOR is compiler dependent (swiglabels.swg),
- - SUN Studio 9 requires 'template',
- - gcc-3.4 forbids the use of 'template'.
- the rest seems not caring very much,
- */
- if (SwigType_istemplate(name))
- Printf(func,"SWIGTEMPLATEDISAMBIGUATOR ");
-
- if (explicit_qualifier)
- Printv(func, explicit_qualifier, "::", NIL);
-
Printf(func,"%s(", nname);
i++;
@@ -787,7 +795,7 @@ Swig_add_extension_code(Node *n, const String *function_name, ParmList *parms,
* ----------------------------------------------------------------------------- */
int
-Swig_MethodToFunction(Node *n, String *classname, int flags) {
+Swig_MethodToFunction(Node *n, String *classname, int flags, SwigType *director_type, int is_director) {
String *name, *qualifier;
ParmList *parms;
SwigType *type;
@@ -845,13 +853,51 @@ Swig_MethodToFunction(Node *n, String *classname, int flags) {
/* Generate action code for the access */
if (!(flags & CWRAP_EXTEND)) {
- /* Call the explicit method rather than allow for a polymorphic call */
- String *explicit_qualifier = GetFlag(n,"explicitcall") ?
- SwigType_namestr(Getattr(Getattr(parentNode(n),"typescope"),k_qname)) : 0;
+ String *explicit_qualifier = 0;
+ String *call = 0;
+ String *cres = 0;
+ String *explicitcall_name = 0;
+ int pure_virtual = !(Cmp(Getattr(n,k_storage), "virtual")) && !(Cmp(Getattr(n,k_value), "0"));
- String *call = Swig_cmethod_call(name,p,self,explicit_qualifier);
- String *cres = Swig_cresult(Getattr(n,k_type),k_result, call);
- Setattr(n,k_wrapaction, cres);
+ /* Call the explicit method rather than allow for a polymorphic call */
+ if ((flags & CWRAP_DIRECTOR_TWO_CALLS) || (flags & CWRAP_DIRECTOR_ONE_CALL)) {
+ String* access = Getattr(n, "access");
+ if (access && (Cmp(access, "protected") == 0)) {
+ /* If protected access (can only be if a director method) then call the extra public accessor method (language module must provide this) */
+ String *explicit_qualifier_tmp = SwigType_namestr(Getattr(Getattr(parentNode(n),"typescope"),k_qname));
+ explicitcall_name = NewStringf("%sSwigPublic", name);
+ explicit_qualifier = NewStringf("SwigDirector_%s", explicit_qualifier_tmp);
+ Delete(explicit_qualifier_tmp);
+ } else {
+ explicit_qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n),"typescope"),k_qname));
+ }
+ }
+
+ call = Swig_cmethod_call(explicitcall_name ? explicitcall_name : name, p, self, explicit_qualifier, director_type);
+ cres = Swig_cresult(Getattr(n,k_type),k_result, call);
+
+ if (pure_virtual && is_director && (flags & CWRAP_DIRECTOR_TWO_CALLS)) {
+ String *qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n),"typescope"),k_qname));
+ Delete(cres);
+ cres = NewStringf("Swig::DirectorPureVirtualException::raise(\"%s::%s\");", qualifier, name);
+ Delete(qualifier);
+ }
+
+ if (flags & CWRAP_DIRECTOR_TWO_CALLS) {
+ /* Create two method calls, one to call the explicit method, the other a normal polymorphic function call */
+ String *cres_both_calls = NewStringf("");
+ String *call_extra = Swig_cmethod_call(name, p, self, 0, director_type);
+ String *cres_extra = Swig_cresult(Getattr(n,k_type),k_result, call_extra);
+ Printv(cres_both_calls, "if (upcall) {\n", cres, "\n", "} else {", cres_extra, "\n}", NIL);
+ Setattr(n,k_wrapaction, cres_both_calls);
+ Delete(cres_extra);
+ Delete(call_extra);
+ Delete(cres_both_calls);
+ } else {
+ Setattr(n,k_wrapaction, cres);
+ }
+
+ Delete(explicitcall_name);
Delete(call);
Delete(cres);
Delete(explicit_qualifier);
diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h
index c8890f6e1..b1e4a497b 100644
--- a/Source/Swig/swig.h
+++ b/Source/Swig/swig.h
@@ -494,7 +494,7 @@ extern int Swig_add_extension_code(Node *n, const String *function_name,
/* --- Transformations --- */
-extern int Swig_MethodToFunction(Node *n, String *classname, int flags);
+extern int Swig_MethodToFunction(Node *n, String *classname, int flags, SwigType *director_type, int is_director);
extern int Swig_ConstructorToFunction(Node *n, String *classname,
String *none_comparison,
String *director_ctor,
@@ -508,6 +508,8 @@ extern int Swig_VarsetToFunction(Node *n, int flags);
#define CWRAP_EXTEND 0x01
#define CWRAP_SMART_POINTER 0x02
#define CWRAP_NATURAL_VAR 0x04
+#define CWRAP_DIRECTOR_ONE_CALL 0x08
+#define CWRAP_DIRECTOR_TWO_CALLS 0x10
/* --- Director Helpers --- */
extern Node *Swig_methodclass(Node *n);