- 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
This commit is contained in:
William S Fulton 2006-09-13 20:55:24 +00:00
commit f0d1d772fa
12 changed files with 355 additions and 303 deletions

View file

@ -83,7 +83,6 @@
<li><a href="#java_directors_classes">Director classes</a>
<li><a href="#java_directors_overhead">Overhead and code bloat</a>
<li><a href="#java_directors_example">Simple directors example</a>
<li><a href="#java_directors_explicitcall">Director base method calls</a>
</ul>
<li><a href="#common_customization">Common customization features</a>
<ul>
@ -3204,62 +3203,6 @@ directorDerived::upcall_method() invoked.
</pre>
</div>
<H3><a name="java_directors_explicitcall"></a>20.5.5 Director base method calls</H3>
<p>
There is a limitation with Java directors when calling a base class method from an overridden method.
A <tt>java.lang.StackOverflowError</tt> 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 <a href="SWIGPlus.html#SWIGPlus_explicitcall">explicitcall feature flag</a>
is one way to work around this problem. Consider the following C++ code:
</p>
<div class="code">
<pre>
%feature("director");
%feature("explicitcall");
%include &lt;std_string.i&gt;
%inline %{
struct Thing {
virtual std::string getit() { return "Thing"; }
virtual ~Thing() {}
};
%}
</pre>
</div>
<p>
and the following Java class:
</p>
<div class="code">
<pre>
class JavaThing extends Thing {
public String getit() {
return "Java" + super.getit();
}
}
</pre>
</div>
<p>
The overridden <tt>JavaThing.getit()</tt> method will throw the <tt>java.lang.StackOverflowError</tt> 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 <tt>getitThing()</tt>. The modified version will then avoid the recursive calls:
</p>
<div class="code">
<pre>
class JavaThing extends Thing {
public String getit() {
return "Java" + super.getitThing();
}
}
</pre>
</div>
<H2><a name="common_customization"></a>20.6 Common customization features</H2>

View file

@ -1668,86 +1668,6 @@ functions for virtual members that are already defined in a base
class.
</p>
<H3><a name="SWIGPlus_explicitcall"></a>6.13.1 Explicit base class method calls</H3>
<p>
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
<tt>explicitcall</tt> <a href="Customization.html#Customization_feature_flags">feature flag</a> 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 <tt>suffix</tt>
<a href="Customization.html#Customization_feature_attributes">feature attribute</a>.
For example, consider the following code:
</p>
<div class="code">
<pre>
%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"; }
};
</pre>
</div>
<p>
From Python, it is then possible to call explicit methods in the inheritance hierarchy.
Note the suffix names:
</p>
<div class="targetlang">
<pre>
$ python
&gt;&gt;&gt; from example import *
&gt;&gt;&gt; child = Child()
&gt;&gt;&gt; print child.describe() # normal polymorphic call
Child
&gt;&gt;&gt; print child.describePerson() # explicit Person::describe call
Person
&gt;&gt;&gt; print child.describeBambino() # explicit Child::describe call
Child
</pre>
</div>
<p>
The pseudo C++ code generated for the <tt>Person::describe</tt> methods is as follows:
</p>
<div class="code">
<pre>
// Normal virtual method wrapper
const char * Person_talk(Person *obj) {
const char * ret = obj-&gt;describe();
return ret;
}
// Additional wrapper due to %explicitcall
const char * Person_talkPerson(Person *obj) {
const char * ret = obj-&gt;Person::describe();
return ret;
}
</pre>
</div>
<p>
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.
<tt>%noexplicitcall</tt> can then be used to turn this feature off for the problem methods.
</p>
<H2><a name="SWIGPlus_nn21"></a>6.14 A brief discussion of multiple inheritance, pointers, and type checking</H2>

View file

@ -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()
*

View file

@ -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);
}

View file

@ -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()
*

View file

@ -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()
* ----------------------------------------------------------------------------- */

View file

@ -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<Swig::Director *>(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<Swig::Director *>(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);
}
}

View file

@ -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);
}
}

View file

@ -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<Swig::Director *>(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<Swig::Director *>(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);
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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);