mirror of https://github.com/swig/swig
Using declarations in inheritance hierarchy improvements.
- Improved documentation for using declarations. - Issue new warning WARN_LANG_USING_NAME_DIFFERENT when there is a conflict in the target language name to be used when introducing a method via a using declaration. Previously the method was silently ignored. Issue #1840. Issue #655.
This commit is contained in:
parent
e36e898c0a
commit
79a1bbee8b
|
@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.1.0 (in progress)
|
||||
===========================
|
||||
|
||||
2022-02-26: wsfulton
|
||||
#655 #1840 Add new warning WARN_LANG_USING_NAME_DIFFERENT to warn when a
|
||||
method introduced by a using declaration in a derived class cannot
|
||||
be used due to a conflict in names.
|
||||
|
||||
2022-02-24: olly
|
||||
#1465 An invalid preprocessor expression is reported as a pair of
|
||||
warnings with the second giving a more detailed message from the
|
||||
|
|
|
@ -1125,7 +1125,7 @@ customization features.
|
|||
<p>
|
||||
SWIG wraps class members that are public following the C++
|
||||
conventions, i.e., by explicit public declaration or by the use of
|
||||
the <tt>using</tt> directive. In general, anything specified in a
|
||||
<tt>using</tt> declarations. In general, anything specified in a
|
||||
private or protected section will be ignored, although the internal
|
||||
code generator sometimes looks at the contents of the private and
|
||||
protected sections so that it can properly generate code for default
|
||||
|
@ -2083,7 +2083,6 @@ or for statically typed languages like Java:
|
|||
<pre>
|
||||
example.i:4: Warning 516: Overloaded method foo(long) ignored,
|
||||
example.i:3: Warning 516: using foo(int) instead.
|
||||
at example.i:3 used.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
@ -2330,8 +2329,8 @@ also apply to <tt>%ignore</tt>. For example:
|
|||
<div class="code">
|
||||
<pre>
|
||||
%ignore foo(double); // Ignore all foo(double)
|
||||
%ignore Spam::foo; // Ignore foo in class Spam
|
||||
%ignore Spam::foo(double); // Ignore foo(double) in class Spam
|
||||
%ignore Spam::foo; // Ignore foo in class Spam (and foo in any derived classes)
|
||||
%ignore Spam::foo(double); // Ignore foo(double) in class Spam (and foo in any derived classes)
|
||||
%ignore *::foo(double); // Ignore foo(double) in all classes
|
||||
</pre>
|
||||
</div>
|
||||
|
@ -2386,6 +2385,53 @@ global scope (e.g., a renaming of <tt>Spam::foo</tt> takes precedence
|
|||
over a renaming of <tt>foo(int)</tt>).</p>
|
||||
</li>
|
||||
|
||||
<li><p>
|
||||
Renaming a class member, using an unparameterized but qualified name, such as <tt>Spam::foo</tt>, also applies to members in all derived classes
|
||||
that have members with the same name.
|
||||
This can be used to simply rename a method, across an entire class hierarchy for all overloaded and non-overloaded methods.
|
||||
This also applies to methods introduced via <tt>using</tt> declarations, see
|
||||
<a href="#SWIGPlus_nn35">Using declarations and inheritance</a>.
|
||||
For example:
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%rename(foo_new) Spam::foo;
|
||||
|
||||
class Spam {
|
||||
public:
|
||||
virtual void foo(int); // Renamed to foo_new
|
||||
};
|
||||
|
||||
class Bar : public Spam {
|
||||
public:
|
||||
virtual void foo(int); // Renamed to foo_new
|
||||
void foo(bool, short, int); // Renamed to foo_new
|
||||
};
|
||||
|
||||
class Grok : public Bar {
|
||||
public:
|
||||
virtual void foo(int); // Renamed to foo_new
|
||||
void foo(bool, int); // Renamed to foo_new
|
||||
void foo(const char *); // Renamed to foo_new
|
||||
void foo(Bar *); // Renamed to foo_new
|
||||
};
|
||||
|
||||
class Spok : public Grok {
|
||||
public:
|
||||
void foo(); // Renamed to foo_new
|
||||
};
|
||||
|
||||
class Knock : public Spok {
|
||||
public:
|
||||
using Grok::foo; // Introduced methods renamed to foo_new
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</p>
|
||||
</li>
|
||||
|
||||
|
||||
<li><p>
|
||||
The order in which <tt>%rename</tt> directives are defined does not matter
|
||||
as long as they appear before the declarations to be renamed. Thus, there is no difference
|
||||
|
@ -4073,23 +4119,23 @@ math::Complex c;
|
|||
<p>
|
||||
At this level, namespaces are relatively easy to manage. However, things start to get
|
||||
very ugly when you throw in the other ways a namespace can be used. For example,
|
||||
selective symbols can be exported from a namespace with <tt>using</tt>.
|
||||
selective symbols can be exported from a namespace with a <tt>using</tt> declaration:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
using math::Complex;
|
||||
using math::Complex; // Using declaration
|
||||
double magnitude(Complex *c); // Namespace prefix stripped
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Similarly, the contents of an entire namespace can be made available like this:
|
||||
Similarly, the contents of an entire namespace can be made available via a <tt>using</tt> directive:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
using namespace math;
|
||||
using namespace math; // Using directive
|
||||
double x = sin(1.0);
|
||||
double magnitude(Complex *c);
|
||||
</pre>
|
||||
|
@ -4246,9 +4292,11 @@ Similarly, <tt>%ignore</tt> can be used to ignore declarations.
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<tt>using</tt> declarations do not have any effect on the generated wrapper
|
||||
code. They are ignored by SWIG language modules and they do not result in any
|
||||
code. However, these declarations <em>are</em> used by the internal type
|
||||
C++ <tt>using</tt> directives and <tt>using</tt> declarations
|
||||
do not add any code to the generated wrapper code.
|
||||
However, there is an exception in one context, see <a href="#SWIGPlus_nn35">Using declarations and inheritance</a>
|
||||
for introducing members of a base class into a derived class definition.
|
||||
C++ <tt>using</tt> declarations and directives <em>are</em> used by the internal type
|
||||
system to track type-names. Therefore, if you have code like this:
|
||||
</p>
|
||||
|
||||
|
@ -5172,7 +5220,7 @@ exit # 'a' is released, SWIG unref 'a' called in the destructor wra
|
|||
|
||||
|
||||
<p>
|
||||
<tt>using</tt> declarations are sometimes used to adjust access to members of
|
||||
C++ <tt>using</tt> declarations are sometimes used to introduce members of
|
||||
base classes. For example:
|
||||
</p>
|
||||
|
||||
|
@ -5180,7 +5228,7 @@ base classes. For example:
|
|||
<pre>
|
||||
class Foo {
|
||||
public:
|
||||
int blah(int x);
|
||||
int blah(int x);
|
||||
};
|
||||
|
||||
class Bar {
|
||||
|
@ -5228,7 +5276,8 @@ you wrap this code in Python, the module works just like you would expect:
|
|||
</div>
|
||||
|
||||
<p>
|
||||
<tt>using</tt> declarations can also be used to change access when applicable. For example:
|
||||
C++ <tt>using</tt> declarations can also be used to change access when applicable.
|
||||
For example, protected methods in a base class can be made public in a derived class:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
|
@ -5261,15 +5310,15 @@ ignored in a base class, it will also be ignored by a <tt>using</tt> declaration
|
|||
|
||||
<p>
|
||||
Because a <tt>using</tt> declaration does not provide fine-grained
|
||||
control over the declarations that get imported, it may be difficult
|
||||
control over the declarations that get imported, because a single <tt>using</tt> declaration
|
||||
may introduce multiple methods, it may be difficult
|
||||
to manage such declarations in applications that make heavy use of
|
||||
SWIG customization features. If you can't get <tt>using</tt> to work
|
||||
correctly, you can always change the interface to the following:
|
||||
correctly, you can always modify the C++ code to handle SWIG differently such as:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
|
||||
class FooBar : public Foo, public Bar {
|
||||
public:
|
||||
#ifndef SWIG
|
||||
|
@ -5285,13 +5334,36 @@ public:
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
If the C++ code being wrapped cannot be changed, make judicious usage of <tt>%extend</tt> and <tt>%rename</tt>
|
||||
to ignore and unignore declarations. The example below is effectively the same as above:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%extend FooBar {
|
||||
int blah(int x) { return $self->Foo::blah(x); }
|
||||
double blah(double x) { return $self->Bar::blah(x); }
|
||||
}
|
||||
%ignore FooBar::blah; // ignore all FooBar::blah below
|
||||
%rename("") FooBar::blah(const char *x); // parameterized unignore
|
||||
|
||||
class FooBar : public Foo, public Bar {
|
||||
public:
|
||||
using Foo::blah;
|
||||
using Bar::blah;
|
||||
char *blah(const char *x);
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<b>Notes:</b>
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><p>If a derived class redefines a method defined in a base class, then a <tt>using</tt> declaration
|
||||
won't cause a conflict. For example:</p>
|
||||
<li><p>If a derived class introduces a method defined in a base class via a <tt>using</tt> declaration,
|
||||
there won't be a conflict due to incorrect additional methods. For example:</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
|
@ -5303,14 +5375,14 @@ public:
|
|||
|
||||
class Bar : public Foo {
|
||||
public:
|
||||
using Foo::blah; // Only imports blah(double);
|
||||
using Foo::blah; // Only introduces blah(double);
|
||||
int blah(int);
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<li><p>Resolving ambiguity in overloading may prevent declarations from being
|
||||
imported by <tt>using</tt>. For example:
|
||||
<li><p>Renaming methods may prevent methods from being
|
||||
introduced into the derived class via <tt>using</tt> declarations. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
|
@ -5324,11 +5396,38 @@ public:
|
|||
|
||||
class Bar : public Foo {
|
||||
public:
|
||||
using Foo::blah; // Only imports blah(int)
|
||||
using Foo::blah; // Only introduces blah(int)
|
||||
double blah(double x);
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The problem here is <tt>Foo::blah</tt> is renamed to <tt>blah_long</tt> in the target language, but
|
||||
the <tt>using</tt> declaration in Bar is not renamed in the target language and thinks all introduced methods should simply
|
||||
be called <tt>blah</tt>.
|
||||
It is not clear what target language names should be used in Bar and so the conflicting names are effectively ignored
|
||||
as they are not introduced into the derived class for the target language wrappers.
|
||||
In such situations SWIG will emit a warning:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
example.i:15: Warning 526: Using declaration Foo::blah, with name 'blah', is not actually using
|
||||
example.i:10: Warning 526: the method from Foo::blah(long), with name 'blah_long', as the names are different.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<b>Compatibility Note:</b>
|
||||
This warning message was introduced in SWIG-4.1.0.
|
||||
Prior versions also effectively ignored the using declaration for the same reasons, but were silent about it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If methods really need different names, please use of combinations of <tt>%rename</tt>, <tt>%ignore</tt> and <tt>%extend</tt> to achieve the desired outcome.
|
||||
</p>
|
||||
|
||||
</ul>
|
||||
|
||||
<H2><a name="SWIGPlus_nested_classes">6.27 Nested classes</a></H2>
|
||||
|
|
|
@ -537,6 +537,7 @@ example.i(4) : Syntax error in input(1).
|
|||
<li>523. Use of an illegal destructor name '<em>name</em>' in %extend is deprecated, the destructor name should be '<em>name</em>'.
|
||||
<li>524. Experimental target language. Target language <em>language</em> specified by <em>lang</em> is an experimental language. Please read about SWIG experimental languages, <em>htmllink</em>.
|
||||
<li>525. Destructor <em>declaration</em> is final, <em>name</em> cannot be a director class.
|
||||
<li>526. Using declaration <em>declaration</em>, with name '<em>name</em>', is not actually using the method from <em>declaration</em>, with name '<em>name</em>', as the names are different.
|
||||
</ul>
|
||||
|
||||
<H3><a name="Warnings_doxygen">19.9.6 Doxygen comments (560-599)</a></H3>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
cpp_using_rename.i:18: Warning 526: Using declaration Base::use_me, with name 'use_me', is not actually using
|
||||
cpp_using_rename.i:10: Warning 526: the method from Base::use_me(int), with name 'UseMe', as the names are different.
|
||||
cpp_using_rename.i:19: Warning 526: Using declaration Base::use_me_too, with name 'UseMeToo', is not actually using
|
||||
cpp_using_rename.i:11: Warning 526: the method from Base::use_me_too(double) const, with name 'use_me_too', as the names are different.
|
||||
cpp_using_rename.i:19: Warning 526: Using declaration Base::use_me_too, with name 'UseMeToo', is not actually using
|
||||
cpp_using_rename.i:12: Warning 526: the method from Base::use_me_too(bool) const, with name 'use_me_too', as the names are different.
|
||||
cpp_using_rename.i:20: Warning 315: Nothing known about 'Base::does_not_exist'.
|
|
@ -12,3 +12,13 @@ bb = BB()
|
|||
swig_assert_equal(bb.greater(int(1)), 0)
|
||||
swig_assert_equal(bb.greater(float(1)), 1)
|
||||
swig_assert_equal(bb.great(True), 2)
|
||||
|
||||
cc = CC()
|
||||
swig_assert_equal(cc.greater(int(10)), 0)
|
||||
swig_assert_equal(cc.greater(float(10)), 1)
|
||||
swig_assert_equal(cc.greater(True), 20)
|
||||
|
||||
dd = DD()
|
||||
swig_assert_equal(dd.greater(int(10)), 0)
|
||||
swig_assert_equal(dd.greater(float(10)), 1)
|
||||
swig_assert_equal(dd.greaterstill(True), 30)
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
%module using_member
|
||||
|
||||
/* using declaration tests, including renaming */
|
||||
%warnfilter(SWIGWARN_LANG_USING_NAME_DIFFERENT) one::twotwo::threetwo::BB::great;
|
||||
|
||||
%rename(greater) one::two::three::interface1::AA::great(int);
|
||||
%rename(greater) one::two::three::interface1::AA::great(float);
|
||||
%rename(greater) one::CC::great;
|
||||
%rename(greater) one::DD::great;
|
||||
%rename(greaterstill) one::DD::great(bool);
|
||||
|
||||
%inline %{
|
||||
namespace interface1
|
||||
|
@ -46,5 +52,19 @@ namespace one {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
class CC : public two::three::AA
|
||||
{
|
||||
public:
|
||||
using two::three::AA::great;
|
||||
int great(bool) {return 20;}
|
||||
};
|
||||
|
||||
class DD : public two::three::AA
|
||||
{
|
||||
public:
|
||||
using two::three::AA::great;
|
||||
int great(bool) {return 30;}
|
||||
};
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -213,6 +213,7 @@
|
|||
#define WARN_LANG_EXTEND_DESTRUCTOR 523
|
||||
#define WARN_LANG_EXPERIMENTAL 524
|
||||
#define WARN_LANG_DIRECTOR_FINAL 525
|
||||
#define WARN_LANG_USING_NAME_DIFFERENT 526
|
||||
|
||||
/* -- Doxygen comments -- */
|
||||
|
||||
|
|
|
@ -1047,13 +1047,6 @@ class TypePass:private Dispatcher {
|
|||
|| (Getattr(c, "feature:extend") && !Getattr(c, "code"))
|
||||
|| GetFlag(c, "feature:ignore"))) {
|
||||
|
||||
/* Don't generate a method if the method is overridden in this class,
|
||||
* for example don't generate another m(bool) should there be a Base::m(bool) :
|
||||
* struct Derived : Base {
|
||||
* void m(bool);
|
||||
* using Base::m;
|
||||
* };
|
||||
*/
|
||||
String *csymname = Getattr(c, "sym:name");
|
||||
if (!csymname || (Strcmp(csymname, symname) == 0)) {
|
||||
{
|
||||
|
@ -1069,6 +1062,13 @@ class TypePass:private Dispatcher {
|
|||
over = Getattr(over, "sym:nextSibling");
|
||||
}
|
||||
if (match) {
|
||||
/* Don't generate a method if the method is overridden in this class,
|
||||
* for example don't generate another m(bool) should there be a Base::m(bool) :
|
||||
* struct Derived : Base {
|
||||
* void m(bool);
|
||||
* using Base::m;
|
||||
* };
|
||||
*/
|
||||
c = Getattr(c, "csym:nextSibling");
|
||||
continue;
|
||||
}
|
||||
|
@ -1117,6 +1117,9 @@ class TypePass:private Dispatcher {
|
|||
} else {
|
||||
Delete(nn);
|
||||
}
|
||||
} else {
|
||||
Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(n), Getline(n), "Using declaration %s, with name '%s', is not actually using\n", SwigType_namestr(Getattr(n, "uname")), symname);
|
||||
Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(c), Getline(c), "the method from %s, with name '%s', as the names are different.\n", Swig_name_decl(c), csymname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue