mirror of https://github.com/swig/swig
Any 'using' statements in the protected section of a class were previously ignored with dirprot mode, certainly with Java and C#. Also directors - a call to a method being defined in the base class, not overridden in a subcalss, but again overridden in a class derived from the first subclass was not being dispatched correcly to the most derived class - affecting non-scripting languages. Fix for C# is based on recent fix for D.
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12419 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
96609f350e
commit
4a73d986dd
|
@ -5,6 +5,16 @@ See the RELEASENOTES file for a summary of changes in each release.
|
|||
Version 2.0.2 (in progress)
|
||||
===========================
|
||||
|
||||
2011-02-01: wsfulton
|
||||
[C#] Directors - a call to a method being defined in the base class, not
|
||||
overridden in a subclass, but again overridden in a class derived from
|
||||
the first subclass was not being dispatched correctly to the most derived class.
|
||||
See director_alternating.i for an example.
|
||||
|
||||
2011-02-01: wsfulton
|
||||
[C#, Java] Any 'using' statements in the protected section of a class were previously
|
||||
ignored with director protected (dirprot) mode.
|
||||
|
||||
2011-01-30: wsfulton
|
||||
Fix overloading with const pointer reference (SWIGTYPE *const&) parameters for a
|
||||
number of scripting languages.
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
using System;
|
||||
using director_alternatingNamespace;
|
||||
|
||||
public class director_alternating_runme {
|
||||
public static void Main() {
|
||||
if (director_alternating.getBar().id() != director_alternating.idFromGetBar())
|
||||
throw new Exception("idFromGetBar failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ public class runme
|
|||
Foo f = b.create();
|
||||
FooBar fb = new FooBar();
|
||||
FooBar2 fb2 = new FooBar2();
|
||||
FooBar3 fb3 = new FooBar3();
|
||||
|
||||
String s;
|
||||
s = fb.used();
|
||||
|
@ -37,6 +38,21 @@ public class runme
|
|||
s = fb.pong();
|
||||
if ( s != ("Bar::pong();Foo::pong();FooBar::ping();"))
|
||||
throw new Exception("bad FooBar::pong");
|
||||
|
||||
// if (fb3.cheer() != "FooBar3::cheer();")
|
||||
// throw new Exception("bad fb3::cheer");
|
||||
|
||||
if (fb2.callping() != "FooBar2::ping();")
|
||||
throw new Exception("bad fb2.callping");
|
||||
|
||||
if (fb2.callcheer() != "FooBar2::pang();Bar::pong();Foo::pong();FooBar2::ping();")
|
||||
throw new Exception("bad fb2.callcheer");
|
||||
|
||||
if (fb3.callping() != "Bar::ping();")
|
||||
throw new Exception("bad fb3.callping");
|
||||
|
||||
if (fb3.callcheer() != "FooBar3::cheer();")
|
||||
throw new Exception("bad fb3.callcheer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,4 +85,16 @@ class FooBar2 : Bar
|
|||
}
|
||||
}
|
||||
|
||||
class FooBar3 : Bar
|
||||
{
|
||||
public FooBar3() : base()
|
||||
{
|
||||
}
|
||||
|
||||
protected override String cheer()
|
||||
{
|
||||
return "FooBar3::cheer();";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ protected:
|
|||
virtual std::string used() {
|
||||
return pang() + pong();
|
||||
}
|
||||
|
||||
virtual std::string cheer() {
|
||||
return pang() + pong();
|
||||
}
|
||||
};
|
||||
|
||||
class Bar : public Foo
|
||||
|
@ -63,6 +67,14 @@ public:
|
|||
return new Bar();
|
||||
}
|
||||
|
||||
std::string callping() {
|
||||
return ping();
|
||||
}
|
||||
|
||||
std::string callcheer() {
|
||||
return cheer();
|
||||
}
|
||||
|
||||
std::string pong() {
|
||||
return "Bar::pong();" + Foo::pong();
|
||||
}
|
||||
|
@ -75,6 +87,7 @@ protected:
|
|||
std::string ping() {
|
||||
return "Bar::ping();";
|
||||
};
|
||||
using Foo::cheer;
|
||||
|
||||
enum Hello {hola, chao};
|
||||
|
||||
|
|
|
@ -59,9 +59,22 @@
|
|||
public:
|
||||
virtual C get_value() const = 0;
|
||||
using Bar::do_advance;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
%template(FooBar_int) FooBar<int>;
|
||||
|
||||
%inline %{
|
||||
struct SomeBase {
|
||||
virtual ~SomeBase() {}
|
||||
virtual void method1() {}
|
||||
virtual void method2() {}
|
||||
};
|
||||
|
||||
struct PrivateDerived : SomeBase {
|
||||
private:
|
||||
virtual void method1() {}
|
||||
using SomeBase::method2;
|
||||
};
|
||||
%}
|
||||
|
|
|
@ -19,6 +19,7 @@ public class director_protected_runme {
|
|||
Foo f = b.create();
|
||||
director_protected_FooBar fb = new director_protected_FooBar();
|
||||
director_protected_FooBar2 fb2 = new director_protected_FooBar2();
|
||||
director_protected_FooBar3 fb3 = new director_protected_FooBar3();
|
||||
|
||||
{
|
||||
String s = fb.used();
|
||||
|
@ -60,11 +61,34 @@ public class director_protected_runme {
|
|||
if ( !Modifier.isProtected(method.getModifiers()) )
|
||||
throw new RuntimeException("Foo::ping should be protected" );
|
||||
|
||||
method = b.getClass().getDeclaredMethod("cheer", (java.lang.Class[])null);
|
||||
if ( !Modifier.isProtected(method.getModifiers()) )
|
||||
throw new RuntimeException("Bar::cheer should be protected" );
|
||||
|
||||
method = f.getClass().getDeclaredMethod("cheer", (java.lang.Class[])null);
|
||||
if ( !Modifier.isProtected(method.getModifiers()) )
|
||||
throw new RuntimeException("Foo::cheer should be protected" );
|
||||
|
||||
} catch (NoSuchMethodException n) {
|
||||
throw new RuntimeException("NoSuchmethodException caught. Test failed.");
|
||||
throw new RuntimeException(n);
|
||||
} catch (SecurityException s) {
|
||||
throw new RuntimeException("SecurityException caught. Test failed.");
|
||||
}
|
||||
|
||||
if (!fb3.cheer().equals("director_protected_FooBar3::cheer();"))
|
||||
throw new RuntimeException("bad fb3::cheer");
|
||||
|
||||
if (!fb2.callping().equals("director_protected_FooBar2::ping();"))
|
||||
throw new RuntimeException("bad fb2.callping");
|
||||
|
||||
if (!fb2.callcheer().equals("director_protected_FooBar2::pang();Bar::pong();Foo::pong();director_protected_FooBar2::ping();"))
|
||||
throw new RuntimeException("bad fb2.callcheer");
|
||||
|
||||
if (!fb3.callping().equals("Bar::ping();"))
|
||||
throw new RuntimeException("bad fb3.callping");
|
||||
|
||||
if (!fb3.callcheer().equals("director_protected_FooBar3::cheer();"))
|
||||
throw new RuntimeException("bad fb3.callcheer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,3 +107,9 @@ class director_protected_FooBar2 extends Bar {
|
|||
}
|
||||
}
|
||||
|
||||
class director_protected_FooBar3 extends Bar {
|
||||
public String cheer() {
|
||||
return "director_protected_FooBar3::cheer();";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,17 @@ class FooBar2 extends Bar {
|
|||
}
|
||||
}
|
||||
|
||||
class FooBar3 extends Bar {
|
||||
function cheer() {
|
||||
return "FooBar3::cheer();";
|
||||
}
|
||||
}
|
||||
|
||||
$b = new Bar();
|
||||
$f = $b->create();
|
||||
$fb = new FooBar();
|
||||
$fb2 = new FooBar2();
|
||||
$fb3 = new FooBar3();
|
||||
|
||||
check::equal($fb->used(), "Foo::pang();Bar::pong();Foo::pong();FooBar::ping();", "bad FooBar::used");
|
||||
|
||||
|
@ -42,7 +49,7 @@ check::equal($f->pong(), "Bar::pong();Foo::pong();Bar::ping();", "bad Foo::pong"
|
|||
check::equal($fb->pong(), "Bar::pong();Foo::pong();FooBar::ping();", "bad FooBar::pong");
|
||||
|
||||
$method = new ReflectionMethod('Bar', 'ping');
|
||||
check::equal($method->isProtected(), true, "Boo::ping should be protected");
|
||||
check::equal($method->isProtected(), true, "Foo::ping should be protected");
|
||||
|
||||
$method = new ReflectionMethod('Foo', 'ping');
|
||||
check::equal($method->isProtected(), true, "Foo::ping should be protected");
|
||||
|
@ -50,5 +57,17 @@ check::equal($method->isProtected(), true, "Foo::ping should be protected");
|
|||
$method = new ReflectionMethod('FooBar', 'pang');
|
||||
check::equal($method->isProtected(), true, "FooBar::pang should be protected");
|
||||
|
||||
$method = new ReflectionMethod('Bar', 'cheer');
|
||||
check::equal($method->isProtected(), true, "Bar::cheer should be protected");
|
||||
|
||||
$method = new ReflectionMethod('Foo', 'cheer');
|
||||
check::equal($method->isProtected(), true, "Foo::cheer should be protected");
|
||||
|
||||
check::equal($fb3->cheer(), "FooBar3::cheer();", "bad fb3::pong");
|
||||
check::equal($fb2->callping(), "FooBar2::ping();", "bad fb2::callping");
|
||||
check::equal($fb2->callcheer(), "FooBar2::pang();Bar::pong();Foo::pong();FooBar2::ping();", "bad fb2::callcheer");
|
||||
check::equal($fb3->callping(), "Bar::ping();", "bad fb3::callping");
|
||||
check::equal($fb3->callcheer(), "FooBar3::cheer();", "bad fb3::callcheer");
|
||||
|
||||
check::done();
|
||||
?>
|
||||
|
|
|
@ -12,11 +12,16 @@ class FooBar2(Bar):
|
|||
def pang(self):
|
||||
return "FooBar2::pang();"
|
||||
|
||||
class FooBar3(Bar):
|
||||
def cheer(self):
|
||||
return "FooBar3::cheer();"
|
||||
|
||||
|
||||
b = Bar()
|
||||
f = b.create()
|
||||
fb = FooBar()
|
||||
fb2 = FooBar2()
|
||||
fb3 = FooBar3()
|
||||
|
||||
|
||||
try:
|
||||
|
@ -66,7 +71,7 @@ try:
|
|||
except:
|
||||
pass
|
||||
if not protected:
|
||||
raise RuntimeError,"Boo::ping is protected"
|
||||
raise RuntimeError,"Foo::ping is protected"
|
||||
|
||||
protected=1
|
||||
try:
|
||||
|
@ -86,3 +91,39 @@ except:
|
|||
pass
|
||||
if not protected:
|
||||
raise RuntimeError,"FooBar::pang is protected"
|
||||
|
||||
|
||||
protected=1
|
||||
try:
|
||||
b.cheer()
|
||||
protected=0
|
||||
except:
|
||||
pass
|
||||
if not protected:
|
||||
raise RuntimeError,"Bar::cheer is protected"
|
||||
|
||||
protected=1
|
||||
try:
|
||||
f.cheer()
|
||||
protected=0
|
||||
except:
|
||||
pass
|
||||
if not protected:
|
||||
raise RuntimeError,"Foo::cheer is protected"
|
||||
|
||||
if fb3.cheer() != "FooBar3::cheer();":
|
||||
raise RuntimeError, "bad fb3::cheer"
|
||||
|
||||
if fb2.callping() != "FooBar2::ping();":
|
||||
raise RuntimeError, "bad fb2.callping"
|
||||
|
||||
if fb2.callcheer() != "FooBar2::pang();Bar::pong();Foo::pong();FooBar2::ping();":
|
||||
raise RuntimeError, "bad fb2.callcheer"
|
||||
|
||||
if fb3.callping() != "Bar::ping();":
|
||||
raise RuntimeError, "bad fb3.callping"
|
||||
|
||||
if fb3.callcheer() != "FooBar3::cheer();":
|
||||
raise RuntimeError, "bad fb3.callcheer"
|
||||
|
||||
|
||||
|
|
|
@ -2292,17 +2292,24 @@ public:
|
|||
String *ex_imcall = Copy(imcall);
|
||||
Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name);
|
||||
Replaceall(imcall, "$imfuncname", 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);
|
||||
Node *directorNode = Getattr(n, "directorNode");
|
||||
if (directorNode) {
|
||||
UpcallData *udata = Getattr(directorNode, "upcalldata");
|
||||
String *methid = Getattr(udata, "class_methodidx");
|
||||
|
||||
Clear(imcall);
|
||||
Printv(imcall, excode, NIL);
|
||||
Delete(ex_overloaded_name);
|
||||
if (!Cmp(return_type, "void"))
|
||||
Printf(excode, "if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s)) %s; else %s", proxy_function_name, methid, ex_imcall, imcall);
|
||||
else
|
||||
Printf(excode, "(SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s) ? %s : %s)", proxy_function_name, methid, ex_imcall, imcall);
|
||||
|
||||
Clear(imcall);
|
||||
Printv(imcall, excode, NIL);
|
||||
} else {
|
||||
// probably an ignored method or nodirector
|
||||
}
|
||||
Delete(excode);
|
||||
Delete(ex_overloaded_name);
|
||||
} else {
|
||||
Replaceall(imcall, "$imfuncname", intermediary_function_name);
|
||||
}
|
||||
|
@ -3869,6 +3876,10 @@ public:
|
|||
/* Emit the actual upcall through */
|
||||
UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name);
|
||||
String *methid = Getattr(udata, "class_methodidx");
|
||||
Setattr(n, "upcalldata", udata);
|
||||
/*
|
||||
Printf(stdout, "setting upcalldata, nodeType: %s %s::%s %p\n", nodeType(n), classname, Getattr(n, "name"), n);
|
||||
*/
|
||||
|
||||
Printf(director_callback_typedefs, " typedef %s (SWIGSTDCALL* SWIG_Callback%s_t)(", c_ret_type, methid);
|
||||
Printf(director_callback_typedefs, "%s);\n", callback_typedef_parms);
|
||||
|
|
|
@ -1806,17 +1806,25 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_
|
|||
classname = Getattr(n, "name");
|
||||
for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) {
|
||||
/* we only need to check the virtual members */
|
||||
if (!checkAttribute(ni, "storage", "virtual"))
|
||||
continue;
|
||||
nodeType = Getattr(ni, "nodeType");
|
||||
int is_using = (Cmp(nodeType, "using") == 0);
|
||||
Node *nn = is_using ? firstChild(ni) : ni; /* assume there is only one child node for "using" nodes */
|
||||
if (is_using) {
|
||||
if (nn)
|
||||
nodeType = Getattr(nn, "nodeType");
|
||||
else
|
||||
continue; // A private "using" node
|
||||
}
|
||||
if (!checkAttribute(nn, "storage", "virtual"))
|
||||
continue;
|
||||
/* we need to add methods(cdecl) and destructor (to check for throw decl) */
|
||||
int is_destructor = (Cmp(nodeType, "destructor") == 0);
|
||||
if ((Cmp(nodeType, "cdecl") == 0) || is_destructor) {
|
||||
decl = Getattr(ni, "decl");
|
||||
decl = Getattr(nn, "decl");
|
||||
/* extra check for function type and proper access */
|
||||
if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(ni)) || need_nonpublic_member(ni))) {
|
||||
String *name = Getattr(ni, "name");
|
||||
Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(ni);
|
||||
if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(nn)) || need_nonpublic_member(nn))) {
|
||||
String *name = Getattr(nn, "name");
|
||||
Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(nn);
|
||||
/* Make sure that the new method overwrites the existing: */
|
||||
int len = Len(vm);
|
||||
const int DO_NOT_REPLACE = -1;
|
||||
|
@ -1834,7 +1842,7 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_
|
|||
String *fqdname = NewStringf("%s::%s", classname, name);
|
||||
Hash *item = NewHash();
|
||||
Setattr(item, "fqdname", fqdname);
|
||||
Node *m = Copy(ni);
|
||||
Node *m = Copy(nn);
|
||||
|
||||
/* Store the complete return type - needed for non-simple return types (pointers, references etc.) */
|
||||
SwigType *ty = NewString(Getattr(m, "type"));
|
||||
|
@ -1854,6 +1862,7 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_
|
|||
Append(vm, item);
|
||||
else
|
||||
Setitem(vm, replace, item);
|
||||
Setattr(nn, "directorNode", m);
|
||||
|
||||
Delete(mname);
|
||||
}
|
||||
|
@ -2806,7 +2815,7 @@ int Language::validIdentifier(String *s) {
|
|||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
int Language::usingDeclaration(Node *n) {
|
||||
if ((cplus_mode == PUBLIC)) {
|
||||
if ((cplus_mode == PUBLIC) || (!is_public(n) && dirprot_mode())) {
|
||||
Node *np = Copy(n);
|
||||
Node *c;
|
||||
for (c = firstChild(np); c; c = nextSibling(c)) {
|
||||
|
|
|
@ -999,6 +999,7 @@ class TypePass:private Dispatcher {
|
|||
}
|
||||
Node *nn = copyNode(c);
|
||||
Delattr(nn, "access"); // access might be different from the method in the base class
|
||||
Setattr(nn, "access", Getattr(n, "access"));
|
||||
if (!Getattr(nn, "sym:name"))
|
||||
Setattr(nn, "sym:name", symname);
|
||||
|
||||
|
|
|
@ -1000,7 +1000,7 @@ int Swig_need_redefined_warn(Node *a, Node *b, int InClass) {
|
|||
* This is basically any protected members when the allprotected mode is set.
|
||||
* Otherwise we take just the protected virtual methods and non-static methods
|
||||
* (potentially virtual methods) as well as constructors/destructors.
|
||||
*
|
||||
* Also any "using" statements in a class may potentially be virtual.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
int Swig_need_protected(Node *n) {
|
||||
|
@ -1017,6 +1017,8 @@ int Swig_need_protected(Node *n) {
|
|||
}
|
||||
} else if (Equal(nodetype, "constructor") || Equal(nodetype, "destructor")) {
|
||||
return 1;
|
||||
} else if (Equal(nodetype, "using") && !Getattr(n, "namespace")) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue