Fix using statements for overloaded methods

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10176 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2007-11-30 22:34:50 +00:00
parent 84dc1cc4f6
commit 575efcdd53
9 changed files with 317 additions and 52 deletions

View File

@ -1,3 +1,13 @@
Version 1.3.34 (in progress)
============================
11/30/2007: wsfulton
Fix using statements using a base class method where the methods were overloaded.
Depending on the order of the using statements and method declarations, these
were previously generating uncompileable wrappers, eg:
struct Derived : Base {
virtual void funk();
using Base::funk;
};

View File

@ -2,10 +2,33 @@ from using_composition import *
f = FooBar()
if f.blah(3) != 3:
raise RuntimeError,"blah(int)"
raise RuntimeError,"FooBar::blah(int)"
if f.blah(3.5) != 3.5:
raise RuntimeError,"blah(double)"
raise RuntimeError,"FooBar::blah(double)"
if f.blah("hello") != "hello":
raise RuntimeError,"blah(char *)"
raise RuntimeError,"FooBar::blah(char *)"
f = FooBar2()
if f.blah(3) != 3:
raise RuntimeError,"FooBar2::blah(int)"
if f.blah(3.5) != 3.5:
raise RuntimeError,"FooBar2::blah(double)"
if f.blah("hello") != "hello":
raise RuntimeError,"FooBar2::blah(char *)"
f = FooBar3()
if f.blah(3) != 3:
raise RuntimeError,"FooBar3::blah(int)"
if f.blah(3.5) != 3.5:
raise RuntimeError,"FooBar3::blah(double)"
if f.blah("hello") != "hello":
raise RuntimeError,"FooBar3::blah(char *)"

View File

@ -2,7 +2,48 @@ from using_inherit import *
b = Bar()
if b.test(3) != 3:
raise RuntimeError,"test(int)"
raise RuntimeError,"Bar::test(int)"
if b.test(3.5) != 3.5:
raise RuntimeError, "test(double)"
raise RuntimeError, "Bar::test(double)"
b = Bar2()
if b.test(3) != 6:
raise RuntimeError,"Bar2::test(int)"
if b.test(3.5) != 7.0:
raise RuntimeError, "Bar2::test(double)"
b = Bar3()
if b.test(3) != 6:
raise RuntimeError,"Bar3::test(int)"
if b.test(3.5) != 7.0:
raise RuntimeError, "Bar3::test(double)"
b = Bar4()
if b.test(3) != 6:
raise RuntimeError,"Bar4::test(int)"
if b.test(3.5) != 7.0:
raise RuntimeError, "Bar4::test(double)"
b = Fred1()
if b.test(3) != 3:
raise RuntimeError,"Fred1::test(int)"
if b.test(3.5) != 7.0:
raise RuntimeError, "Fred1::test(double)"
b = Fred2()
if b.test(3) != 3:
raise RuntimeError,"Fred2::test(int)"
if b.test(3.5) != 7.0:
raise RuntimeError, "Fred2::test(double)"

View File

@ -15,14 +15,42 @@ include Using_composition
f = FooBar.new
if f.blah(3) != 3
raise RuntimeError,"blah(int)"
raise RuntimeError,"FooBar::blah(int)"
end
if f.blah(3.5) != 3.5
raise RuntimeError,"blah(double)"
raise RuntimeError,"FooBar::blah(double)"
end
if f.blah("hello") != "hello"
raise RuntimeError,"blah(char *)"
raise RuntimeError,"FooBar::blah(char *)"
end
f = FooBar2.new
if f.blah(3) != 3
raise RuntimeError,"FooBar2::blah(int)"
end
if f.blah(3.5) != 3.5
raise RuntimeError,"FooBar2::blah(double)"
end
if f.blah("hello") != "hello"
raise RuntimeError,"FooBar2::blah(char *)"
end
f = FooBar3.new
if f.blah(3) != 3
raise RuntimeError,"FooBar3::blah(int)"
end
if f.blah(3.5) != 3.5
raise RuntimeError,"FooBar3::blah(double)"
end
if f.blah("hello") != "hello"
raise RuntimeError,"FooBar3::blah(char *)"
end

View File

