Merge branch 'templates-scope-enforcement'

* templates-scope-enforcement:
  Test a few %template errors
  Add using declarations to templates into typedef table.
  Fix type lookup in the presence of using directives and using declarations
  More docs on %template
  Testcase fix for nameclash in php
  %template scope enforcement and class definition fixes
  Template documentation tweaks
  More consistent formatting of examples in documentation
  More consistent formatting of examples in documentation
  Documentation corrections to use targetlang formatting
  More consistent formatting of examples in documentation
  More consistent formatting of examples in documentation
  More consistent formatting of examples in documentation
  Namespace documentation minor corrections
  Improve description of template_parameters_resolve
  Minor code optimisation in template_parameters_resolve
  Fix scope lookup for template parameters containing unary scope operators
  Typemap change for templates
This commit is contained in:
William S Fulton 2017-08-16 21:44:51 +01:00
commit 32a454cfef
51 changed files with 1924 additions and 700 deletions

View file

@ -823,10 +823,11 @@ String *Swig_string_emangle(String *s) {
/* -----------------------------------------------------------------------------
* Swig_scopename_prefix()
* Swig_scopename_split()
*
* Take a qualified name like "A::B::C" and return the scope name.
* In this case, "A::B". Returns NULL if there is no base.
* Take a qualified name like "A::B::C" and splits off the last name.
* In this case, returns "C" as last and "A::B" as prefix.
* Always returns non NULL for last, but prefix may be NULL if there is no prefix.
* ----------------------------------------------------------------------------- */
void Swig_scopename_split(const String *s, String **rprefix, String **rlast) {
@ -882,6 +883,12 @@ void Swig_scopename_split(const String *s, String **rprefix, String **rlast) {
}
}
/* -----------------------------------------------------------------------------
* Swig_scopename_prefix()
*
* Take a qualified name like "A::B::C" and return the scope name.
* In this case, "A::B". Returns NULL if there is no base.
* ----------------------------------------------------------------------------- */
String *Swig_scopename_prefix(const String *s) {
char *tmp = Char(s);
@ -1067,6 +1074,31 @@ String *Swig_scopename_suffix(const String *s) {
}
}
/* -----------------------------------------------------------------------------
* Swig_scopename_tolist()
*
* Take a qualified scope name like "A::B::C" and convert it to a list.
* In this case, return a list of 3 elements "A", "B", "C".
* Returns an empty list if the input is empty.
* ----------------------------------------------------------------------------- */
List *Swig_scopename_tolist(const String *s) {
List *scopes = NewList();
String *name = Len(s) == 0 ? 0 : NewString(s);
while (name) {
String *last = 0;
String *prefix = 0;
Swig_scopename_split(name, &prefix, &last);
Insert(scopes, 0, last);
Delete(last);
Delete(name);
name = prefix;
}
Delete(name);
return scopes;
}
/* -----------------------------------------------------------------------------
* Swig_scopename_check()
*

View file

@ -326,6 +326,7 @@ extern int ParmList_is_compactdefargs(ParmList *p);
extern String *Swig_scopename_last(const String *s);
extern String *Swig_scopename_first(const String *s);
extern String *Swig_scopename_suffix(const String *s);
extern List *Swig_scopename_tolist(const String *s);
extern int Swig_scopename_check(const String *s);
extern String *Swig_string_lower(String *s);
extern String *Swig_string_upper(String *s);

View file

@ -61,13 +61,44 @@ static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper
static Hash *typemaps;
/* -----------------------------------------------------------------------------
* typemap_identifier_fix()
*
* Create a type that can be used as a hash key lookup independent of the various
* ways a template parameter list can be defined. This is achieved by fully
* resolving the template parameters.
*
* This is a copy and modification of feature_identifier_fix in parser.y.
* ----------------------------------------------------------------------------- */
static SwigType *typemap_identifier_fix(const SwigType *s) {
String *tp = SwigType_istemplate_templateprefix(s);
if (tp) {
String *ts, *ta, *tq, *tr;
ts = SwigType_templatesuffix(s);
ta = SwigType_templateargs(s);
tq = Swig_symbol_type_qualify(ta, 0);
tr = SwigType_typedef_resolve_all(ta);
Append(tp,tr);
Append(tp,ts);
Delete(ts);
Delete(ta);
Delete(tq);
Delete(tr);
return tp;
} else {
return NewString(s);
}
}
static Hash *get_typemap(const SwigType *type) {
Hash *tm = 0;
SwigType *dtype = 0;
SwigType *hashtype;
if (SwigType_istemplate(type)) {
String *ty = Swig_symbol_template_deftype(type, 0);
SwigType *rty = typemap_identifier_fix(type);
String *ty = Swig_symbol_template_deftype(rty, 0);
dtype = Swig_symbol_type_qualify(ty, 0);
type = dtype;
Delete(ty);
@ -88,7 +119,7 @@ static void set_typemap(const SwigType *type, Hash **tmhash) {
Hash *new_tm = 0;
assert(*tmhash == 0);
if (SwigType_istemplate(type)) {
SwigType *rty = SwigType_typedef_resolve_all(type);
SwigType *rty = typemap_identifier_fix(type);
String *ty = Swig_symbol_template_deftype(rty, 0);
String *tyq = Swig_symbol_type_qualify(ty, 0);
hashtype = SwigType_remove_global_scope_prefix(tyq);
@ -733,6 +764,7 @@ static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type
SwigType *oldctype = ctype;
ctype = SwigType_typedef_resolve(ctype_unstripped);
Delete(oldctype);
Delete(ctype_unstripped);
ctype_unstripped = Copy(ctype);
}
}

View file

@ -42,10 +42,15 @@
* "name" - Scope name
* "qname" - Fully qualified typename
* "typetab" - Type table containing typenames and typedef information
* For a given key in the typetab table, the value is a fully
* qualified name if not pointing to itself.
* "symtab" - Hash table of symbols defined in a scope
* "inherit" - List of inherited scopes
* "parent" - Parent scope
*
* The contents of these tables can be viewed for debugging using the -debug-typedef
* option which calls SwigType_print_scope().
*
* Typedef information is stored in the "typetab" hash table. For example,
* if you have these declarations:
*
@ -53,8 +58,7 @@
* typedef A B;
* typedef B *C;
*
* typetab is built as follows:
*
* typetab in scope '' contains:
* "A" : "int"
* "B" : "A"
* "C" : "p.B"
@ -67,31 +71,76 @@
* ---> a(40).p.p.A (B --> A)
* ---> a(40).p.p.int (A --> int)
*
*
* Using declarations are stored in the "typetab" hash table. For example,
*
* namespace NN {
* struct SS {};
* }
* namespace N {
* struct S {};
* using NN::SS;
* }
* using N::S;
*
* typetab in scope '' contains:
* "S" : "N::S"
*
* and typetab in scope 'N' contains:
* "SS" : "NN::SS"
* "S" : "S"
*
*
* For inheritance, SWIG tries to resolve types back to the base class. For instance, if
* you have this:
*
* class Foo {
* public:
* typedef int Integer;
* };
* class Foo {
* public:
* typedef int Integer;
* };
* struct Bar : public Foo {
* void blah(Integer x);
* };
*
* class Bar : public Foo {
* void blah(Integer x);
* };
* In this case typetab in scope '' contains:
* "Foo" : "Foo"
* "Bar" : "Bar"
* and scope 'Foo' contains:
* "Integer" : "int"
* and scope 'Bar' inherits from 'Foo' but is empty (observe that blah is not a scope or typedef)
*
* The argument type of Bar::blah will be set to Foo::Integer.
*
*
* The scope-inheritance mechanism is used to manage C++ using directives.
*
* namespace XX {
* class CC {};
* }
* namespace X {
* class C {};
* using namespace XX;
* }
* using namespace X;
*
* typetab in scope '' inherits from 'X'
* typetab in scope 'X' inherits from 'XX' and contains:
* "C" : "C"
* typetab in scope 'XX' contains:
* "CC" : "CC"
*
*
* The scope-inheritance mechanism is used to manage C++ namespace aliases.
* For example, if you have this:
*
* namespace Foo {
* typedef int Integer;
* }
* namespace Foo {
* typedef int Integer;
* }
*
* namespace F = Foo;
* namespace F = Foo;
*
* In this case, "F::" is defined as a scope that "inherits" from Foo. Internally,
* "F::" will merely be an empty scope that refers to Foo. SWIG will never
* In this case, F is defined as a scope that "inherits" from Foo. Internally,
* F will merely be an empty scope that points to Foo. SWIG will never
* place new type information into a namespace alias---attempts to do so
* will generate a warning message (in the parser) and will place information into
* Foo instead.
@ -166,6 +215,7 @@ void SwigType_typesystem_init() {
* ----------------------------------------------------------------------------- */
int SwigType_typedef(const SwigType *type, const_String_or_char_ptr name) {
/* Printf(stdout, "typedef %s %s\n", type, name); */
if (Getattr(current_typetab, name))
return -1; /* Already defined */
if (Strcmp(type, name) == 0) { /* Can't typedef a name to itself */
@ -248,10 +298,26 @@ void SwigType_new_scope(const_String_or_char_ptr name) {
ttab = NewHash();
Setattr(s, "typetab", ttab);
/* Build fully qualified name and */
/* Build fully qualified name */
qname = SwigType_scope_name(s);
#if 1
{
/* TODO: only do with templates? What happens with non-templates with code below? */
String *stripped_qname;
stripped_qname = SwigType_remove_global_scope_prefix(qname);
/* Use fully qualified name for hash key without unary scope prefix, qname may contain unary scope */
Setattr(scopes, stripped_qname, s);
Setattr(s, "qname", qname);
/*
Printf(stdout, "SwigType_new_scope stripped %s %s\n", qname, stripped_qname);
*/
Delete(stripped_qname);
}
#else
Printf(stdout, "SwigType_new_scope %s\n", qname);
Setattr(scopes, qname, s);
Setattr(s, "qname", qname);
#endif
Delete(qname);
current_scope = s;
@ -418,12 +484,14 @@ static Typetab *SwigType_find_scope(Typetab *s, const SwigType *nameprefix) {
Typetab *s_orig = s;
String *nnameprefix = 0;
static int check_parent = 1;
int is_template = 0;
if (Getmark(s))
return 0;
Setmark(s, 1);
if (SwigType_istemplate(nameprefix)) {
is_template = SwigType_istemplate(nameprefix);
if (is_template) {
nnameprefix = SwigType_typedef_resolve_all(nameprefix);
nameprefix = nnameprefix;
}
@ -437,10 +505,12 @@ static Typetab *SwigType_find_scope(Typetab *s, const SwigType *nameprefix) {
} else {
full = NewString(nameprefix);
}
if (Getattr(scopes, full)) {
s = Getattr(scopes, full);
} else {
s = 0;
s = Getattr(scopes, full);
if (!s && is_template) {
/* try look up scope with all the unary scope operators within the template parameter list removed */
SwigType *full_stripped = SwigType_remove_global_scope_prefix(full);
s = Getattr(scopes, full_stripped);
Delete(full_stripped);
}
Delete(full);
if (s) {
@ -541,8 +611,11 @@ static SwigType *_typedef_resolve(Typetab *s, String *base, int look_parent) {
/* -----------------------------------------------------------------------------
* template_parameters_resolve()
*
* For use with templates only. The template parameters are resolved. If none
* of the parameters can be resolved, zero is returned.
* For use with templates only. Attempts to resolve one template parameter.
*
* If one of the template parameters can be resolved, the type is returned with
* just the one parameter resolved and the remaining parameters left as is.
* If none of the template parameters can be resolved, zero is returned.
* ----------------------------------------------------------------------------- */
static String *template_parameters_resolve(const String *base) {
@ -574,14 +647,15 @@ static String *template_parameters_resolve(const String *base) {
if ((i + 1) < sz)
Append(type, ",");
}
Append(type, ")>");
Append(type, suffix);
Delete(suffix);
Delete(tparms);
if (!rep) {
if (rep) {
Append(type, ")>");
Append(type, suffix);
} else {
Delete(type);
type = 0;
}
Delete(suffix);
Delete(tparms);
return type;
}
@ -592,6 +666,17 @@ static SwigType *typedef_resolve(Typetab *s, String *base) {
/* -----------------------------------------------------------------------------
* SwigType_typedef_resolve()
*
* Given a type declaration, this function looks to reduce/resolve the type via a
* typedef (including via C++ using declarations).
*
* If it is able to find a typedef, the resolved type is returned. If no typedef
* is found NULL is returned. The type name is resolved in the current scope.
* The type returned is not always fully qualified for the global scope, it is
* valid for use in the current scope. If the current scope is global scope, a
* fully qualified type should be returned.
*
* Some additional notes are in Doc/Manual/Extending.html.
* ----------------------------------------------------------------------------- */
/* #define SWIG_DEBUG */
@ -718,6 +803,25 @@ SwigType *SwigType_typedef_resolve(const SwigType *t) {
}
}
if (!type && SwigType_istemplate(base)) {
String *tprefix = SwigType_templateprefix(base);
String *rtprefix = SwigType_typedef_resolve(tprefix);
/* We're looking for a using declaration on the template prefix to resolve the template prefix
* in another scope. Using declaration do not have template parameters. */
if (rtprefix && !SwigType_istemplate(rtprefix)) {
String *tsuffix = SwigType_templatesuffix(base);
String *targs = SwigType_templateargs(base);
type = NewString(rtprefix);
newtype = 1;
Append(type, targs);
Append(type, tsuffix);
Delete(targs);
Delete(tsuffix);
Delete(rtprefix);
}
Delete(tprefix);
}
if (type && (Equal(base, type))) {
if (newtype)
Delete(type);
@ -911,6 +1015,9 @@ SwigType *SwigType_typedef_resolve_all(const SwigType *t) {
return Copy(r);
}
#ifdef SWIG_DEBUG
Printf(stdout, "SwigType_typedef_resolve_all start ... %s\n", t);
#endif
/* Recursively resolve the typedef */
r = NewString(t);
while ((n = SwigType_typedef_resolve(r))) {
@ -931,6 +1038,9 @@ SwigType *SwigType_typedef_resolve_all(const SwigType *t) {
Delete(key);
Delete(rr);
}
#ifdef SWIG_DEBUG
Printf(stdout, "SwigType_typedef_resolve_all end === %s => %s\n", t, r);
#endif
return r;
}
@ -938,8 +1048,17 @@ SwigType *SwigType_typedef_resolve_all(const SwigType *t) {
/* -----------------------------------------------------------------------------
* SwigType_typedef_qualified()
*
* Given a type declaration, this function tries to fully qualify it according to
* typedef scope rules.
* Given a type declaration, this function tries to fully qualify it so that the
* resulting type can be used in the global scope. The type name is resolved in
* the current scope.
*
* It provides a fully qualified name, not necessarily a fully expanded name.
* When a using declaration or using directive is found the type may not be fully
* expanded, but it will be resolved and fully qualified for use in the global scope.
*
* This function is for looking up scopes to qualify a type. It does not resolve
* C typedefs, it just qualifies them. See SwigType_typedef_resolve for resolving.
*
* If the unary scope operator (::) is used as a prefix to the type to denote global
* scope, it is left in place.
* ----------------------------------------------------------------------------- */
@ -1000,20 +1119,14 @@ SwigType *SwigType_typedef_qualified(const SwigType *t) {
out of the current scope */
Typetab *cs = current_scope;
while (cs) {
String *qs = SwigType_scope_name(cs);
if (Len(qs)) {
Append(qs, "::");
}
Append(qs, e);
if (Getattr(scopes, qs)) {
if (cs) {
Typetab *found_scope = SwigType_find_scope(cs, e);
if (found_scope) {
String *qs = SwigType_scope_name(found_scope);
Clear(e);
Append(e, qs);
Delete(qs);
break;
}
Delete(qs);
cs = Getattr(cs, "parent");
}
}
}
@ -1029,10 +1142,6 @@ SwigType *SwigType_typedef_qualified(const SwigType *t) {
Parm *p;
List *parms;
ty = Swig_symbol_template_deftype(e, current_symtab);
/*
String *dt = Swig_symbol_template_deftype(e, current_symtab);
ty = Swig_symbol_type_qualify(dt, 0);
*/
e = ty;
parms = SwigType_parmlist(e);
tprefix = SwigType_templateprefix(e);
@ -1099,9 +1208,6 @@ SwigType *SwigType_typedef_qualified(const SwigType *t) {
Delete(tprefix);
Delete(qprefix);
Delete(parms);
/*
Delete(dt);
*/
}
Append(result, e);
Delete(ty);
@ -1181,7 +1287,7 @@ int SwigType_typedef_using(const_String_or_char_ptr name) {
String *defined_name = 0;
/* Printf(stdout,"using %s\n", name); */
/* Printf(stdout, "using %s\n", name); */
if (!Swig_scopename_check(name))
return -1; /* Not properly qualified */