Merge branch 'ZackerySpytz-director-classes-final-methods'

* ZackerySpytz-director-classes-final-methods:
  Warning tweaks for destructors that are final in director classes
  Documentation for directors and virtual final methods
  Fixes for final destructors in director classes
  Warning fix for final destructor in directors
  Remove a useless warning filter
  Fix the handling of director classes with final methods
This commit is contained in:
William S Fulton 2019-03-03 15:12:53 +00:00
commit bc0645ce2b
14 changed files with 128 additions and 20 deletions

View file

@ -47,6 +47,9 @@ Version 4.0.0 (in progress)
2019-02-22: tamuratak
#984 Add support for RTypedData introduced in Ruby 1.9.3.
2019-02-22: ZackerySpytz
#1483 Fix compilation failures when a director class has final methods.
2019-02-21: wsfulton
#1240 Suppress Java 9 deprecation warnings on finalize method.

View file

@ -785,7 +785,9 @@ In order to override virtual methods on a C++ class with Go methods the
<tt>NewDirectorClassName</tt> constructor functions receives a
<tt>DirectorInterface</tt> argument. The methods in the <tt>
DirectorInterface</tt> are a subset of the public and protected virtual methods
of the C++ class. If the <tt>DirectorInterface</tt> contains a method with a
of the C++ class.
Virtual methods that have a final specifier are unsurprisingly excluded.
If the <tt>DirectorInterface</tt> contains a method with a
matching signature to a virtual method of the C++ class then the virtual C++
method will be overwritten with the Go method. As Go doesn't support protected
methods all overridden protected virtual C++ methods will be public in Go.

View file

@ -3629,7 +3629,7 @@ The %feature directive can be applied globally, to specific classes, and to spec
// generate directors for all classes that have virtual methods
%feature("director");
// generate directors for all virtual methods in class Foo
// generate directors for the virtual methods in class Foo
%feature("director") Foo;
</pre>
</div>
@ -3647,7 +3647,7 @@ So for example,
</div>
<p>
will generate directors for all virtual methods of class Foo except bar().
will generate directors for the virtual methods of class Foo except bar().
</p>
<p>
@ -3683,7 +3683,8 @@ The director classes store a pointer to their underlying Java proxy classes.
<p>
For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the original C++ class as the director's base class.
By default, a director class extends all virtual methods in the inheritance chain of its base class (see the preceding section for how to modify this behavior).
Thus all virtual method calls, whether they originate in C++ or in Java via proxy classes, eventually end up in at the implementation in the director class.
Virtual methods that have a final specifier are unsurprisingly excluded.
Thus the virtual method calls, whether they originate in C++ or in Java via proxy classes, eventually end up in at the implementation in the director class.
The job of the director methods is to route these method calls to the appropriate place in the inheritance chain.
By "appropriate place" we mean the method that would have been called if the C++ base class and its Java derived classes were seamlessly integrated.
That seamless integration is exactly what the director classes provide, transparently skipping over all the messy JNI glue code that binds the two languages together.

View file

@ -3070,7 +3070,7 @@ globally, to specific classes, and to specific methods, like this:
// generate directors for all classes that have virtual methods
%feature("director");
// generate directors for all virtual methods in class Foo
// generate directors for the virtual methods in class Foo
%feature("director") Foo;
</pre>
</div>
@ -3088,7 +3088,7 @@ directors for specific classes or methods. So for example,
</div>
<p>
will generate directors for all virtual methods of class Foo except
will generate directors for the virtual methods of class Foo except
bar().
</p>
@ -3153,7 +3153,8 @@ For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the
original C++ class as the director's base class. By default, a director
class extends all virtual methods in the inheritance chain of its base
class (see the preceding section for how to modify this behavior).
Thus all virtual method calls, whether they originate in C++ or in
Virtual methods that have a final specifier are unsurprisingly excluded.
Thus the virtual method calls, whether they originate in C++ or in
Perl via proxy classes, eventually end up in at the implementation in
the director class. The job of the director methods is to route these
method calls to the appropriate place in the inheritance chain. By

View file