@ -15,10 +15,60 @@ include Using_inherit
b = Bar.new
if b.test(3) != 3
raise RuntimeError,"test(int)"
raise RuntimeError,"Bar::test(int)"
end
if b.test(3.5) != 3.5
raise RuntimeError, "test(double)"
raise RuntimeError, "Bar::test(double)"
end
b = Bar2.new
if b.test(3) != 6
raise RuntimeError,"Bar2::test(int)"
end
if b.test(3.5) != 7.0
raise RuntimeError, "Bar2::test(double)"
end
b = Bar3.new
if b.test(3) != 6
raise RuntimeError,"Bar3::test(int)"
end
if b.test(3.5) != 7.0
raise RuntimeError, "Bar3::test(double)"
end
b = Bar4.new
if b.test(3) != 6
raise RuntimeError,"Bar4::test(int)"
end
if b.test(3.5) != 7.0
raise RuntimeError, "Bar4::test(double)"
end
b = Fred1.new
if b.test(3) != 3
raise RuntimeError,"Fred1::test(int)"
end
if b.test(3.5) != 7.0
raise RuntimeError, "Fred1::test(double)"
end
b = Fred2.new
if b.test(3) != 3
raise RuntimeError,"Fred2::test(int)"
end
if b.test(3.5) != 7.0
raise RuntimeError, "Fred2::test(double)"
end

View File

@ -26,4 +26,18 @@ public:
char *blah(char *x) { return x; }
};
class FooBar2 : public Foo, public Bar {
public:
char *blah(char *x) { return x; }
using Foo::blah;
using Bar::blah;
};
class FooBar3 : public Foo, public Bar {
public:
using Foo::blah;
char *blah(char *x) { return x; }
using Bar::blah;
};
%}

View File

@ -17,5 +17,38 @@ public:
using Foo::test;
};
class Bar2 : public Foo {
public:
int test(int x) { return x*2; }
double test(double x) { return x*2; };
using Foo::test;
};
class Bar3 : public Foo {
public:
int test(int x) { return x*2; }
double test(double x) { return x*2; };
using Foo::test;
};
class Bar4 : public Foo {
public:
int test(int x) { return x*2; }
using Foo::test;
double test(double x) { return x*2; };
};
class Fred1 : public Foo {
public:
using Foo::test;
double test(double x) { return x*2; };
};
class Fred2 : public Foo {
public:
double test(double x) { return x*2; };
using Foo::test;
};
%}

View File

