mirror of https://github.com/swig/swig
141 lines
4.7 KiB
C
141 lines
4.7 KiB
C
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at https://www.swig.org/legal.html.
|
|
*
|
|
* extend.c
|
|
*
|
|
* Extensions support (%extend)
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "swig.h"
|
|
#include "cparse.h"
|
|
|
|
static Hash *extendhash = 0; /* Hash table of added methods */
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_extend_hash()
|
|
*
|
|
* Access the extend hash
|
|
* ----------------------------------------------------------------------------- */
|
|
Hash *Swig_extend_hash(void) {
|
|
if (!extendhash)
|
|
extendhash = NewHash();
|
|
return extendhash;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_extend_merge()
|
|
*
|
|
* Extension merge. This function is used to handle the %extend directive
|
|
* when it appears before a class definition. To handle this, the %extend
|
|
* actually needs to take precedence. Therefore, we will selectively nuke symbols
|
|
* from the current symbol table, replacing them with the added methods.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_extend_merge(Node *cls, Node *am) {
|
|
Node *n;
|
|
|
|
n = firstChild(am);
|
|
while (n) {
|
|
String *symname;
|
|
if (Strcmp(nodeType(n),"constructor") == 0) {
|
|
symname = Getattr(n,"sym:name");
|
|
if (symname) {
|
|
if (Strcmp(symname,Getattr(n,"name")) == 0) {
|
|
/* If the name and the sym:name of a constructor are the same,
|
|
then it hasn't been renamed. However---the name of the class
|
|
itself might have been renamed so we need to do a consistency
|
|
check here */
|
|
if (Getattr(cls,"sym:name")) {
|
|
Setattr(n,"sym:name", Getattr(cls,"sym:name"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
symname = Getattr(n,"sym:name");
|
|
DohIncref(symname);
|
|
if ((symname) && (!Getattr(n,"error"))) {
|
|
Node *c;
|
|
/* Remove node from its symbol table */
|
|
Swig_symbol_remove(n);
|
|
c = Swig_symbol_add(symname,n);
|
|
if (c != n) {
|
|
/* Conflict with previous definition. Nuke previous definition */
|
|
String *e = NewStringEmpty();
|
|
String *en = NewStringEmpty();
|
|
String *ec = NewStringEmpty();
|
|
Printf(ec, "Redefinition of identifier '%s' by %%extend ignored,", symname);
|
|
Printf(en, "%%extend definition of '%s'.", symname);
|
|
SWIG_WARN_NODE_BEGIN(n);
|
|
Swig_warning(WARN_PARSE_REDEFINED, Getfile(c), Getline(c), "%s\n", ec);
|
|
Swig_warning(WARN_PARSE_REDEFINED, Getfile(n), Getline(n), "%s\n", en);
|
|
SWIG_WARN_NODE_END(n);
|
|
Printf(e, "%s:%d:%s\n%s:%d:%s\n", Getfile(c), Getline(c), ec, Getfile(n),Getline(n),en);
|
|
Setattr(c, "error", e);
|
|
Delete(e);
|
|
Delete(en);
|
|
Delete(ec);
|
|
Swig_symbol_remove(c); /* Remove class definition */
|
|
Swig_symbol_add(symname, n); /* Insert extend definition */
|
|
}
|
|
}
|
|
n = nextSibling(n);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_extend_append_previous()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_extend_append_previous(Node *cls, Node *am) {
|
|
Node *n, *ne;
|
|
Node *pe = 0;
|
|
Node *ae = 0;
|
|
|
|
if (!am) return;
|
|
|
|
n = firstChild(am);
|
|
while (n) {
|
|
ne = nextSibling(n);
|
|
set_nextSibling(n,0);
|
|
/* typemaps and fragments need to be prepended */
|
|
if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) {
|
|
if (!pe) pe = Swig_cparse_new_node("extend");
|
|
appendChild(pe, n);
|
|
} else {
|
|
if (!ae) ae = Swig_cparse_new_node("extend");
|
|
appendChild(ae, n);
|
|
}
|
|
n = ne;
|
|
}
|
|
if (pe) prependChild(cls,pe);
|
|
if (ae) appendChild(cls,ae);
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_extend_unused_check()
|
|
*
|
|
* Check for unused %extend. Special case, don't report unused
|
|
* extensions for templates
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_extend_unused_check(void) {
|
|
Iterator ki;
|
|
|
|
if (!extendhash) return;
|
|
for (ki = First(extendhash); ki.key; ki = Next(ki)) {
|
|
if (!Strchr(ki.key,'<')) {
|
|
SWIG_WARN_NODE_BEGIN(ki.item);
|
|
Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", SwigType_namestr(ki.key));
|
|
SWIG_WARN_NODE_END(ki.item);
|
|
}
|
|
}
|
|
}
|
|
|