@ -937,7 +937,7 @@ globally, to specific classes, and to specific methods, like this:
// generate directors for all classes that have virtual methods
%feature("director");
// generate directors for all virtual methods in class Foo
// generate directors for the virtual methods in class Foo
%feature("director") Foo;
</pre>
</div>
@ -955,7 +955,7 @@ directors for specific classes or methods. So for example,
</div>
<p>
will generate directors for all virtual methods of class Foo except
will generate directors for the virtual methods of class Foo except
bar().
</p>
@ -1020,7 +1020,8 @@ For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the
original C++ class as the director's base class. By default, a director
class extends all virtual methods in the inheritance chain of its base
class (see the preceding section for how to modify this behavior).
Thus all virtual method calls, whether they originate in C++ or in
Virtual methods that have a final specifier are unsurprisingly excluded.
Thus the virtual method calls, whether they originate in C++ or in
PHP via proxy classes, eventually end up in at the implementation in the
director class. The job of the director methods is to route these method
calls to the appropriate place in the inheritance chain. By "appropriate

View file

@ -2934,7 +2934,7 @@ globally, to specific classes, and to specific methods, like this:
// generate directors for all classes that have virtual methods
%feature("director");
// generate directors for all virtual methods in class Foo
// generate directors for the virtual methods in class Foo
%feature("director") Foo;
</pre>
</div>
@ -2952,7 +2952,7 @@ directors for specific classes or methods. So for example,
</div>
<p>
will generate directors for all virtual methods of class Foo except
will generate directors for the virtual methods of class Foo except
bar().
</p>
@ -3018,7 +3018,8 @@ For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the
original C++ class as the director's base class. By default, a director
class extends all virtual methods in the inheritance chain of its base
class (see the preceding section for how to modify this behavior).
Thus all virtual method calls, whether they originate in C++ or in
Virtual methods that have a final specifier are unsurprisingly excluded.
Thus the virtual method calls, whether they originate in C++ or in
Python via proxy classes, eventually end up in at the implementation in
the director class. The job of the director methods is to route these
method calls to the appropriate place in the inheritance chain. By

View file

@ -535,6 +535,7 @@ example.i(4) : Syntax error in input(1).
<li>522. Use of an illegal constructor name '<em>name</em>' in %extend is deprecated, the constructor name should be '<em>name</em>'.
<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.
</ul>
<H3><a name="Warnings_doxygen">18.9.6 Doxygen comments (560-599)</a></H3>

View file

@ -572,6 +572,7 @@ CPP11_TEST_CASES += \
cpp11_director_enums \
cpp11_directors \
cpp11_explicit_conversion_operators \
cpp11_final_directors \
cpp11_final_override \
cpp11_function_objects \
cpp11_inheriting_constructors \

View file

@ -0,0 +1,33 @@
%module(directors="1") cpp11_final_directors
%director Derived;
// Check SWIG will not wrap these classes as directors where the destructors are final
%director BaseFinalDestructor;
%director BaseFinalDestructor2;
%warnfilter(SWIGWARN_LANG_DIRECTOR_FINAL) BaseFinalDestructor::~BaseFinalDestructor;
%warnfilter(SWIGWARN_LANG_DIRECTOR_FINAL) BaseFinalDestructor2::~BaseFinalDestructor2;
%inline %{
struct Base {
virtual void basemeth() final {}
virtual ~Base() {}
};
struct Derived : Base {
virtual int derivedmeth() final { return 1; }
virtual int meth() { return 2; }
virtual ~Derived() {}
};
struct BaseFinalDestructor {
virtual void basefinalmeth() final {}
virtual ~BaseFinalDestructor() final {}
};
struct BaseFinalDestructor2 {
virtual void basefinalmeth() {}
virtual ~BaseFinalDestructor2() final {}
};
%}

View file

@ -0,0 +1 @@
cpp_final_destructor.i:7: Warning 525: Destructor BaseFinal::~BaseFinal() is final, BaseFinal cannot be a director class.

View file

@ -0,0 +1,11 @@
import cpp11_final_directors
class Derived2(cpp11_final_directors.Derived):
def meth(self):
return 3
b = Derived2()
if b.meth() != 3:
raise RuntimeError

View file