@ -564,7 +564,6 @@ class TypePass:private Dispatcher {
* ------------------------------------------------------------ */
virtual int cDeclaration(Node *n) {
if (NoExcept) {
Delattr(n, "throws");
}
@ -777,6 +776,35 @@ class TypePass:private Dispatcher {
return enumDeclaration(n);
}
#ifdef DEBUG_OVERLOADED
static void show_overloaded(Node *n) {
Node *c = Getattr(n, "sym:overloaded");
Node *checkoverloaded = c;
Printf(stdout, "-------------------- overloaded start %s sym:overloaded():%p -------------------------------\n", Getattr(n, "name"), c);
while (c) {
if (Getattr(c, "error")) {
c = Getattr(c, "sym:nextSibling");
continue;
}
if (Getattr(c, "sym:overloaded") != checkoverloaded) {
Printf(stdout, "sym:overloaded error c:%p checkoverloaded:%p\n", c, checkoverloaded);
Swig_print_node(c);
exit (1);
}
String *decl = Strcmp(nodeType(c), "using") == 0 ? NewString("------") : Getattr(c, "decl");
Printf(stdout, " show_overloaded %s::%s(%s) [%s] nodeType:%s\n", parentNode(c) ? Getattr(parentNode(c), "name") : "NOPARENT", Getattr(c, "name"), decl, Getattr(c, "sym:overname"), nodeType(c));
if (!Getattr(c, "sym:overloaded")) {
Printf(stdout, "sym:overloaded error.....%p\n", c);
Swig_print_node(c);
exit (1);
}
c = Getattr(c, "sym:nextSibling");
}
Printf(stdout, "-------------------- overloaded end %s -------------------------------\n", Getattr(n, "name"));
}
#endif
/* ------------------------------------------------------------
* usingDeclaration()
* ------------------------------------------------------------ */
@ -816,10 +844,8 @@ class TypePass:private Dispatcher {
Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname")));
}
} else {
/* Only a single symbol is being used. There are only a few symbols that
we actually care about. These are typedef, class declarations, and enum */
String *ntype = nodeType(ns);
if (Strcmp(ntype, "cdecl") == 0) {
if (checkAttribute(ns, "storage", "typedef")) {
@ -841,9 +867,15 @@ 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)) {
/* Check for existence in overload list already */
{
String *decl = Getattr(c, "decl");
Node *over = Getattr(n, "sym:overloaded");
@ -918,6 +950,75 @@ class TypePass:private Dispatcher {
}
}
}
/* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the
* list of overloaded methods we have just added in as child nodes to the "using" node.
* The node will still exist, it is just the symbol table linked list of overloaded methods
* which is hacked. */
if (Getattr(n, "sym:overloaded"))
{
#ifdef DEBUG_OVERLOADED
show_overloaded(n);
#endif
int cnt = 0;
Node *debugnode = n;
if (!firstChild(n)) {
// Remove from overloaded list ('using' node does not actually end up adding in any methods)
Node *ps = Getattr(n, "sym:previousSibling");
Node *ns = Getattr(n, "sym:nextSibling");
if (ps) {
Setattr(ps, "sym:nextSibling", ns);
}
if (ns) {
Setattr(ns, "sym:previousSibling", ps);
}
} else {
// The 'using' node results in methods being added in - slot in the these methods here
Node *ps = Getattr(n, "sym:previousSibling");
Node *ns = Getattr(n, "sym:nextSibling");
Node *fc = firstChild(n);
Node *pp = fc;
Node *firstoverloaded = Getattr(n, "sym:overloaded");
if (firstoverloaded == n) {
// This 'using' node we are cutting out was the first node in the overloaded list.
// Change the first node in the list to its first sibling
Delattr(firstoverloaded, "sym:overloaded");
Node *nnn = Getattr(firstoverloaded, "sym:nextSibling");
firstoverloaded = fc;
while (nnn) {
Setattr(nnn, "sym:overloaded", firstoverloaded);
nnn = Getattr(nnn, "sym:nextSibling");
}
}
while (pp) {
Node *ppn = Getattr(pp, "sym:nextSibling");
Setattr(pp, "sym:overloaded", firstoverloaded);
Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++));
if (ppn)
pp = ppn;
else
break;
}
if (ps) {
Setattr(ps, "sym:nextSibling", fc);
Setattr(fc, "sym:previousSibling", ps);
}
if (ns) {
Setattr(ns, "sym:previousSibling", pp);
Setattr(pp, "sym:nextSibling", ns);
}
debugnode = firstoverloaded;
}
Delattr(n, "sym:previousSibling");
Delattr(n, "sym:nextSibling");
Delattr(n, "sym:overloaded");
Delattr(n, "sym:overname");
#ifdef DEBUG_OVERLOADED
show_overloaded(debugnode);
#endif
clean_overloaded(n); // Needed?
}
}
}
} else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) {

View File

@ -46,19 +46,17 @@ int is_member_director(Node *member) {
return is_member_director(Getattr(member, "parentNode"), member);
}
/* Clean overloaded list. Removes templates, ignored, and errors */
void clean_overloaded(Node *n) {
Node *nn = Getattr(n, "sym:overloaded");
Node *first = 0;
int cnt = 0;
while (nn) {
String *ntype = nodeType(nn);
if ((GetFlag(nn, "feature:ignore")) ||
(Getattr(nn, "error")) ||
(Strcmp(ntype, "template") == 0) ||
((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn)) || ((Strcmp(ntype, "using") == 0) && !firstChild(nn))) {
((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn))) {
/* Remove from overloaded list */
Node *ps = Getattr(nn, "sym:previousSibling");
Node *ns = Getattr(nn, "sym:nextSibling");
@ -73,40 +71,6 @@ void clean_overloaded(Node *n) {
Delattr(nn, "sym:overloaded");
nn = ns;
continue;
} else if ((Strcmp(ntype, "using") == 0)) {
/* A possibly dangerous parse tree hack. We're going to
cut the parse tree node out and stick in the resolved
using declarations */
Node *ps = Getattr(nn, "sym:previousSibling");
Node *ns = Getattr(nn, "sym:nextSibling");
Node *un = firstChild(nn);
Node *pn = un;
if (!first) {
first = un;
}
while (pn) {
Node *ppn = Getattr(pn, "sym:nextSibling");
Setattr(pn, "sym:overloaded", first);
Setattr(pn, "sym:overname", NewStringf("%s_%d", Getattr(nn, "sym:overname"), cnt++));
if (ppn)
pn = ppn;
else
break;
}
if (ps) {
Setattr(ps, "sym:nextSibling", un);
Setattr(un, "sym:previousSibling", ps);
}
if (ns) {
Setattr(ns, "sym:previousSibling", pn);
Setattr(pn, "sym:nextSibling", ns);
}
if (!first) {
first = un;
Setattr(nn, "sym:overloaded", first);
}
} else {
if (!first)
first = nn;
@ -115,6 +79,7 @@ void clean_overloaded(Node *n) {
nn = Getattr(nn, "sym:nextSibling");
}
if (!first || (first && !Getattr(first, "sym:nextSibling"))) {
Delattr(n, "sym:overloaded");
if (Getattr(n, "sym:overloaded"))
Delattr(n, "sym:overloaded");
}
}