diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2011-02-01 07:02:50 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2011-02-01 07:02:50 +0000 |
commit | 4a73d986ddc26fd8eab62219090a4bc4bb55a453 (patch) | |
tree | 333e90b86b7fd207b782ea54adfdf425177c37ac | |
parent | 96609f350e9d895f4c8f844b0b7cacfd8ca95feb (diff) | |
download | swig-4a73d986ddc26fd8eab62219090a4bc4bb55a453.tar.gz |
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
-rw-r--r-- | CHANGES.current | 10 | ||||
-rw-r--r-- | Examples/test-suite/csharp/director_alternating_runme.cs | 11 | ||||
-rw-r--r-- | Examples/test-suite/csharp/director_protected_runme.cs | 28 | ||||
-rw-r--r-- | Examples/test-suite/director_protected.i | 13 | ||||
-rw-r--r-- | Examples/test-suite/director_using.i | 15 | ||||
-rw-r--r-- | Examples/test-suite/java/director_protected_runme.java | 32 | ||||
-rw-r--r-- | Examples/test-suite/php/director_protected_runme.php | 21 | ||||
-rw-r--r-- | Examples/test-suite/python/director_protected_runme.py | 43 | ||||
-rw-r--r-- | Source/Modules/csharp.cxx | 27 | ||||
-rw-r--r-- | Source/Modules/lang.cxx | 25 | ||||
-rw-r--r-- | Source/Modules/typepass.cxx | 1 | ||||
-rw-r--r-- | Source/Swig/naming.c | 4 |
12 files changed, 209 insertions, 21 deletions
diff --git a/CHANGES.current b/CHANGES.current index fda995085..216484693 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -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. diff --git a/Examples/test-suite/csharp/director_alternating_runme.cs b/Examples/test-suite/csharp/director_alternating_runme.cs new file mode 100644 index 000000000..19365217a --- /dev/null +++ b/Examples/test-suite/csharp/director_alternating_runme.cs @@ -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"); + } +} + diff --git a/Examples/test-suite/csharp/director_protected_runme.cs b/Examples/test-suite/csharp/director_protected_runme.cs index ee4697b0e..b44c3b7e9 100644 --- a/Examples/test-suite/csharp/director_protected_runme.cs +++ b/Examples/test-suite/csharp/director_protected_runme.cs @@ -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();"; + } +} + } diff --git a/Examples/test-suite/director_protected.i b/Examples/test-suite/director_protected.i index fee45b4a6..0299b238d 100644 --- a/Examples/test-suite/director_protected.i +++ b/Examples/test-suite/director_protected.i @@ -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}; diff --git a/Examples/test-suite/director_using.i b/Examples/test-suite/director_using.i index 9001ffbb9..d86546e86 100644 --- a/Examples/test-suite/director_using.i +++ b/Examples/test-suite/director_using.i @@ -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; + }; +%} diff --git a/Examples/test-suite/java/director_protected_runme.java b/Examples/test-suite/java/director_protected_runme.java index 464b4d4d9..63ac03502 100644 --- a/Examples/test-suite/java/director_protected_runme.java +++ b/Examples/test-suite/java/director_protected_runme.java @@ -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();"; + } +} + diff --git a/Examples/test-suite/php/director_protected_runme.php b/Examples/test-suite/php/director_protected_runme.php index 73bcba1fd..9d47ef658 100644 --- a/Examples/test-suite/php/director_protected_runme.php +++ b/Examples/test-suite/php/director_protected_runme.php @@ -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(); ?> diff --git a/Examples/test-suite/python/director_protected_runme.py b/Examples/test-suite/python/director_protected_runme.py index 9d565a1b4..fd3c868a1 100644 --- a/Examples/test-suite/python/director_protected_runme.py +++ b/Examples/test-suite/python/director_protected_runme.py @@ -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" + + diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx index 6d0896b16..1444dbd87 100644 --- a/Source/Modules/csharp.cxx +++ b/Source/Modules/csharp.cxx @@ -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); diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index 7f96007e3..82af250f7 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -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)) { diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index 8751b1e67..3e2c9ca1e 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -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); diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c index 6beecc130..d4a7adf84 100644 --- a/Source/Swig/naming.c +++ b/Source/Swig/naming.c @@ -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; |