@ -1552,6 +1552,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
Parm *throws;
String *throwf;
String *nexcept;
String *final;
} dtype;
struct {
const char *type;
@ -1567,6 +1568,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
ParmList *throws;
String *throwf;
String *nexcept;
String *final;
} decl;
Parm *tparms;
struct {
@ -3189,6 +3191,7 @@ c_decl : storage_class type declarator cpp_const initializer c_decl_tail {
Setattr($$,"throws",$4.throws);
Setattr($$,"throw",$4.throwf);
Setattr($$,"noexcept",$4.nexcept);
Setattr($$,"final",$4.final);
if ($5.val && $5.type) {
/* store initializer type as it might be different to the declared type */
SwigType *valuetype = NewSwigType($5.type);
@ -3266,6 +3269,7 @@ c_decl : storage_class type declarator cpp_const initializer c_decl_tail {
Setattr($$,"throws",$4.throws);
Setattr($$,"throw",$4.throwf);
Setattr($$,"noexcept",$4.nexcept);
Setattr($$,"final",$4.final);
if (!$9) {
if (Len(scanner_ccode)) {
String *code = Copy(scanner_ccode);
@ -3330,6 +3334,7 @@ c_decl_tail : SEMI {
Setattr($$,"throws",$3.throws);
Setattr($$,"throw",$3.throwf);
Setattr($$,"noexcept",$3.nexcept);
Setattr($$,"final",$3.final);
if ($4.bitfield) {
Setattr($$,"bitfield", $4.bitfield);
}
@ -3638,6 +3643,7 @@ c_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Setattr($$,"throws",$6.throws);
Setattr($$,"throw",$6.throwf);
Setattr($$,"noexcept",$6.nexcept);
Setattr($$,"final",$6.final);
err = 0;
}
}
@ -4704,6 +4710,7 @@ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Setattr($$,"throws",$6.throws);
Setattr($$,"throw",$6.throwf);
Setattr($$,"noexcept",$6.nexcept);
Setattr($$,"final",$6.final);
if (Len(scanner_ccode)) {
String *code = Copy(scanner_ccode);
Setattr($$,"code",code);
@ -4740,6 +4747,7 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
Setattr($$,"throws",$6.throws);
Setattr($$,"throw",$6.throwf);
Setattr($$,"noexcept",$6.nexcept);
Setattr($$,"final",$6.final);
if ($6.val)
Setattr($$,"value",$6.val);
if ($6.qualifier)
@ -4760,6 +4768,7 @@ cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end {
Setattr($$,"throws",$7.throws);
Setattr($$,"throw",$7.throwf);
Setattr($$,"noexcept",$7.nexcept);
Setattr($$,"final",$7.final);
if ($7.val)
Setattr($$,"value",$7.val);
if (Len(scanner_ccode)) {
@ -4941,6 +4950,7 @@ cpp_end : cpp_const SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
}
| cpp_const EQUAL default_delete SEMI {
Clear(scanner_ccode);
@ -4951,6 +4961,7 @@ cpp_end : cpp_const SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
}
| cpp_const LBRACE {
skip_balanced('{','}');
@ -4961,6 +4972,7 @@ cpp_end : cpp_const SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
}
;
@ -4973,6 +4985,7 @@ cpp_vend : cpp_const SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
}
| cpp_const EQUAL definetype SEMI {
Clear(scanner_ccode);
@ -4982,7 +4995,8 @@ cpp_vend : cpp_const SEMI {
$$.bitfield = 0;
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
}
| cpp_const LBRACE {
skip_balanced('{','}');
@ -4992,7 +5006,8 @@ cpp_vend : cpp_const SEMI {
$$.bitfield = 0;
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
}
;
@ -5210,6 +5225,7 @@ def_args : EQUAL definetype {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
}
| EQUAL definetype LBRACKET expr RBRACKET {
@ -5223,6 +5239,7 @@ def_args : EQUAL definetype {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
} else {
$$.val = NewStringf("%s[%s]",$2.val,$4.val);
}
@ -5236,6 +5253,7 @@ def_args : EQUAL definetype {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
| COLON expr {
$$.val = 0;
@ -5245,6 +5263,7 @@ def_args : EQUAL definetype {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
| empty {
$$.val = 0;
@ -5254,6 +5273,7 @@ def_args : EQUAL definetype {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
;
@ -6293,6 +6313,7 @@ definetype : { /* scanner_check_typedef(); */ } expr {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
scanner_ignore_typedef();
}
| default_delete {
@ -6319,6 +6340,7 @@ deleted_definition : DELETE_KW {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
;
@ -6333,6 +6355,7 @@ explicit_default : DEFAULT {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
;
@ -6525,6 +6548,7 @@ valexpr : exprnum {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
| WCHARCONST {
$$.val = NewString($1);
@ -6538,6 +6562,7 @@ valexpr : exprnum {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
/* grouping */
@ -6892,18 +6917,18 @@ virt_specifier_seq : OVERRIDE {
$$ = 0;
}
| FINAL {
$$ = 0;
$$ = NewString("1");
}
| FINAL OVERRIDE {
$$ = 0;
$$ = NewString("1");
}
| OVERRIDE FINAL {
$$ = 0;
$$ = NewString("1");
}
;
virt_specifier_seq_opt : virt_specifier_seq {
$$ = 0;
$$ = $1;
}
| empty {
$$ = 0;
@ -6914,31 +6939,37 @@ exception_specification : THROW LPAREN parms RPAREN {
$$.throws = $3;
$$.throwf = NewString("1");
$$.nexcept = 0;
$$.final = 0;
}
| NOEXCEPT {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = NewString("true");
$$.final = 0;
}
| virt_specifier_seq {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = $1;
}
| THROW LPAREN parms RPAREN virt_specifier_seq {
$$.throws = $3;
$$.throwf = NewString("1");
$$.nexcept = 0;
$$.final = $5;
}
| NOEXCEPT virt_specifier_seq {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = NewString("true");
$$.final = $2;
}
| NOEXCEPT LPAREN expr RPAREN {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = $3.val;
$$.final = 0;
}
;
@ -6946,6 +6977,7 @@ qualifiers_exception_specification : cv_ref_qualifier {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
$$.qualifier = $1.qualifier;
$$.refqualifier = $1.refqualifier;
}
@ -6968,6 +7000,7 @@ cpp_const : qualifiers_exception_specification {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
$$.qualifier = 0;
$$.refqualifier = 0;
}
@ -6980,6 +7013,7 @@ ctor_end : cpp_const ctor_initializer SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
if ($1.qualifier)
Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
}
@ -6990,6 +7024,7 @@ ctor_end : cpp_const ctor_initializer SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
if ($1.qualifier)
Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
}
@ -7001,6 +7036,7 @@ ctor_end : cpp_const ctor_initializer SEMI {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
| LPAREN parms RPAREN LBRACE {
skip_balanced('{','}');
@ -7010,6 +7046,7 @@ ctor_end : cpp_const ctor_initializer SEMI {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
| EQUAL definetype SEMI {
$$.have_parms = 0;
@ -7017,6 +7054,7 @@ ctor_end : cpp_const ctor_initializer SEMI {
$$.throws = 0;
$$.throwf = 0;
$$.nexcept = 0;
$$.final = 0;
}
| exception_specification EQUAL default_delete SEMI {
$$.have_parms = 0;
@ -7024,6 +7062,7 @@ ctor_end : cpp_const ctor_initializer SEMI {
$$.throws = $1.throws;
$$.throwf = $1.throwf;
$$.nexcept = $1.nexcept;
$$.final = $1.final;
if ($1.qualifier)
Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
}

View file

@ -211,6 +211,7 @@
#define WARN_LANG_EXTEND_CONSTRUCTOR 522
#define WARN_LANG_EXTEND_DESTRUCTOR 523
#define WARN_LANG_EXPERIMENTAL 524
#define WARN_LANG_DIRECTOR_FINAL 525
/* -- Doxygen comments -- */

View file

@ -1894,6 +1894,8 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_
}
if (!checkAttribute(nn, "storage", "virtual"))
continue;
if (GetFlag(nn, "final"))
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) {
@ -2109,7 +2111,7 @@ int Language::classDirectorMethods(Node *n) {
Node *item = Getitem(vtable, i);
String *method = Getattr(item, "methodNode");
String *fqdname = Getattr(item, "fqdname");
if (GetFlag(method, "feature:nodirector"))
if (GetFlag(method, "feature:nodirector") || GetFlag(method, "final"))
continue;
String *wrn = Getattr(method, "feature:warnfilter");
@ -2198,6 +2200,16 @@ int Language::classDirector(Node *n) {
String *using_protected_members_code = NewString("");
for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) {
Node *nodeType = Getattr(ni, "nodeType");
if (Cmp(nodeType, "destructor") == 0 && GetFlag(ni, "final")) {
String *classtype = Getattr(n, "classtype");
SWIG_WARN_NODE_BEGIN(ni);
Swig_warning(WARN_LANG_DIRECTOR_FINAL, input_file, line_number, "Destructor %s is final, %s cannot be a director class.\n", Swig_name_decl(ni), classtype);
SWIG_WARN_NODE_END(ni);
SetFlag(n, "feature:nodirector");
Delete(vtable);
Delete(using_protected_members_code);
return SWIG_OK;
}
bool cdeclaration = (Cmp(nodeType, "cdecl") == 0);
if (cdeclaration && !GetFlag(ni, "feature:ignore")) {
if (isNonVirtualProtectedAccess(ni)) {