summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam S Fulton <wsf@fultondesigns.co.uk>2022-03-12 12:46:59 +0000
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2022-03-12 23:04:24 +0000
commitb6ece11fc1d4120a1f1ed85d1c18639fe04a34b5 (patch)
tree16cccc18fd8e26bc17cd27797fc456f8862dfe28
parent77853770bdaec814e0e231856c4590f35a8578bb (diff)
downloadswig-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.current18
-rw-r--r--Doc/Manual/Java.html15
-rw-r--r--Examples/test-suite/common.mk1
-rw-r--r--Examples/test-suite/csharp/multiple_inheritance_overload_runme.cs58
-rw-r--r--Examples/test-suite/java/multiple_inheritance_overload_runme.java65
-rw-r--r--Examples/test-suite/multiple_inheritance_abstract.i2
-rw-r--r--Examples/test-suite/multiple_inheritance_interfaces.i2
-rw-r--r--Examples/test-suite/multiple_inheritance_nspace.i2
-rw-r--r--Examples/test-suite/multiple_inheritance_overload.i67
-rw-r--r--Examples/test-suite/multiple_inheritance_shared_ptr.i2
-rw-r--r--Examples/test-suite/nested_inheritance_interface.i2
-rw-r--r--Source/Modules/interface.cxx40
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);
}