diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2022-03-12 12:46:59 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2022-03-12 23:04:24 +0000 |
commit | b6ece11fc1d4120a1f1ed85d1c18639fe04a34b5 (patch) | |
tree | 16cccc18fd8e26bc17cd27797fc456f8862dfe28 | |
parent | 77853770bdaec814e0e231856c4590f35a8578bb (diff) | |
download | swig-b6ece11fc1d4120a1f1ed85d1c18639fe04a34b5.tar.gz |
Fixes for the family of %interface macros for overloaded methods
When C++ methods are not able to be overloaded in a derived class,
such as when they differ by just const, or the target language
parameters types are identical even when the C++ parameter types
are different, SWIG will ignore one of the overloaded methods with
a warning. A %ignore is required to explicitly ignore one of the
overloaded methods to avoid the warning message. Methods added
in the derived classes due to one of the %interface macros are now
similarly ignored/not added to the derived class.
The adding of additional methods into the parse tree is now more
robust and complete resulting in support for %feature and %rename
for the added methods.
Closes #1277
-rw-r--r-- | CHANGES.current | 18 | ||||
-rw-r--r-- | Doc/Manual/Java.html | 15 | ||||
-rw-r--r-- | Examples/test-suite/common.mk | 1 | ||||
-rw-r--r-- | Examples/test-suite/csharp/multiple_inheritance_overload_runme.cs | 58 | ||||
-rw-r--r-- | Examples/test-suite/java/multiple_inheritance_overload_runme.java | 65 | ||||
-rw-r--r-- | Examples/test-suite/multiple_inheritance_abstract.i | 2 | ||||
-rw-r--r-- | Examples/test-suite/multiple_inheritance_interfaces.i | 2 | ||||
-rw-r--r-- | Examples/test-suite/multiple_inheritance_nspace.i | 2 | ||||
-rw-r--r-- | Examples/test-suite/multiple_inheritance_overload.i | 67 | ||||
-rw-r--r-- | Examples/test-suite/multiple_inheritance_shared_ptr.i | 2 | ||||
-rw-r--r-- | Examples/test-suite/nested_inheritance_interface.i | 2 | ||||
-rw-r--r-- | Source/Modules/interface.cxx | 40 |
12 files changed, 259 insertions, 15 deletions
diff --git a/CHANGES.current b/CHANGES.current index aa3939567..336b0152c 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,23 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-03-12: wsfulton + #1277 Fixes for the family of %interface macros, %interface, + %interface_impl and %interface_custom fixes for overloaded methods + in an inheritance chain. + + When C++ methods are not able to be overloaded in a derived class, + such as when they differ by just const, or the target language + parameters types are identical even when the C++ parameter types + are different, SWIG will ignore one of the overloaded methods with + a warning. A %ignore is required to explicitly ignore one of the + overloaded methods to avoid the warning message. Methods added + in the derived classes due to one of the %interface macros are now + similarly ignored/not added to the derived class. + + The methods added to the derived classes can now also be modified + via %feature and %rename. + 2022-03-08: olly #1006 SWIG now copes with an interface filename specified on the command line which contains a closing parenthesis `)`, and more @@ -626,7 +643,6 @@ Version 4.1.0 (in progress) %typemap(csinterfacemodifiers) X "internal interface" - 2020-09-24: geefr [C#] #1868 Fix wchar_t* csvarout typemap for member variable wrappers. diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html index 9b4213ae9..469463831 100644 --- a/Doc/Manual/Java.html +++ b/Doc/Manual/Java.html @@ -3434,9 +3434,11 @@ Consider the following C++ code: namespace Space { struct Base1 { virtual void Method1(); + virtual Base1(); }; struct Base2 { virtual void Method2(); + virtual Base2(); }; struct Derived : Base1, Base2 { }; @@ -3453,7 +3455,7 @@ SWIG generates a warning for the above code: <div class="shell"> <pre> -example.i:10: Warning 813: Warning for Derived, base Base2 ignored. +example.i:12: Warning 813: Warning for Derived, base Base2 ignored. Multiple inheritance is not supported in Java. </pre> </div> @@ -3506,7 +3508,7 @@ public class Base1SwigImpl implements Base1 { </div> <p> -In fact any class deriving from <tt>Base</tt> will now implement the interface instead of +In fact any class using <tt>Base</tt> as an immediate base class will now implement the interface instead of deriving from it (or ignoring the base in the case of multiple base classes). Hence the <tt>Derived</tt> proxy class will now implement both bases: </p> @@ -3536,6 +3538,15 @@ public class Derived implements Base1, Base2 { </div> <p> +The proxy class has methods added to it, from the implemented bases, so that +the underlying C++ implementation can be called. +In the example above, <tt>Method1</tt> and <tt>Method2</tt> have been added from the implemented bases. +If a method is ignored in the base, such as via <tt>%ignore</tt>, then that method +will be excluded from the interface and there will not be an additional method +added to the proxy class implementing that interface. +</p> + +<p> Wherever a class marked as an interface is used, such as the <tt>UseBases</tt> method in the example, the interface name is used as the type in the Java layer: </p> diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index b5ac56049..48e0546c1 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -308,6 +308,7 @@ CPP_TEST_CASES += \ multiple_inheritance_abstract \ multiple_inheritance_interfaces \ multiple_inheritance_nspace \ + multiple_inheritance_overload \ multiple_inheritance_shared_ptr \ name_cxx \ name_warnings \ diff --git a/Examples/test-suite/csharp/multiple_inheritance_overload_runme.cs b/Examples/test-suite/csharp/multiple_inheritance_overload_runme.cs new file mode 100644 index 000000000..4036722a9 --- /dev/null +++ b/Examples/test-suite/csharp/multiple_inheritance_overload_runme.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using multiple_inheritance_overloadNamespace; + +public class multiple_inheritance_overload_runme { + + public static void check(bool fail, String msg) { + if (fail) + throw new Exception(msg); + } + + public static void Main() { + int i = 0; + Base b1 = new Derived(); + check(b1.Method(i) != 0, "b1.Method failed"); + check(b1.MethodForRenaming(i) != 0, "b1.MethodForRenaming failed"); + check(b1.MethodForRenamingConst(i) != 1, "b1.MethodForRenamingConst failed"); + check(b1.MethodWarningSuppressed(i) != 0, "b1.MethodWarningSuppressed failed"); + check(b1.NotVirtualMethod(i) != 0, "b1.NotVirtualMethod failed"); + check(b1.SimilarOverloadedMethod(i) != 0, "b1.NotVirtualMethod failed"); + + Derived d1 = new Derived(); + check(d1.Method(i) != 0, "d1.Method failed"); + check(d1.MethodForRenaming(i) != 0, "d1.MethodForRenaming failed"); + check(d1.MethodForRenamingConst(i) != 1, "d1.MethodForRenamingConst failed"); + check(d1.MethodWarningSuppressed(i) != 0, "d1.MethodWarningSuppressed failed"); + check(d1.NotVirtualMethod(i) != 0, "d1.NotVirtualMethod failed"); + check(d1.SimilarOverloadedMethod(i) != 0, "d1.NotVirtualMethod failed"); + + check(d1.AnotherMethod(i) != 0, "d1.AnotherMethod failed"); + + Base db1 = BaseSwigImpl.inout(d1); + check(db1.Method(i) != 0, "db1.Method failed"); + check(db1.MethodForRenaming(i) != 0, "db1.MethodForRenaming failed"); + check(db1.MethodForRenamingConst(i) != 1, "db1.MethodForRenamingConst failed"); + check(db1.MethodWarningSuppressed(i) != 0, "db1.MethodWarningSuppressed failed"); + check(db1.NotVirtualMethod(i) != 0, "db1.NotVirtualMethod failed"); + check(db1.SimilarOverloadedMethod(i) != 0, "db1.NotVirtualMethod failed"); + + MoreDerived m1 = new MoreDerived(); + check(m1.Method(i) != 0, "m1.Method failed"); + check(m1.MethodForRenaming(i) != 0, "m1.MethodForRenaming failed"); + check(m1.MethodForRenamingConst(i) != 1, "m1.MethodForRenamingConst failed"); + check(m1.MethodWarningSuppressed(i) != 0, "m1.MethodWarningSuppressed failed"); + check(m1.NotVirtualMethod(i) != 0, "m1.NotVirtualMethod failed"); + check(m1.SimilarOverloadedMethod(i) != 0, "m1.NotVirtualMethod failed"); + + check(m1.AnotherMethod(i) != 0, "m1.AnotherMethod failed"); + + Base mb2 = BaseSwigImpl.inout(m1); + check(mb2.Method(i) != 0, "mb2.Method failed"); + check(mb2.MethodForRenaming(i) != 0, "mb2.MethodForRenaming failed"); + check(mb2.MethodForRenamingConst(i) != 1, "mb2.MethodForRenamingConst failed"); + check(mb2.MethodWarningSuppressed(i) != 0, "mb2.MethodWarningSuppressed failed"); + check(mb2.NotVirtualMethod(i) != 0, "mb2.NotVirtualMethod failed"); + check(mb2.SimilarOverloadedMethod(i) != 0, "mb2.NotVirtualMethod failed"); + } +} diff --git a/Examples/test-suite/java/multiple_inheritance_overload_runme.java b/Examples/test-suite/java/multiple_inheritance_overload_runme.java new file mode 100644 index 000000000..d2cc3ed71 --- /dev/null +++ b/Examples/test-suite/java/multiple_inheritance_overload_runme.java @@ -0,0 +1,65 @@ +import multiple_inheritance_overload.*; + +public class multiple_inheritance_overload_runme { + + static { + try { + System.loadLibrary("multiple_inheritance_overload"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void check(boolean fail, String msg) { + if (fail) + throw new RuntimeException(msg); + } + + public static void main(String argv[]) { + int i = 0; + Base b1 = new Derived(); + check(b1.Method(i) != 0, "b1.Method failed"); + check(b1.MethodForRenaming(i) != 0, "b1.MethodForRenaming failed"); + check(b1.MethodForRenamingConst(i) != 1, "b1.MethodForRenamingConst failed"); + check(b1.MethodWarningSuppressed(i) != 0, "b1.MethodWarningSuppressed failed"); + check(b1.NotVirtualMethod(i) != 0, "b1.NotVirtualMethod failed"); + check(b1.SimilarOverloadedMethod(i) != 0, "b1.NotVirtualMethod failed"); + + Derived d1 = new Derived(); + check(d1.Method(i) != 0, "d1.Method failed"); + check(d1.MethodForRenaming(i) != 0, "d1.MethodForRenaming failed"); + check(d1.MethodForRenamingConst(i) != 1, "d1.MethodForRenamingConst failed"); + check(d1.MethodWarningSuppressed(i) != 0, "d1.MethodWarningSuppressed failed"); + check(d1.NotVirtualMethod(i) != 0, "d1.NotVirtualMethod failed"); + check(d1.SimilarOverloadedMethod(i) != 0, "d1.NotVirtualMethod failed"); + + check(d1.AnotherMethod(i) != 0, "d1.AnotherMethod failed"); + + Base db1 = BaseSwigImpl.inout(d1); + check(db1.Method(i) != 0, "db1.Method failed"); + check(db1.MethodForRenaming(i) != 0, "db1.MethodForRenaming failed"); + check(db1.MethodForRenamingConst(i) != 1, "db1.MethodForRenamingConst failed"); + check(db1.MethodWarningSuppressed(i) != 0, "db1.MethodWarningSuppressed failed"); + check(db1.NotVirtualMethod(i) != 0, "db1.NotVirtualMethod failed"); + check(db1.SimilarOverloadedMethod(i) != 0, "db1.NotVirtualMethod failed"); + + MoreDerived m1 = new MoreDerived(); + check(m1.Method(i) != 0, "m1.Method failed"); + check(m1.MethodForRenaming(i) != 0, "m1.MethodForRenaming failed"); + check(m1.MethodForRenamingConst(i) != 1, "m1.MethodForRenamingConst failed"); + check(m1.MethodWarningSuppressed(i) != 0, "m1.MethodWarningSuppressed failed"); + check(m1.NotVirtualMethod(i) != 0, "m1.NotVirtualMethod failed"); + check(m1.SimilarOverloadedMethod(i) != 0, "m1.NotVirtualMethod failed"); + + check(m1.AnotherMethod(i) != 0, "m1.AnotherMethod failed"); + + Base mb2 = BaseSwigImpl.inout(m1); + check(mb2.Method(i) != 0, "mb2.Method failed"); + check(mb2.MethodForRenaming(i) != 0, "mb2.MethodForRenaming failed"); + check(mb2.MethodForRenamingConst(i) != 1, "mb2.MethodForRenamingConst failed"); + check(mb2.MethodWarningSuppressed(i) != 0, "mb2.MethodWarningSuppressed failed"); + check(mb2.NotVirtualMethod(i) != 0, "mb2.NotVirtualMethod failed"); + check(mb2.SimilarOverloadedMethod(i) != 0, "mb2.NotVirtualMethod failed"); + } +} diff --git a/Examples/test-suite/multiple_inheritance_abstract.i b/Examples/test-suite/multiple_inheritance_abstract.i index 9ac16a235..34813a068 100644 --- a/Examples/test-suite/multiple_inheritance_abstract.i +++ b/Examples/test-suite/multiple_inheritance_abstract.i @@ -5,7 +5,7 @@ SWIGWARN_PHP_MULTIPLE_INHERITANCE); /* languages not supporting multiple inheritance */ #if defined(SWIGJAVA) || defined(SWIGCSHARP) -%include "swiginterface.i" +%include <swiginterface.i> %interface_impl(Space::ABase1) %interface_impl(Space::CBase1) %interface_impl(Space::CBase2) diff --git a/Examples/test-suite/multiple_inheritance_interfaces.i b/Examples/test-suite/multiple_inheritance_interfaces.i index 6bb1d50cb..48e24344a 100644 --- a/Examples/test-suite/multiple_inheritance_interfaces.i +++ b/Examples/test-suite/multiple_inheritance_interfaces.i @@ -4,7 +4,7 @@ SWIGWARN_PHP_MULTIPLE_INHERITANCE); /* languages not supporting multiple inheritance */ #if defined(SWIGJAVA) || defined(SWIGCSHARP) -%include "swiginterface.i" +%include <swiginterface.i> %interface_custom("A", "IA", IA) %interface_custom("B", "IB", IB) %interface_custom("%(strip:[I])s", "I%s", IC) // same as %interface_custom("C", "IC", IC) diff --git a/Examples/test-suite/multiple_inheritance_nspace.i b/Examples/test-suite/multiple_inheritance_nspace.i index 002e6d6ee..f82285fcf 100644 --- a/Examples/test-suite/multiple_inheritance_nspace.i +++ b/Examples/test-suite/multiple_inheritance_nspace.i @@ -10,7 +10,7 @@ #endif #if defined(SWIGJAVA) || defined(SWIGCSHARP) -%include "swiginterface.i" +%include <swiginterface.i> %interface(Space::ABase1) %interface(Space::CBase1) %interface(Space::CBase2) diff --git a/Examples/test-suite/multiple_inheritance_overload.i b/Examples/test-suite/multiple_inheritance_overload.i new file mode 100644 index 000000000..77f5a9ad4 --- /dev/null +++ b/Examples/test-suite/multiple_inheritance_overload.i @@ -0,0 +1,67 @@ +%module(ruby_minherit="1") multiple_inheritance_overload + +%warnfilter(SWIGWARN_D_MULTIPLE_INHERITANCE, + SWIGWARN_PHP_MULTIPLE_INHERITANCE); /* languages not supporting multiple inheritance */ + +#if defined(SWIGJAVA) || defined(SWIGCSHARP) +%include <swiginterface.i> +%interface_impl(Space::Base); +%interface_impl(Space::AnotherBase); +#endif + +%ignore AnotherSpace::AnotherBase::AnotherMethod(int i) const; +%ignore Space::Base::Method(int i) const; +%ignore Space::Base::NotVirtualMethod(int i) const; +%ignore Space::Base::SimilarOverloadedMethod(unsigned short i); +%rename(MethodForRenamingConst) Space::Base::MethodForRenaming(int i) const; + +// Different overloaded warning filters needed for scripting languages (eg Python) and for statically typed languages (eg C#). +%warnfilter(509, 516) Space::Base::MethodWarningSuppressed(int i) const; + +%inline %{ +namespace AnotherSpace { +class AnotherBase { +public: + virtual int AnotherMethod(int i) { return 0; } + virtual int AnotherMethod(int i) const { return 1; } + virtual ~AnotherBase() {} +}; +} + +namespace Space { +class Base +{ +public: + virtual int Method(int i) { return 0; } + virtual int Method(int i) const { return 1; } + virtual int MethodForRenaming(int i) { return 0; } + virtual int MethodForRenaming(int i) const { return 1; } + virtual int MethodWarningSuppressed(int i) { return 0; } + virtual int MethodWarningSuppressed(int i) const { return 1; } + int NotVirtualMethod(int i) { return 0; } + int NotVirtualMethod(int i) const { return 1; } + + typedef int Integer; + + // int and unsigned short are wrapped with a Java int and so would be automatically ignored with a warning + virtual int SimilarOverloadedMethod(Integer i) { return 0; } + virtual int SimilarOverloadedMethod(unsigned short i) { return 1; } + virtual ~Base() {} + static Base *inout(Base *p) { return p; } +}; + +class Derived : public Base, public AnotherSpace::AnotherBase +{ +public: + int member_var; +}; +class MoreDerived : public Derived { +}; +} + +namespace OtherSpace { +class OtherDerived : public Space::Base +{ +}; +} +%} diff --git a/Examples/test-suite/multiple_inheritance_shared_ptr.i b/Examples/test-suite/multiple_inheritance_shared_ptr.i index 061db57d9..d68e12d04 100644 --- a/Examples/test-suite/multiple_inheritance_shared_ptr.i +++ b/Examples/test-suite/multiple_inheritance_shared_ptr.i @@ -48,7 +48,7 @@ %shared_ptr(Space::Bottom2) %shared_ptr(Space::Bottom3) -%include "swiginterface.i" +%include <swiginterface.i> SWIG_SHARED_PTR_INTERFACE_TYPEMAPS(, Space::ABase1) SWIG_SHARED_PTR_INTERFACE_TYPEMAPS(, Space::CBase1) SWIG_SHARED_PTR_INTERFACE_TYPEMAPS(, Space::CBase2) diff --git a/Examples/test-suite/nested_inheritance_interface.i b/Examples/test-suite/nested_inheritance_interface.i index f8335c0af..09238eadf 100644 --- a/Examples/test-suite/nested_inheritance_interface.i +++ b/Examples/test-suite/nested_inheritance_interface.i @@ -5,7 +5,7 @@ SWIGWARN_PHP_MULTIPLE_INHERITANCE); /* languages not supporting multiple inheritance or %interface */ #if defined(SWIGJAVA) || defined(SWIGCSHARP) -%include "swiginterface.i" +%include <swiginterface.i> %interface(IA) #endif diff --git a/Source/Modules/interface.cxx b/Source/Modules/interface.cxx index 3398fa428..6d9738592 100644 --- a/Source/Modules/interface.cxx +++ b/Source/Modules/interface.cxx @@ -15,6 +15,7 @@ * ----------------------------------------------------------------------------- */ #include "swigmod.h" +#include "cparse.h" static bool interface_feature_enabled = false; @@ -38,11 +39,19 @@ static List *collect_interface_methods(Node *n) { if (Cmp(nodeType(child), "cdecl") == 0) { if (GetFlag(child, "feature:ignore") || Getattr(child, "interface:owner")) continue; // skip methods propagated to bases - Node *m = Copy(child); - set_nextSibling(m, NIL); - set_previousSibling(m, NIL); - Setattr(m, "interface:owner", cls); - Append(methods, m); + if (!checkAttribute(child, "kind", "function")) + continue; + if (checkAttribute(child, "storage", "static")) + continue; // accept virtual methods, non-virtual methods too... mmm??. Warn that the interface class has something that is not a virtual method? + Node *nn = copyNode(child); + Setattr(nn, "interface:owner", cls); + ParmList *parms = CopyParmList(Getattr(child, "parms")); + Setattr(nn, "parms", parms); + Delete(parms); + ParmList *throw_parm_list = Getattr(child, "throws"); + if (throw_parm_list) + Setattr(nn, "throws", CopyParmList(throw_parm_list)); + Append(methods, nn); } } } @@ -164,8 +173,25 @@ void Swig_interface_propagate_methods(Node *n) { } Delete(this_decl_resolved); if (!identically_overloaded_method) { - // TODO: Fix if the method is overloaded with different arguments / has default args - appendChild(n, mi.item); + // Add method copied from base class to this derived class + Node *cn = mi.item; + Delattr(cn, "sym:overname"); + String *prefix = Getattr(n, "name"); + String *name = Getattr(cn, "name"); + String *decl = Getattr(cn, "decl"); + String *oldname = Getattr(cn, "sym:name"); + + String *symname = Swig_name_make(cn, prefix, name, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + assert(on == cn); + + // Features from the copied base class method are already present, now add in features specific to the added method in the derived class + Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); + Swig_symbol_setscope(oldscope); + appendChild(n, cn); + } } else { Delete(mi.item); } |