/
niceSOFT
/
swig
Обзор
Документация
Войти
/
niceSOFT
/
swig
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Source/Modules/typepass.cxx
1 352 строки
49 KB
William S Fulton
Fix protected/private nested class referenced in generated upcast helper
11 июл 2026, 23:02
11 июл 2026, 23:02
f156c99
Код
Авторство
О чём код?
/* ----------------------------------------------------------------------------- * 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. * * typepass.cxx * * This module builds all of the internal type information by collecting * typedef declarations as well as registering classes, structures, and unions. * This information is needed to correctly handle shadow classes and other * advanced features. This phase of compilation is also used to perform * type-expansion. All types are fully qualified with namespace prefixes * and other information needed for compilation. * ----------------------------------------------------------------------------- */ #include "swigmod.h" #include "cparse.h" struct normal_node { Symtab *symtab; Hash *typescope; List *normallist; normal_node *next; }; static normal_node *patch_list = 0; /* Find the class or template aliased by a name by walking the symbol table sibling chain. */ static Node *symbol_resolve_to_class(Node *n) { while (n && !(Equal(nodeType(n), "class") || Equal(nodeType(n), "template"))) n = Getattr(n, "csym:nextSibling"); return n; } /* Singleton class - all non-static methods in this class are private */ class TypePass : private Dispatcher { Node *inclass; Node *module; int importmode; String *nsname; String *nssymname; Hash *classhash; List *normalize; TypePass() : inclass(0), module(0), importmode(0), nsname(0), nssymname(0), classhash(0), normalize(0) { } /* ----------------------------------------------------------------------------- * normalize_void() * * This function is used to replace arguments of the form (void) with empty * arguments in C++ class constructors and methods only (not global functions). * ----------------------------------------------------------------------------- */ void normalize_void(Node *n) { String *decl = Getattr(n, "decl"); Parm *parms = Getattr(n, "parms"); if (SwigType_isfunction(decl)) { if ((ParmList_len(parms) == 1) && (SwigType_type(Getattr(parms, "type")) == T_VOID)) { String *qualifiers = SwigType_pop_function_qualifiers(decl); String *func = SwigType_pop_function(decl); SwigType_add_function(decl, 0); SwigType_push(decl, qualifiers); Delattr(n, "parms"); Delete(func); Delete(qualifiers); } } } /* Normalize a type. Replaces type with fully qualified version */ void normalize_type(SwigType *ty) { SwigType *qty; if (CPlusPlus) { Replaceall(ty, "struct ", ""); Replaceall(ty, "union ", ""); Replaceall(ty, "class ", ""); } qty = SwigType_typedef_qualified(ty); /* Printf(stdout,"%s --> %s\n", ty, qty); */ Clear(ty); Append(ty, qty); Delete(qty); } /* Normalize a parameter list */ void normalize_parms(ParmList *p) { while (p) { SwigType *ty = Getattr(p, "type"); normalize_type(ty); /* This is a check for a function type */ { SwigType *qty = SwigType_typedef_resolve_all(ty); if (SwigType_isfunction(qty)) { SwigType_add_pointer(ty); } Delete(qty); } String *value = Getattr(p, "value"); if (value) { Node *n = Swig_symbol_clookup(value, 0); if (n) { String *q = Swig_symbol_qualified(n); if (q && Len(q)) { String *vb = Swig_scopename_last(value); Clear(value); Printf(value, "%s::%s", SwigType_namestr(q), vb); Delete(q); } } } if (value && SwigType_istemplate(value)) { String *nv = SwigType_namestr(value); Setattr(p, "value", nv); } p = nextSibling(p); } } void normalize_later(ParmList *p) { while (p) { SwigType *ty = Getattr(p, "type"); Append(normalize, ty); p = nextSibling(p); } } /* Walk through entries in normalize list and patch them up */ void normalize_list() { Hash *currentsym = Swig_symbol_current(); normal_node *nn = patch_list; normal_node *np; while (nn) { Swig_symbol_setscope(nn->symtab); SwigType_set_scope(nn->typescope); Iterator t; for (t = First(nn->normallist); t.item; t = Next(t)) { normalize_type(t.item); } Delete(nn->normallist); np = nn->next; delete (nn); nn = np; } Swig_symbol_setscope(currentsym); } /* generate C++ inheritance type-relationships */ void cplus_inherit_types_impl(Node *first, Node *cls, String *clsname, const char *bases, const char *baselist, int ispublic, String *cast = 0) { if (first == cls) return; /* The Marcelo check */ if (!cls) cls = first; List *alist = 0; List *ilist = Getattr(cls, bases); if (!ilist) { List *nlist = Getattr(cls, baselist); if (nlist) { int len = Len(nlist); int i; for (i = 0; i < len; i++) { Node *bcls = 0; int clsforward = 0; String *bname = Getitem(nlist, i); String *sname = bname; String *tname = 0; /* Try to locate the base class. We look in the symbol table and we chase typedef declarations to get to the base class if necessary */ Symtab *st = Getattr(cls, "sym:symtab"); if (SwigType_istemplate(bname)) { tname = SwigType_typedef_resolve_all(bname); sname = tname; } int resolve_class = 0; while (1) { String *qsname = SwigType_typedef_qualified(sname); /* When resolve_class is set, look up the aliased class instead of a self-referential typedef. */ bcls = resolve_class ? Swig_symbol_clookup_check(qsname, st, symbol_resolve_to_class) : Swig_symbol_clookup(qsname, st); Delete(qsname); if (bcls) { if (Strcmp(nodeType(bcls), "class") != 0) { /* Not a class. The symbol could be a typedef. */ if (checkAttribute(bcls, "storage", "typedef")) { SwigType *decl = Getattr(bcls, "decl"); if (!decl || !(Len(decl))) { sname = Getattr(bcls, "type"); st = Getattr(bcls, "sym:symtab"); if (SwigType_istemplate(sname)) { if (tname) Delete(tname); tname = SwigType_typedef_resolve_all(sname); sname = tname; } /* A self-referential typedef such as 'typedef struct foo foo;' resolves by name back to itself; resolve the aliased class instead of looping forever. */ String *nqsname = SwigType_typedef_qualified(sname); if (Swig_symbol_clookup(nqsname, st) == bcls) resolve_class = 1; Delete(nqsname); continue; } // A case when both outer and nested classes inherit from the same parent. Constructor may be found instead of the class itself. } else if (GetFlag(cls, "nested") && checkAttribute(bcls, "nodeType", "constructor")) { bcls = Getattr(bcls, "parentNode"); if (Getattr(bcls, "typepass:visit")) { if (!Getattr(bcls, "feature:onlychildren")) { if (!ilist) ilist = alist = NewList(); Append(ilist, bcls); } else { if (!GetFlag(bcls, "feature:ignore")) { Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); } } } break; } if (Strcmp(nodeType(bcls), "classforward") != 0) { Swig_error(Getfile(bname), Getline(bname), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); Swig_error(Getfile(bcls), Getline(bcls), "See definition of '%s'.\n", SwigType_namestr(bname)); } else { Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bname), Getline(bname), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname)); clsforward = 1; } bcls = 0; } else { if (Getattr(bcls, "typepass:visit")) { if (!Getattr(bcls, "feature:onlychildren")) { if (!ilist) ilist = alist = NewList(); Append(ilist, bcls); } else { if (!GetFlag(bcls, "feature:ignore")) { Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); } } } else { Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' undefined.\n", SwigType_namestr(bname)); Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "'%s' must be defined before it is used as a base class.\n", SwigType_namestr(bname)); } } } break; } if (tname) Delete(tname); if (!bcls) { if (!clsforward && !GetFlag(cls, "feature:ignore")) { if (ispublic && !Getmeta(bname, "already_warned")) { Swig_warning( WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); if (Strchr(bname, '<')) { Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Maybe you forgot to instantiate '%s' using %%template.\n", SwigType_namestr(bname)); } Setmeta(bname, "already_warned", "1"); } } SwigType_inherit(clsname, bname, cast, 0); } } } if (ilist) { Setattr(cls, bases, ilist); } } if (alist) Delete(alist); if (!ilist) return; int len = Len(ilist); int i; for (i = 0; i < len; i++) { Node *bclass = Getitem(ilist, i); SwigType *bname = Getattr(bclass, "name"); Hash *scopes = Getattr(bclass, "typescope"); SwigType_inherit(clsname, bname, cast, 0); if (ispublic && !GetFlag(bclass, "feature:ignore")) { String *smart = Getattr(first, "smart"); if (smart) { /* Record a (fake) inheritance relationship between smart pointer and smart pointer to base class, so that smart pointer upcasts are automatically generated. */ SwigType *bsmart = Getattr(bclass, "smart"); if (bsmart) { String *smartnamestr = SwigType_namestr(smart); String *bsmartnamestr = SwigType_namestr(bsmart); /* construct casting code */ String *convcode = NewStringf("\n *newmemory = SWIG_CAST_NEW_MEMORY;\n return (void *) new %s(*(%s *)$from);\n", bsmartnamestr, smartnamestr); /* setup inheritance relationship between smart pointer templates */ SwigType_inherit(smart, bsmart, 0, convcode); Delete(bsmartnamestr); Delete(smartnamestr); Delete(convcode); } else { Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Base class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(bclass, "name")), SwigType_namestr(Getattr(first, "name"))); } } else { if (GetFlag(bclass, "smart")) if (!GetFlag(first, "feature:ignore")) Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Derived class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(first, "name")), SwigType_namestr(Getattr(bclass, "name"))); } } if (!importmode) { String *btype = Copy(bname); SwigType_add_pointer(btype); SwigType_remember(btype); Delete(btype); } if (scopes) { SwigType_inherit_scope(scopes); /* Make the base class' name resolve to the base's own scope from within the derived class (the C++ injected class name). This lets a type that names the base unqualified ('Base') or through the derived class ('Derived::Base') resolve to the base's own type, mirroring in the type system what Swig_symbol_inherit() does in the symbol table. */ { String *blast = Swig_scopename_last(bname); SwigType_scope_alias(blast, scopes); Delete(blast); } } /* Set up inheritance in the symbol table */ Symtab *st = Getattr(cls, "symtab"); Symtab *bst = Getattr(bclass, "symtab"); if (st == bst) { Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", SwigType_namestr(Getattr(cls, "name"))); continue; } Symtab *s = Swig_symbol_current(); Swig_symbol_setscope(st); Swig_symbol_inherit(bst); Swig_symbol_setscope(s); /* Recursively hit base classes */ String *namestr = SwigType_namestr(Getattr(bclass, "name")); String *newcast = NewStringf("(%s *)%s", namestr, cast); Delete(namestr); cplus_inherit_types_impl(first, bclass, clsname, bases, baselist, ispublic, newcast); Delete(newcast); } } void append_list(List *lb, List *la) { if (la && lb) { for (Iterator bi = First(la); bi.item; bi = Next(bi)) { Append(lb, bi.item); } } } void cplus_inherit_types(Node *first, Node *cls, String *clsname, String *cast = 0) { cplus_inherit_types_impl(first, cls, clsname, "bases", "baselist", 1, cast); cplus_inherit_types_impl(first, cls, clsname, "protectedbases", "protectedbaselist", 0, cast); cplus_inherit_types_impl(first, cls, clsname, "privatebases", "privatebaselist", 0, cast); if (!cls) cls = first; List *allbases = NewList(); append_list(allbases, Getattr(cls, "bases")); append_list(allbases, Getattr(cls, "protectedbases")); append_list(allbases, Getattr(cls, "privatebases")); if (Len(allbases)) { Setattr(cls, "allbases", allbases); } Delete(allbases); } /* ------------------------------------------------------------ * nspace_setting() * * Configures "sym:nspace" on the node and returns an overridden * nspace value when %nspacemove is used. * outer should point to parent class. * ------------------------------------------------------------ */ String *nspace_setting(Node *n, Node *outer) { String *nssymname_new = nssymname; String *feature_nspace = GetFlagAttr(n, "feature:nspace"); String *nspace = Copy(feature_nspace); // Check validity - single colons not allowed const char *c = Char(feature_nspace); int valid = 1; while (c && *c) { if (*(c++) == ':' && *(c++) != ':') { valid = 0; break; } } // Remove whitespace Replaceall(nspace, " ", ""); Replaceall(nspace, "\t", ""); valid = valid && (feature_nspace ? Equal(feature_nspace, "1") || Swig_scopename_isvalid(nspace) : 1); Replaceall(nspace, "::", "."); if (valid) { if (outer) { // Nested class or enum in a class String *outer_nspace = Getattr(outer, "sym:nspace"); String *nspace_attribute = Getattr(n, "feature:nspace"); bool warn = false; if (outer_nspace) { if (Equal(nspace_attribute, "0")) { warn = true; } else if (nspace && !(Equal(nspace, "1") || Equal(nspace, outer_nspace))) { warn = true; } } else if (nspace) { warn = true; } if (warn) { String *outer_nspace_feature = Copy(outer_nspace); Replaceall(outer_nspace_feature, ".", "::"); Swig_warning(WARN_TYPE_NSPACE_SETTING, Getfile(n), Getline(n), "Ignoring nspace setting (%s) for '%s',\n", nspace_attribute, Swig_name_decl(n)); Swig_warning(WARN_TYPE_NSPACE_SETTING, Getfile(outer), Getline(outer), "as it conflicts with the nspace setting (%s) for outer class '%s'.\n", outer_nspace_feature, Swig_name_decl(outer)); } Setattr(n, "sym:nspace", outer_nspace); } else { if (nspace) { if (Equal(nspace, "1")) { if (nssymname) Setattr(n, "sym:nspace", nssymname); } else { Setattr(n, "sym:nspace", nspace); nssymname_new = nspace; } } } } else { Swig_error(Getfile(n), Getline(n), "'%s' is not a valid identifier for nspace.\n", feature_nspace); } Delete(nspace); return nssymname_new; } /* ------------------------------------------------------------ * top() * ------------------------------------------------------------ */ virtual int top(Node *n) { importmode = 0; module = Getattr(n, "module"); inclass = 0; normalize = 0; nsname = 0; nssymname = 0; classhash = Getattr(n, "classes"); emit_children(n); normalize_list(); SwigType_set_scope(0); return SWIG_OK; } /* ------------------------------------------------------------ * moduleDirective() * ------------------------------------------------------------ */ virtual int moduleDirective(Node *n) { if (!module) { module = n; } return SWIG_OK; } /* ------------------------------------------------------------ * importDirective() * ------------------------------------------------------------ */ virtual int importDirective(Node *n) { String *oldmodule = module; int oldimport = importmode; importmode = 1; module = 0; emit_children(n); importmode = oldimport; module = oldmodule; return SWIG_OK; } /* ------------------------------------------------------------ * includeDirective() * externDirective() * extendDirective() * ------------------------------------------------------------ */ virtual int includeDirective(Node *n) { return emit_children(n); } virtual int externDeclaration(Node *n) { return emit_children(n); } virtual int extendDirective(Node *n) { return emit_children(n); } /* ------------------------------------------------------------ * classDeclaration() * ------------------------------------------------------------ */ virtual int classDeclaration(Node *n) { String *name = Getattr(n, "name"); String *tdname = Getattr(n, "tdname"); String *unnamed = Getattr(n, "unnamed"); String *storage = Getattr(n, "storage"); String *kind = Getattr(n, "kind"); save_value<Node *> oldinclass(inclass); List *olist = normalize; Symtab *symtab; String *nname = 0; String *fname = 0; String *scopename = 0; String *template_default_expanded = 0; normalize = NewList(); if (name) { if (SwigType_istemplate(name)) { // We need to fully resolve the name and expand default template parameters to make templates work correctly Node *cn; SwigType *resolved_name = SwigType_typedef_resolve_all(name); SwigType *deftype_name = Swig_symbol_template_deftype(resolved_name, 0); fname = Copy(resolved_name); if (!Equal(resolved_name, deftype_name)) template_default_expanded = Copy(deftype_name); if (!Equal(fname, name) && (cn = Swig_symbol_clookup_local(fname, 0))) { if ((n == cn) || (Strcmp(nodeType(cn), "template") == 0) || (Getattr(cn, "feature:onlychildren") != 0) || (Getattr(n, "feature:onlychildren") != 0)) { Swig_symbol_cadd(fname, n); if (template_default_expanded) Swig_symbol_cadd(template_default_expanded, n); SwigType_typedef_class(fname); scopename = Copy(fname); } else { // Arguably the parser should instead ignore these duplicate template instantiations, in particular for ensuring the first parsed instantiation is // used SetFlag(n, "feature:ignore"); Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "Duplicate template instantiation of '%s' with name '%s' ignored,\n", SwigType_namestr(name), Getattr(n, "sym:name")); Swig_warning(WARN_TYPE_REDEFINED, Getfile(cn), Getline(cn), "previous instantiation of '%s' with name '%s'.\n", SwigType_namestr(Getattr(cn, "name")), Getattr(cn, "sym:name")); scopename = 0; } } else { Swig_symbol_cadd(fname, n); SwigType_typedef_class(fname); scopename = Copy(fname); } Delete(deftype_name); Delete(resolved_name); } else { if ((CPlusPlus) || (unnamed)) { SwigType_typedef_class(name); } else { SwigType_typedef_class(NewStringf("%s %s", kind, name)); } scopename = Copy(name); } } else { scopename = 0; } Setattr(n, "typepass:visit", "1"); /* Need to set up a typedef if unnamed */ if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { SwigType_typedef(unnamed, tdname); } // name of the outer class should already be patched to contain its outer classes names, but not to contain namespaces // namespace name (if present) is added after processing child nodes if (Getattr(n, "nested:outer") && name) { String *outerName = Getattr(Getattr(n, "nested:outer"), "name"); name = NewStringf("%s::%s", outerName, name); Setattr(n, "name", name); if (tdname) { tdname = NewStringf("%s::%s", outerName, tdname); Setattr(n, "tdname", tdname); } } if (nsname && name) { nname = NewStringf("%s::%s", nsname, name); String *tdname = Getattr(n, "tdname"); if (tdname) { tdname = NewStringf("%s::%s", nsname, tdname); Setattr(n, "tdname", tdname); } } String *oldnssymname = nssymname; nssymname = nspace_setting(n, Getattr(n, "nested:outer")); SwigType_new_scope(scopename); SwigType_attach_symtab(Getattr(n, "symtab")); if (!GetFlag(n, "feature:ignore")) { SwigType *smart = Swig_cparse_smartptr(n); if (smart) { // Resolve the type in 'feature:smartptr' in the scope of the class it is attached to normalize_type(smart); Setattr(n, "smart", smart); Delete(smart); } } /* Inherit type definitions into the class. Skipped for a non-public nested class that is not wrapped. */ if (name && !(GetFlag(n, "nested") && !checkAttribute(n, "access", "public"))) { cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name)); } inclass = n; symtab = Swig_symbol_setscope(Getattr(n, "symtab")); emit_children(n); Swig_symbol_setscope(symtab); Hash *ts = SwigType_pop_scope(); Setattr(n, "typescope", ts); Delete(ts); Setattr(n, "module", module); // When a fully qualified templated type with default parameters is used in the parsed code, // the following additional symbols and scopes are needed for successful lookups if (template_default_expanded) { Swig_symbol_alias(template_default_expanded, Getattr(n, "symtab")); SwigType_scope_alias(template_default_expanded, Getattr(n, "typescope")); } nssymname = oldnssymname; /* Normalize deferred types */ { normal_node *nn = new normal_node(); nn->normallist = normalize; nn->symtab = Getattr(n, "symtab"); nn->next = patch_list; nn->typescope = Getattr(n, "typescope"); patch_list = nn; } normalize = olist; /* If in a namespace, patch the class name */ if (nname) { Setattr(n, "name", nname); Delete(nname); } Delete(fname); return SWIG_OK; } /* ------------------------------------------------------------ * templateDeclaration() * ------------------------------------------------------------ */ virtual int templateDeclaration(Node *n) { String *name = Getattr(n, "name"); String *ttype = Getattr(n, "templatetype"); if (Strcmp(ttype, "class") == 0) { String *rname = SwigType_typedef_resolve_all(name); SwigType_typedef_class(rname); Delete(rname); } else if (Strcmp(ttype, "classforward") == 0) { String *rname = SwigType_typedef_resolve_all(name); SwigType_typedef_class(rname); Delete(rname); /* SwigType_typedef_class(name); */ } else if (Strcmp(ttype, "cdecl") == 0) { String *rname = SwigType_typedef_resolve_all(name); SwigType_typedef_class(rname); Delete(rname); } else if (Strcmp(ttype, "concept") == 0) { /* A C++20 concept is a constexpr bool, not a type, so no typedef class registration is needed; the branch is here to mark "concept" as a known templatetype. */ } return SWIG_OK; } /* ------------------------------------------------------------ * lambdaDeclaration() * ------------------------------------------------------------ */ virtual int lambdaDeclaration(Node *) { return SWIG_OK; } /* ------------------------------------------------------------ * classforwardDeclaration() * ------------------------------------------------------------ */ virtual int classforwardDeclaration(Node *n) { /* Can't do inside a C struct because it breaks C nested structure wrapping */ if ((!inclass) || (CPlusPlus)) { String *name = Getattr(n, "name"); SwigType_typedef_class(name); } return SWIG_OK; } /* ------------------------------------------------------------ * namespaceDeclaration() * ------------------------------------------------------------ */ virtual int namespaceDeclaration(Node *n) { Symtab *symtab; String *name = Getattr(n, "name"); String *alias = Getattr(n, "alias"); List *olist = normalize; normalize = NewList(); if (alias) { Typetab *ts = Getattr(n, "typescope"); if (!ts) { /* Create an empty scope for the alias */ Node *ns = Getattr(n, "namespace"); SwigType_scope_alias(name, Getattr(ns, "typescope")); ts = Getattr(ns, "typescope"); Setattr(n, "typescope", ts); } /* Namespace alias */ return SWIG_OK; } else { if (name) { Node *nn = Swig_symbol_clookup(name, n); Hash *ts = 0; if (nn) ts = Getattr(nn, "typescope"); if (!ts) { SwigType_new_scope(name); SwigType_attach_symtab(Getattr(n, "symtab")); } else { SwigType_set_scope(ts); } } String *oldnsname = nsname; String *oldnssymname = nssymname; nsname = Swig_symbol_qualified(Getattr(n, "symtab")); nssymname = Swig_symbol_qualified_language_scopename(Getattr(n, "symtab")); symtab = Swig_symbol_setscope(Getattr(n, "symtab")); emit_children(n); Swig_symbol_setscope(symtab); if (name) { Hash *ts = SwigType_pop_scope(); Setattr(n, "typescope", ts); Delete(ts); } /* Normalize deferred types */ { normal_node *nn = new normal_node(); nn->normallist = normalize; nn->symtab = Getattr(n, "symtab"); nn->next = patch_list; nn->typescope = Getattr(n, "typescope"); patch_list = nn; } normalize = olist; Delete(nssymname); nssymname = oldnssymname; Delete(nsname); nsname = oldnsname; return SWIG_OK; } } /* ------------------------------------------------------------ * cDeclaration() * ------------------------------------------------------------ */ virtual int cDeclaration(Node *n) { if (NoExcept) { Delattr(n, "throws"); } /* Normalize types. */ if (inclass) { normalize_void(n); } SwigType *ty = Getattr(n, "type"); if (!ty) { return SWIG_OK; } normalize_type(ty); SwigType *decl = Getattr(n, "decl"); if (decl) { normalize_type(decl); } normalize_parms(Getattr(n, "parms")); normalize_parms(Getattr(n, "throws")); if (GetFlag(n, "conversion_operator")) { /* The call to the operator in the generated wrapper must be fully qualified in order to compile */ SwigType *name = Getattr(n, "name"); SwigType *qualifiedname = Swig_symbol_string_qualify(name, 0); Clear(name); Append(name, qualifiedname); Delete(qualifiedname); } if (checkAttribute(n, "storage", "typedef")) { String *name = Getattr(n, "name"); ty = Getattr(n, "type"); decl = Getattr(n, "decl"); SwigType *t = Copy(ty); { /* If the typename is qualified, make sure the scopename is fully qualified when making a typedef */ if (Swig_scopename_check(t) && strncmp(Char(t), "::", 2)) { String *base, *prefix, *qprefix; base = Swig_scopename_last(t); prefix = Swig_scopename_prefix(t); qprefix = SwigType_typedef_qualified(prefix); Delete(t); t = NewStringf("%s::%s", qprefix, base); Delete(base); Delete(prefix); Delete(qprefix); } } SwigType_push(t, decl); if (CPlusPlus) { Replaceall(t, "struct ", ""); Replaceall(t, "union ", ""); Replaceall(t, "class ", ""); } SwigType_typedef(t, name); } /* If namespaces are active. We need to patch the name with a namespace prefix */ if (nsname && !inclass) { String *name = Getattr(n, "name"); if (name) { String *nname = NewStringf("%s::%s", nsname, name); Setattr(n, "name", nname); Delete(nname); } } clean_overloaded(n); return SWIG_OK; } /* ------------------------------------------------------------ * constructorDeclaration() * ------------------------------------------------------------ */ virtual int constructorDeclaration(Node *n) { if (NoExcept) { Delattr(n, "throws"); } /* Normalize types. */ if (inclass) { normalize_void(n); } normalize_parms(Getattr(n, "parms")); normalize_parms(Getattr(n, "throws")); clean_overloaded(n); return SWIG_OK; } /* ------------------------------------------------------------ * destructorDeclaration() * ------------------------------------------------------------ */ virtual int destructorDeclaration(Node *) { return SWIG_OK; } /* ------------------------------------------------------------ * constantDirective() * ------------------------------------------------------------ */ virtual int constantDirective(Node *n) { SwigType *ty = Getattr(n, "type"); if (ty) { Setattr(n, "type", SwigType_typedef_qualified(ty)); } return SWIG_OK; } /* ------------------------------------------------------------ * enumDeclaration() * ------------------------------------------------------------ */ virtual int enumDeclaration(Node *n) { String *name = Getattr(n, "name"); if (name) { String *scope = 0; // Add a typedef to the type table so that we can use 'enum Name' as well as just 'Name' if (nsname || inclass) { // But first correct the name and tdname to contain the fully qualified scopename if (nsname && inclass) { scope = NewStringf("%s::%s", nsname, Getattr(inclass, "name")); } else if (nsname) { scope = NewStringf("%s", nsname); } else if (inclass) { scope = NewStringf("%s", Getattr(inclass, "name")); } String *nname = NewStringf("%s::%s", scope, name); Setattr(n, "name", nname); String *tdname = Getattr(n, "tdname"); if (tdname) { tdname = NewStringf("%s::%s", scope, tdname); Setattr(n, "tdname", tdname); } SwigType *t = NewStringf("enum %s", nname); SwigType_typedef(t, name); } else { SwigType *t = NewStringf("enum %s", name); SwigType_typedef(t, name); } Delete(scope); } String *tdname = Getattr(n, "tdname"); String *unnamed = Getattr(n, "unnamed"); String *storage = Getattr(n, "storage"); // Construct enumtype - for declaring an enum of this type with SwigType_ltype() etc String *enumtype = 0; if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { enumtype = Copy(Getattr(n, "tdname")); } else if (name) { enumtype = NewStringf("%s%s", CPlusPlus ? "" : "enum ", Getattr(n, "name")); } else { // anonymous enums enumtype = Copy(Getattr(n, "type")); } Setattr(n, "enumtype", enumtype); String *oldnssymname = nssymname; Node *parent = parentNode(n); nssymname = nspace_setting(n, parent && Equal(nodeType(parent), "class") ? parent : NULL); // This block of code is for dealing with %ignore on an enum item where the target language // attempts to use the C enum value in the target language itself and expects the previous enum value // to be one more than the previous value... the previous enum item might not exist if it is ignored! // - It sets the first non-ignored enum item with the "firstenumitem" attribute. // - It adds an enumvalue attribute if the previous enum item is ignored { Node *c; int count = 0; String *previous = 0; bool previous_ignored = false; bool firstenumitem = false; for (c = firstChild(n); c; c = nextSibling(c)) { assert(strcmp(Char(nodeType(c)), "enumitem") == 0); bool reset; String *enumvalue = Getattr(c, "enumvalue"); if (GetFlag(c, "feature:ignore") || !Getattr(c, "sym:name")) { reset = enumvalue ? true : false; previous_ignored = true; } else { if (!enumvalue && previous_ignored) { if (previous) Setattr(c, "enumvalue", NewStringf("(%s) + %d", previous, count + 1)); else Setattr(c, "enumvalue", NewStringf("%d", count)); SetFlag(c, "virtenumvalue"); // identify enumvalue as virtual, ie not from the parsed source } if (!firstenumitem) { SetFlag(c, "firstenumitem"); firstenumitem = true; } reset = true; previous_ignored = false; } if (reset) { previous = enumvalue ? enumvalue : Getattr(c, "name"); count = 0; } else { count++; } } } emit_children(n); nssymname = oldnssymname; return SWIG_OK; } /* ------------------------------------------------------------ * enumvalueDeclaration() * ------------------------------------------------------------ */ virtual int enumvalueDeclaration(Node *n) { String *name = Getattr(n, "name"); String *value = Getattr(n, "value"); String *scopedenum = Getattr(parentNode(n), "scopedenum"); if (!value) value = name; if (Strcmp(value, name) == 0) { String *new_value; if ((nsname || inclass || scopedenum) && cparse_cplusplus) { new_value = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); } else { new_value = NewString(value); } if ((nsname || inclass || scopedenum) && !cparse_cplusplus) { String *cppvalue = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); Setattr(n, "cppvalue", cppvalue); /* for target languages that always generate C++ code even when wrapping C code */ } Setattr(n, "value", new_value); Delete(new_value); } Node *next = nextSibling(n); // Make up an enumvalue if one was not specified in the parsed code (not designed to be used on enum items and %ignore - enumvalue will be set instead) if (!GetFlag(n, "feature:ignore")) { if (Getattr(n, "_last") && !Getattr(n, "enumvalue")) { // Only the first enum item has _last set (Note: first non-ignored enum item has firstenumitem set) Setattr(n, "enumvalueex", "0"); } if (next && !Getattr(next, "enumvalue")) { Setattr(next, "enumvalueex", NewStringf("%s + 1", Getattr(n, "sym:name"))); } } return SWIG_OK; } /* ------------------------------------------------------------ * enumforwardDeclaration() * ------------------------------------------------------------ */ virtual int enumforwardDeclaration(Node *n) { // Use enumDeclaration() to do all the hard work. // Note that no children can be emitted in a forward declaration as there aren't any. int result = enumDeclaration(n); if (result == SWIG_OK) { // Detect when the real enum matching the forward enum declaration has not been parsed/declared SwigType *ty = SwigType_typedef_resolve_all(Getattr(n, "type")); Replaceall(ty, "enum ", ""); Node *nn = Swig_symbol_clookup(ty, 0); String *nodetype = nn ? nodeType(nn) : 0; if (nodetype) { if (Equal(nodetype, "enumforward")) { SetFlag(nn, "enumMissing"); } // if a real enum was declared this would be an "enum" node type } Delete(ty); } return result; } #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(EXIT_FAILURE); } 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(EXIT_FAILURE); } c = Getattr(c, "sym:nextSibling"); } Printf(stdout, "-------------------- overloaded end %s -------------------------------\n", Getattr(n, "name")); } #endif /* ------------------------------------------------------------ * usingDeclaration() * ------------------------------------------------------------ */ virtual int usingDeclaration(Node *n) { if (Getattr(n, "namespace")) { /* using namespace id */ /* For a namespace import. We set up inheritance in the type system */ Node *ns = Getattr(n, "node"); if (ns) { Typetab *ts = Getattr(ns, "typescope"); if (ts) { SwigType_using_scope(ts); } } return SWIG_OK; } else { Node *ns = 0; /* using id */ Symtab *stab = Getattr(n, "sym:symtab"); if (stab) { String *uname = Getattr(n, "uname"); if (GetFlag(n, "usingctor")) { /* The parser flags a using declaration as a candidate inheriting constructor when either: * (a) the terminal name of the nested-name-specifier is the same as the unqualified-id, or * (b) the unqualified-id is the terminal name of a base class of the enclosing class. * Case (a) is verified in Allocate::usingDeclaration. * Case (b) is verified here. A case (b) candidate may be a false positive: an ordinary member * using declaration whose unqualified-id happens to match a base class name. Verify it by resolving the * nested-name-specifier through typedefs to its base class - a genuine inheriting constructor names that * base class's own constructor, so the unqualified-id must equal the resolved base class name. */ SwigType *nested_name_specifier = Swig_scopename_prefix(uname); String *unqualified_id = Swig_scopename_last(uname); String *terminal = Swig_scopename_last(nested_name_specifier); String *terminal_name = SwigType_istemplate(terminal) ? SwigType_templateprefix(terminal) : Copy(terminal); if (!Equal(unqualified_id, terminal_name)) { /* Verify case (b) */ normalize_type(nested_name_specifier); SwigType *nested_name_specifier_resolved = SwigType_typedef_resolve_all(nested_name_specifier); SwigType *resolved_terminal = Swig_scopename_last(nested_name_specifier_resolved); String *resolved_terminal_name = SwigType_istemplate(resolved_terminal) ? SwigType_templateprefix(resolved_terminal) : Copy(resolved_terminal); if (!Equal(unqualified_id, resolved_terminal_name)) { // Not an inheriting constructor - undo the parser's rename so it is treated as an ordinary member using declaration UnsetFlag(n, "usingctor"); Setattr(n, "name", unqualified_id); // sym:name reverts to the plain unqualified-id, however, a %rename of this would be missed though (an obscure corner case) Setattr(n, "sym:name", unqualified_id); } Delete(resolved_terminal_name); Delete(resolved_terminal); Delete(nested_name_specifier_resolved); } Delete(terminal_name); Delete(terminal); Delete(unqualified_id); Delete(nested_name_specifier); } if (GetFlag(n, "usingctor")) { // Inherited constructors: don't try and resolve the constructor as it may be implicit and hence absent at this stage. // Normalize and resolve the class instead and if successful reconstruct the using declaration for the inherited constructor. SwigType *nested_name_specifier = Swig_scopename_prefix(uname); normalize_type(nested_name_specifier); SwigType *nested_name_specifier_resolved = SwigType_typedef_resolve_all(nested_name_specifier); SwigType *resolved_terminal = Swig_scopename_last(nested_name_specifier_resolved); String *resolved_terminal_name = SwigType_istemplate(resolved_terminal) ? SwigType_templateprefix(resolved_terminal) : Copy(resolved_terminal); SwigType *uname_normalized = NewStringf("%s::%s", nested_name_specifier_resolved, resolved_terminal_name); Setattr(n, "uname", uname_normalized); Delete(uname_normalized); Delete(resolved_terminal_name); Delete(resolved_terminal); Delete(nested_name_specifier_resolved); Delete(nested_name_specifier); } else { ns = Swig_symbol_clookup(uname, stab); if (!ns && SwigType_istemplate(uname)) { String *tmp = Swig_symbol_template_deftype(uname, 0); if (!Equal(tmp, uname)) { ns = Swig_symbol_clookup(tmp, stab); } Delete(tmp); } } } // Note that Allocate::usingDeclaration will warn when using member is not found (when ns is zero) if (ns) { /* 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 (Equal(ntype, "cdecl") || Equal(ntype, "constructor")) { if (checkAttribute(ns, "storage", "typedef")) { /* A typedef declaration */ String *uname = Getattr(n, "uname"); SwigType_typedef_using(uname); } } else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) { /* We install the using class name as kind of a typedef back to the original class */ String *uname = Getattr(n, "uname"); /* Import into current type scope */ SwigType_typedef_using(uname); } else if (Strcmp(ntype, "enum") == 0) { SwigType_typedef_using(Getattr(n, "uname")); } else if (Strcmp(ntype, "template") == 0) { SwigType_typedef_using(Getattr(n, "uname")); } } } return SWIG_OK; } /* ------------------------------------------------------------ * typemapDirective() * ------------------------------------------------------------ */ virtual int typemapDirective(Node *n) { if (inclass || nsname) { Node *items = firstChild(n); while (items) { Parm *pattern = Getattr(items, "pattern"); Parm *parms = Getattr(items, "parms"); normalize_later(pattern); normalize_later(parms); items = nextSibling(items); } } return SWIG_OK; } /* ------------------------------------------------------------ * typemapcopyDirective() * ------------------------------------------------------------ */ virtual int typemapcopyDirective(Node *n) { if (inclass || nsname) { Node *items = firstChild(n); ParmList *pattern = Getattr(n, "pattern"); normalize_later(pattern); while (items) { ParmList *npattern = Getattr(items, "pattern"); normalize_later(npattern); items = nextSibling(items); } } return SWIG_OK; } /* ------------------------------------------------------------ * applyDirective() * ------------------------------------------------------------ */ virtual int applyDirective(Node *n) { if (inclass || nsname) { ParmList *pattern = Getattr(n, "pattern"); normalize_later(pattern); Node *items = firstChild(n); while (items) { Parm *apattern = Getattr(items, "pattern"); normalize_later(apattern); items = nextSibling(items); } } return SWIG_OK; } /* ------------------------------------------------------------ * clearDirective() * ------------------------------------------------------------ */ virtual int clearDirective(Node *n) { if (inclass || nsname) { Node *p; for (p = firstChild(n); p; p = nextSibling(p)) { ParmList *pattern = Getattr(p, "pattern"); normalize_later(pattern); } } return SWIG_OK; } public: static void pass(Node *n) { TypePass t; t.top(n); } }; void Swig_process_types(Node *n) { if (!n) return; TypePass::pass(n); }