PageRenderTime 105ms CodeModel.GetById 10ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 1ms

/trunk/Source/Modules/allocate.cxx

#
C++ | 953 lines | 759 code | 78 blank | 116 comment | 290 complexity | eb9a40820f1b19711dd0468f92ab6e3d MD5 | raw file
  1/* ----------------------------------------------------------------------------- 
  2 * This file is part of SWIG, which is licensed as a whole under version 3 
  3 * (or any later version) of the GNU General Public License. Some additional
  4 * terms also apply to certain portions of SWIG. The full details of the SWIG
  5 * license and copyrights can be found in the LICENSE and COPYRIGHT files
  6 * included with the SWIG source code as distributed by the SWIG developers
  7 * and at http://www.swig.org/legal.html.
  8 *
  9 * allocate.cxx
 10 *
 11 * This module tries to figure out which classes and structures support
 12 * default constructors and destructors in C++.   There are several rules that
 13 * define this behavior including pure abstract methods, private sections,
 14 * and non-default constructors in base classes.  See the ARM or
 15 * Doc/Manual/SWIGPlus.html for details.
 16 * ----------------------------------------------------------------------------- */
 17
 18char cvsroot_allocate_cxx[] = "$Id: allocate.cxx 12804 2011-09-13 06:15:29Z wsfulton $";
 19
 20#include "swigmod.h"
 21#include "cparse.h"
 22
 23static int virtual_elimination_mode = 0;	/* set to 0 on default */
 24
 25/* Set virtual_elimination_mode */
 26void Wrapper_virtual_elimination_mode_set(int flag) {
 27  virtual_elimination_mode = flag;
 28}
 29
 30/* Helper function to assist with abstract class checking.  
 31   This is a major hack. Sorry.  */
 32
 33extern "C" {
 34  static String *search_decl = 0;	/* Declarator being searched */
 35  static int check_implemented(Node *n) {
 36    String *decl;
 37    if (!n)
 38       return 0;
 39    while (n) {
 40      if (Strcmp(nodeType(n), "cdecl") == 0) {
 41	decl = Getattr(n, "decl");
 42	if (SwigType_isfunction(decl)) {
 43	  SwigType *decl1 = SwigType_typedef_resolve_all(decl);
 44	  SwigType *decl2 = SwigType_pop_function(decl1);
 45	  if (Strcmp(decl2, search_decl) == 0) {
 46	    if (!Getattr(n, "abstract")) {
 47	      Delete(decl1);
 48	      Delete(decl2);
 49	      return 1;
 50	    }
 51	  }
 52	  Delete(decl1);
 53	  Delete(decl2);
 54	}
 55      }
 56      n = Getattr(n, "csym:nextSibling");
 57    }
 58    return 0;
 59  }
 60}
 61
 62class Allocate:public Dispatcher {
 63  Node *inclass;
 64  int extendmode;
 65
 66  /* Checks if a function, n, is the same as any in the base class, ie if the method is polymorphic.
 67   * Also checks for methods which will be hidden (ie a base has an identical non-virtual method).
 68   * Both methods must have public access for a match to occur. */
 69  int function_is_defined_in_bases(Node *n, Node *bases) {
 70
 71    if (!bases)
 72      return 0;
 73
 74    String *this_decl = Getattr(n, "decl");
 75    if (!this_decl)
 76       return 0;
 77
 78    String *name = Getattr(n, "name");
 79    String *this_type = Getattr(n, "type");
 80    String *resolved_decl = SwigType_typedef_resolve_all(this_decl);
 81
 82    // Search all base classes for methods with same signature
 83    for (int i = 0; i < Len(bases); i++) {
 84      Node *b = Getitem(bases, i);
 85      Node *base = firstChild(b);
 86      while (base) {
 87	if (Strcmp(nodeType(base), "extend") == 0) {
 88	  // Loop through all the %extend methods
 89	  Node *extend = firstChild(base);
 90	  while (extend) {
 91	    if (function_is_defined_in_bases_seek(n, b, extend, this_decl, name, this_type, resolved_decl)) {
 92	      Delete(resolved_decl);
 93	      return 1;
 94	    }
 95	    extend = nextSibling(extend);
 96	  }
 97	} else if (Strcmp(nodeType(base), "using") == 0) {
 98	  // Loop through all the using declaration methods
 99	  Node *usingdecl = firstChild(base);
100	  while (usingdecl) {
101	    if (function_is_defined_in_bases_seek(n, b, usingdecl, this_decl, name, this_type, resolved_decl)) {
102	      Delete(resolved_decl);
103	      return 1;
104	    }
105	    usingdecl = nextSibling(usingdecl);
106	  }
107	} else {
108	  // normal methods
109	  if (function_is_defined_in_bases_seek(n, b, base, this_decl, name, this_type, resolved_decl)) {
110	    Delete(resolved_decl);
111	    return 1;
112	  }
113	}
114	base = nextSibling(base);
115      }
116    }
117    Delete(resolved_decl);
118    resolved_decl = 0;
119    for (int j = 0; j < Len(bases); j++) {
120      Node *b = Getitem(bases, j);
121      if (function_is_defined_in_bases(n, Getattr(b, "allbases")))
122	return 1;
123    }
124    return 0;
125  }
126
127  /* Helper function for function_is_defined_in_bases */
128  int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) {
129
130    String *base_decl = Getattr(base, "decl");
131    SwigType *base_type = Getattr(base, "type");
132    if (base_decl && base_type) {
133      if (checkAttribute(base, "name", name) && !GetFlag(b, "feature:ignore") /* whole class is ignored */ ) {
134	if (SwigType_isfunction(resolved_decl) && SwigType_isfunction(base_decl)) {
135	  // We have found a method that has the same name as one in a base class
136	  bool covariant_returntype = false;
137	  bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false;
138	  bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false;
139	  if (returntype_match && decl_match) {
140	    // Exact match - we have found a method with identical signature
141	    // No typedef resolution was done, but skipping it speeds things up slightly
142	  } else {
143	    // Either we have:
144	    //  1) matching methods but are one of them uses a different typedef (return type or parameter) to the one in base class' method
145	    //  2) matching polymorphic methods with covariant return type
146	    //  3) a non-matching method (ie an overloaded method of some sort)
147	    //  4) a matching method which is not polymorphic, ie it hides the base class' method
148
149	    // Check if fully resolved return types match (including
150	    // covariant return types)
151	    if (!returntype_match) {
152	      String *this_returntype = function_return_type(n);
153	      String *base_returntype = function_return_type(base);
154	      returntype_match = Strcmp(this_returntype, base_returntype) == 0 ? true : false;
155	      if (!returntype_match) {
156		covariant_returntype = SwigType_issubtype(this_returntype, base_returntype) ? true : false;
157		returntype_match = covariant_returntype;
158	      }
159	      Delete(this_returntype);
160	      Delete(base_returntype);
161	    }
162	    // The return types must match at this point, for the whole method to match
163	    if (returntype_match && !decl_match) {
164	      // Now need to check the parameter list
165	      // First do an inexpensive parameter count
166	      ParmList *this_parms = Getattr(n, "parms");
167	      ParmList *base_parms = Getattr(base, "parms");
168	      if (ParmList_len(this_parms) == ParmList_len(base_parms)) {
169		// Number of parameters are the same, now check that all the parameters match
170		SwigType *base_fn = NewString("");
171		SwigType *this_fn = NewString("");
172		SwigType_add_function(base_fn, base_parms);
173		SwigType_add_function(this_fn, this_parms);
174		base_fn = SwigType_typedef_resolve_all(base_fn);
175		this_fn = SwigType_typedef_resolve_all(this_fn);
176		if (Strcmp(base_fn, this_fn) == 0) {
177		  // Finally check that the qualifiers match
178		  int base_qualifier = SwigType_isqualifier(resolved_decl);
179		  int this_qualifier = SwigType_isqualifier(base_decl);
180		  if (base_qualifier == this_qualifier) {
181		    decl_match = true;
182		  }
183		}
184		Delete(base_fn);
185		Delete(this_fn);
186	      }
187	    }
188	  }
189	  //Printf(stderr,"look %s %s %d %d\n",base_decl, this_decl, returntype_match, decl_match);
190
191	  if (decl_match && returntype_match) {
192	    // Found an identical method in the base class
193	    bool this_wrapping_protected_members = is_member_director(n) ? true : false;	// This should really check for dirprot rather than just being a director method
194	    bool base_wrapping_protected_members = is_member_director(base) ? true : false;	// This should really check for dirprot rather than just being a director method
195	    bool both_have_public_access = is_public(n) && is_public(base);
196	    bool both_have_protected_access = (is_protected(n) && this_wrapping_protected_members) && (is_protected(base) && base_wrapping_protected_members);
197	    bool both_have_private_access = is_private(n) && is_private(base);
198	    if (checkAttribute(base, "storage", "virtual")) {
199	      // Found a polymorphic method.
200	      // Mark the polymorphic method, in case the virtual keyword was not used.
201	      Setattr(n, "storage", "virtual");
202
203	      if (both_have_public_access || both_have_protected_access) {
204		if (!is_non_public_base(inclass, b))
205		  Setattr(n, "override", base);	// Note C# definition of override, ie access must be the same
206	      } else if (!both_have_private_access) {
207		// Different access
208		if (this_wrapping_protected_members || base_wrapping_protected_members)
209		  if (!is_non_public_base(inclass, b))
210		    Setattr(n, "hides", base);	// Note C# definition of hiding, ie hidden if access is different
211	      }
212	      // Try and find the most base's covariant return type
213	      SwigType *most_base_covariant_type = Getattr(base, "covariant");
214	      if (!most_base_covariant_type && covariant_returntype)
215		most_base_covariant_type = function_return_type(base, false);
216
217	      if (!most_base_covariant_type) {
218		// Eliminate the derived virtual method.
219		if (virtual_elimination_mode && !is_member_director(n))
220		  if (both_have_public_access)
221		    if (!is_non_public_base(inclass, b))
222		      if (!Swig_symbol_isoverloaded(n)) {
223			// Don't eliminate if an overloaded method as this hides the method
224			// in the scripting languages: the dispatch function will hide the base method if ignored.
225			SetFlag(n, "feature:ignore");
226		      }
227	      } else {
228		// Some languages need to know about covariant return types
229		Setattr(n, "covariant", most_base_covariant_type);
230	      }
231
232	    } else {
233	      // Found an identical method in the base class, but it is not polymorphic.
234	      if (both_have_public_access || both_have_protected_access)
235		if (!is_non_public_base(inclass, b))
236		  Setattr(n, "hides", base);
237	    }
238	    if (both_have_public_access || both_have_protected_access)
239	      return 1;
240	  }
241	}
242      }
243    }
244    return 0;
245  }
246
247  /* Determines whether the base class, b, is in the list of private
248   * or protected base classes for class n. */
249  bool is_non_public_base(Node *n, Node *b) {
250    bool non_public_base = false;
251    Node *bases = Getattr(n, "privatebases");
252    if (bases) {
253      for (int i = 0; i < Len(bases); i++) {
254	Node *base = Getitem(bases, i);
255	if (base == b)
256	  non_public_base = true;
257      }
258    }
259    bases = Getattr(n, "protectedbases");
260    if (bases) {
261      for (int i = 0; i < Len(bases); i++) {
262	Node *base = Getitem(bases, i);
263	if (base == b)
264	  non_public_base = true;
265      }
266    }
267    return non_public_base;
268  }
269
270  /* Returns the return type for a function. The node n should be a function.
271     If resolve is true the fully returned type is fully resolved.
272     Caller is responsible for deleting returned string. */
273  String *function_return_type(Node *n, bool resolve = true) {
274    String *decl = Getattr(n, "decl");
275    SwigType *type = Getattr(n, "type");
276    String *ty = NewString(type);
277    SwigType_push(ty, decl);
278    if (SwigType_isqualifier(ty))
279      Delete(SwigType_pop(ty));
280    Delete(SwigType_pop_function(ty));
281    if (resolve) {
282      String *unresolved = ty;
283      ty = SwigType_typedef_resolve_all(unresolved);
284      Delete(unresolved);
285    }
286    return ty;
287  }
288
289  /* Checks if a class member is the same as inherited from the class bases */
290  int class_member_is_defined_in_bases(Node *member, Node *classnode) {
291    Node *bases;		/* bases is the closest ancestors of classnode */
292    int defined = 0;
293
294    bases = Getattr(classnode, "allbases");
295    if (!bases)
296      return 0;
297
298    {
299      int old_mode = virtual_elimination_mode;
300      if (is_member_director(classnode, member))
301	virtual_elimination_mode = 0;
302
303      if (function_is_defined_in_bases(member, bases)) {
304	defined = 1;
305      }
306
307      virtual_elimination_mode = old_mode;
308    }
309
310    if (defined)
311      return 1;
312    else
313      return 0;
314  }
315
316  /* Checks to see if a class is abstract through inheritance,
317     and saves the first node that seems to be abstract.
318   */
319  int is_abstract_inherit(Node *n, Node *base = 0, int first = 0) {
320    if (!first && (base == n))
321      return 0;
322    if (!base) {
323      /* Root node */
324      Symtab *stab = Getattr(n, "symtab");	/* Get symbol table for node */
325      Symtab *oldtab = Swig_symbol_setscope(stab);
326      int ret = is_abstract_inherit(n, n, 1);
327      Swig_symbol_setscope(oldtab);
328      return ret;
329    }
330    List *abstract = Getattr(base, "abstract");
331    if (abstract) {
332      int dabstract = 0;
333      int len = Len(abstract);
334      for (int i = 0; i < len; i++) {
335	Node *nn = Getitem(abstract, i);
336	String *name = Getattr(nn, "name");
337	if (!name)
338	  continue;
339	String *base_decl = Getattr(nn, "decl");
340	if (base_decl)
341	  base_decl = SwigType_typedef_resolve_all(base_decl);
342	if (Strchr(name, '~'))
343	  continue;		/* Don't care about destructors */
344
345	if (SwigType_isfunction(base_decl)) {
346	  search_decl = SwigType_pop_function(base_decl);
347	}
348	Node *dn = Swig_symbol_clookup_local_check(name, 0, check_implemented);
349	Delete(search_decl);
350	Delete(base_decl);
351
352	if (!dn) {
353	  List *nabstract = Getattr(n, "abstract");
354	  if (!nabstract) {
355	    nabstract = NewList();
356	    Setattr(n, "abstract", nabstract);
357	    Delete(nabstract);
358	  }
359	  Append(nabstract, nn);
360	  if (!Getattr(n, "abstract:firstnode")) {
361	    Setattr(n, "abstract:firstnode", nn);
362	  }
363	  dabstract = base != n;
364	}
365      }
366      if (dabstract)
367	return 1;
368    }
369    List *bases = Getattr(base, "allbases");
370    if (!bases)
371      return 0;
372    for (int i = 0; i < Len(bases); i++) {
373      if (is_abstract_inherit(n, Getitem(bases, i))) {
374	return 1;
375      }
376    }
377    return 0;
378  }
379
380
381  /* Grab methods used by smart pointers */
382
383  List *smart_pointer_methods(Node *cls, List *methods, int isconst, String *classname = 0) {
384    if (!methods) {
385      methods = NewList();
386    }
387
388    Node *c = firstChild(cls);
389
390    while (c) {
391      if (Getattr(c, "error") || GetFlag(c, "feature:ignore")) {
392	c = nextSibling(c);
393	continue;
394      }
395      if (!isconst && (Strcmp(nodeType(c), "extend") == 0)) {
396	methods = smart_pointer_methods(c, methods, isconst, Getattr(cls, "name"));
397      } else if (Strcmp(nodeType(c), "cdecl") == 0) {
398	if (!GetFlag(c, "feature:ignore")) {
399	  String *storage = Getattr(c, "storage");
400	  if (!((Cmp(storage, "typedef") == 0))
401	      && !((Cmp(storage, "friend") == 0))) {
402	    String *name = Getattr(c, "name");
403	    String *symname = Getattr(c, "sym:name");
404	    Node *e = Swig_symbol_clookup_local(name, 0);
405	    if (e && is_public(e) && !GetFlag(e, "feature:ignore") && (Cmp(symname, Getattr(e, "sym:name")) == 0)) {
406	      Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(e), Getline(e), "Declaration of '%s' shadows declaration accessible via operator->(),\n", name);
407	      Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(c), Getline(c), "previous declaration of '%s'.\n", name);
408	    } else {
409	      /* Make sure node with same name doesn't already exist */
410	      int k;
411	      int match = 0;
412	      for (k = 0; k < Len(methods); k++) {
413		e = Getitem(methods, k);
414		if (Cmp(symname, Getattr(e, "sym:name")) == 0) {
415		  match = 1;
416		  break;
417		}
418		if ((!symname || (!Getattr(e, "sym:name"))) && (Cmp(name, Getattr(e, "name")) == 0)) {
419		  match = 1;
420		  break;
421		}
422	      }
423	      if (!match) {
424		Node *cc = c;
425		while (cc) {
426		  Node *cp = cc;
427		  if (classname) {
428		    Setattr(cp, "classname", classname);
429		  }
430		  Setattr(cp, "allocate:smartpointeraccess", "1");
431		  /* If constant, we have to be careful */
432		  if (isconst) {
433		    SwigType *decl = Getattr(cp, "decl");
434		    if (decl) {
435		      if (SwigType_isfunction(decl)) {	/* If method, we only add if it's a const method */
436			if (SwigType_isconst(decl)) {
437			  Append(methods, cp);
438			}
439		      } else {
440			Append(methods, cp);
441		      }
442		    } else {
443		      Append(methods, cp);
444		    }
445		  } else {
446		    Append(methods, cp);
447		  }
448		  cc = Getattr(cc, "sym:nextSibling");
449		}
450	      }
451	    }
452	  }
453	}
454      }
455
456      c = nextSibling(c);
457    }
458    /* Look for methods in base classes */
459    {
460      Node *bases = Getattr(cls, "bases");
461      int k;
462      for (k = 0; k < Len(bases); k++) {
463	smart_pointer_methods(Getitem(bases, k), methods, isconst);
464      }
465    }
466    /* Remove protected/private members */
467    {
468      for (int i = 0; i < Len(methods);) {
469	Node *n = Getitem(methods, i);
470	if (!is_public(n)) {
471	  Delitem(methods, i);
472	  continue;
473	}
474	i++;
475      }
476    }
477    return methods;
478  }
479
480  void mark_exception_classes(ParmList *p) {
481    while (p) {
482      SwigType *ty = Getattr(p, "type");
483      SwigType *t = SwigType_typedef_resolve_all(ty);
484      if (SwigType_isreference(t) || SwigType_ispointer(t) || SwigType_isarray(t)) {
485	Delete(SwigType_pop(t));
486      }
487      Node *c = Swig_symbol_clookup(t, 0);
488      if (c) {
489	if (!GetFlag(c, "feature:exceptionclass")) {
490	  SetFlag(c, "feature:exceptionclass");
491	}
492      }
493      p = nextSibling(p);
494      Delete(t);
495    }
496  }
497
498
499  void process_exceptions(Node *n) {
500    ParmList *catchlist = 0;
501    /* 
502       the "catchlist" attribute is used to emit the block
503
504       try {$action;} 
505       catch <list of catches>;
506
507       in emit.cxx
508
509       and is either constructued from the "feature:catches" feature
510       or copied from the node "throws" list.
511     */
512    String *scatchlist = Getattr(n, "feature:catches");
513    if (scatchlist) {
514      catchlist = Swig_cparse_parms(scatchlist, n);
515      if (catchlist) {
516	Setattr(n, "catchlist", catchlist);
517	mark_exception_classes(catchlist);
518	Delete(catchlist);
519      }
520    }
521    ParmList *throws = Getattr(n, "throws");
522    if (throws) {
523      /* if there is no explicit catchlist, we catch everything in the throws list */
524      if (!catchlist) {
525	Setattr(n, "catchlist", throws);
526      }
527      mark_exception_classes(throws);
528    }
529  }
530
531public:
532Allocate():
533  inclass(NULL), extendmode(0) {
534  }
535
536  virtual int top(Node *n) {
537    cplus_mode = PUBLIC;
538    inclass = 0;
539    extendmode = 0;
540    emit_children(n);
541    return SWIG_OK;
542  }
543
544  virtual int importDirective(Node *n) {
545    return emit_children(n);
546  }
547  virtual int includeDirective(Node *n) {
548    return emit_children(n);
549  }
550  virtual int externDeclaration(Node *n) {
551    return emit_children(n);
552  }
553  virtual int namespaceDeclaration(Node *n) {
554    return emit_children(n);
555  }
556  virtual int extendDirective(Node *n) {
557    extendmode = 1;
558    emit_children(n);
559    extendmode = 0;
560    return SWIG_OK;
561  }
562
563  virtual int classDeclaration(Node *n) {
564    Symtab *symtab = Swig_symbol_current();
565    Swig_symbol_setscope(Getattr(n, "symtab"));
566
567    if (!CPlusPlus) {
568      /* Always have default constructors/destructors in C */
569      Setattr(n, "allocate:default_constructor", "1");
570      Setattr(n, "allocate:default_destructor", "1");
571    }
572
573    if (Getattr(n, "allocate:visit"))
574      return SWIG_OK;
575    Setattr(n, "allocate:visit", "1");
576
577    /* Always visit base classes first */
578    {
579      List *bases = Getattr(n, "bases");
580      if (bases) {
581	for (int i = 0; i < Len(bases); i++) {
582	  Node *b = Getitem(bases, i);
583	  classDeclaration(b);
584	}
585      }
586    }
587
588    inclass = n;
589    String *kind = Getattr(n, "kind");
590    if (Strcmp(kind, "class") == 0) {
591      cplus_mode = PRIVATE;
592    } else {
593      cplus_mode = PUBLIC;
594    }
595
596    emit_children(n);
597
598    /* Check if the class is abstract via inheritance.   This might occur if a class didn't have
599       any pure virtual methods of its own, but it didn't implement all of the pure methods in
600       a base class */
601    if (!Getattr(n, "abstract") && is_abstract_inherit(n)) {
602      if (((Getattr(n, "allocate:public_constructor") || (!GetFlag(n, "feature:nodefault") && !Getattr(n, "allocate:has_constructor"))))) {
603	if (!GetFlag(n, "feature:notabstract")) {
604	  Node *na = Getattr(n, "abstract:firstnode");
605	  if (na) {
606	    Swig_warning(WARN_TYPE_ABSTRACT, Getfile(n), Getline(n),
607			 "Class '%s' might be abstract, " "no constructors generated,\n", SwigType_namestr(Getattr(n, "name")));
608	    Swig_warning(WARN_TYPE_ABSTRACT, Getfile(na), Getline(na), "Method %s might not be implemented.\n", Swig_name_decl(na));
609	    if (!Getattr(n, "abstract")) {
610	      List *abstract = NewList();
611	      Append(abstract, na);
612	      Setattr(n, "abstract", abstract);
613	      Delete(abstract);
614	    }
615	  }
616	}
617      }
618    }
619
620    if (!Getattr(n, "allocate:has_constructor")) {
621      /* No constructor is defined.  We need to check a few things */
622      /* If class is abstract.  No default constructor. Sorry */
623      if (Getattr(n, "abstract")) {
624	Delattr(n, "allocate:default_constructor");
625      }
626      if (!Getattr(n, "allocate:default_constructor")) {
627	/* Check base classes */
628	List *bases = Getattr(n, "allbases");
629	int allows_default = 1;
630
631	for (int i = 0; i < Len(bases); i++) {
632	  Node *n = Getitem(bases, i);
633	  /* If base class does not allow default constructor, we don't allow it either */
634	  if (!Getattr(n, "allocate:default_constructor") && (!Getattr(n, "allocate:default_base_constructor"))) {
635	    allows_default = 0;
636	  }
637	}
638	if (allows_default) {
639	  Setattr(n, "allocate:default_constructor", "1");
640	}
641      }
642    }
643    if (!Getattr(n, "allocate:has_copy_constructor")) {
644      if (Getattr(n, "abstract")) {
645	Delattr(n, "allocate:copy_constructor");
646      }
647      if (!Getattr(n, "allocate:copy_constructor")) {
648	/* Check base classes */
649	List *bases = Getattr(n, "allbases");
650	int allows_copy = 1;
651
652	for (int i = 0; i < Len(bases); i++) {
653	  Node *n = Getitem(bases, i);
654	  /* If base class does not allow copy constructor, we don't allow it either */
655	  if (!Getattr(n, "allocate:copy_constructor") && (!Getattr(n, "allocate:copy_base_constructor"))) {
656	    allows_copy = 0;
657	  }
658	}
659	if (allows_copy) {
660	  Setattr(n, "allocate:copy_constructor", "1");
661	}
662      }
663    }
664
665    if (!Getattr(n, "allocate:has_destructor")) {
666      /* No destructor was defined.  We need to check a few things here too */
667      List *bases = Getattr(n, "allbases");
668      int allows_destruct = 1;
669
670      for (int i = 0; i < Len(bases); i++) {
671	Node *n = Getitem(bases, i);
672	/* If base class does not allow default destructor, we don't allow it either */
673	if (!Getattr(n, "allocate:default_destructor") && (!Getattr(n, "allocate:default_base_destructor"))) {
674	  allows_destruct = 0;
675	}
676      }
677      if (allows_destruct) {
678	Setattr(n, "allocate:default_destructor", "1");
679      }
680    }
681
682    if (!Getattr(n, "allocate:has_assign")) {
683      /* No destructor was defined.  We need to check a few things here too */
684      List *bases = Getattr(n, "allbases");
685      int allows_assign = 1;
686
687      for (int i = 0; i < Len(bases); i++) {
688	Node *n = Getitem(bases, i);
689	/* If base class does not allow default destructor, we don't allow it either */
690	if (Getattr(n, "allocate:has_assign")) {
691	  allows_assign = !Getattr(n, "allocate:noassign");
692	}
693      }
694      if (!allows_assign) {
695	Setattr(n, "allocate:noassign", "1");
696      }
697    }
698
699    if (!Getattr(n, "allocate:has_new")) {
700      /* No destructor was defined.  We need to check a few things here too */
701      List *bases = Getattr(n, "allbases");
702      int allows_new = 1;
703
704      for (int i = 0; i < Len(bases); i++) {
705	Node *n = Getitem(bases, i);
706	/* If base class does not allow default destructor, we don't allow it either */
707	if (Getattr(n, "allocate:has_new")) {
708	  allows_new = !Getattr(n, "allocate:nonew");
709	}
710      }
711      if (!allows_new) {
712	Setattr(n, "allocate:nonew", "1");
713      }
714    }
715
716    /* Check if base classes allow smart pointers, but might be hidden */
717    if (!Getattr(n, "allocate:smartpointer")) {
718      Node *sp = Swig_symbol_clookup((char *) "operator ->", 0);
719      if (sp) {
720	/* Look for parent */
721	Node *p = parentNode(sp);
722	if (Strcmp(nodeType(p), "extend") == 0) {
723	  p = parentNode(p);
724	}
725	if (Strcmp(nodeType(p), "class") == 0) {
726	  if (GetFlag(p, "feature:ignore")) {
727	    Setattr(n, "allocate:smartpointer", Getattr(p, "allocate:smartpointer"));
728	  }
729	}
730      }
731    }
732
733    /* Only care about default behavior.  Remove temporary values */
734    Setattr(n, "allocate:visit", "1");
735    inclass = 0;
736    Swig_symbol_setscope(symtab);
737    return SWIG_OK;
738  }
739
740  virtual int accessDeclaration(Node *n) {
741    String *kind = Getattr(n, "kind");
742    if (Cmp(kind, "public") == 0) {
743      cplus_mode = PUBLIC;
744    } else if (Cmp(kind, "private") == 0) {
745      cplus_mode = PRIVATE;
746    } else if (Cmp(kind, "protected") == 0) {
747      cplus_mode = PROTECTED;
748    }
749    return SWIG_OK;
750  }
751
752  virtual int usingDeclaration(Node *n) {
753
754    Node *c = 0;
755    for (c = firstChild(n); c; c = nextSibling(c)) {
756      if (Strcmp(nodeType(c), "cdecl") == 0) {
757	process_exceptions(c);
758
759	if (inclass)
760	  class_member_is_defined_in_bases(c, inclass);
761      }
762    }
763
764    return SWIG_OK;
765  }
766
767  virtual int cDeclaration(Node *n) {
768
769    process_exceptions(n);
770
771    if (inclass) {
772      /* check whether the member node n is defined in class node in class's bases */
773      class_member_is_defined_in_bases(n, inclass);
774
775      /* Check to see if this is a static member or not.  If so, we add an attribute
776         cplus:staticbase that saves the current class */
777
778      if (checkAttribute(n, "storage", "static")) {
779	Setattr(n, "cplus:staticbase", inclass);
780      }
781
782      String *name = Getattr(n, "name");
783      if (cplus_mode != PUBLIC) {
784	if (Strcmp(name, "operator =") == 0) {
785	  /* Look for a private assignment operator */
786	  Setattr(inclass, "allocate:has_assign", "1");
787	  Setattr(inclass, "allocate:noassign", "1");
788	} else if (Strcmp(name, "operator new") == 0) {
789	  /* Look for a private new operator */
790	  Setattr(inclass, "allocate:has_new", "1");
791	  Setattr(inclass, "allocate:nonew", "1");
792	}
793      } else {
794	if (Strcmp(name, "operator =") == 0) {
795	  Setattr(inclass, "allocate:has_assign", "1");
796	} else if (Strcmp(name, "operator new") == 0) {
797	  Setattr(inclass, "allocate:has_new", "1");
798	}
799	/* Look for smart pointer operator */
800	if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) {
801	  /* Look for version with no parameters */
802	  Node *sn = n;
803	  while (sn) {
804	    if (!Getattr(sn, "parms")) {
805	      SwigType *type = SwigType_typedef_resolve_all(Getattr(sn, "type"));
806	      SwigType_push(type, Getattr(sn, "decl"));
807	      Delete(SwigType_pop_function(type));
808	      SwigType *base = SwigType_base(type);
809	      Node *sc = Swig_symbol_clookup(base, 0);
810	      if ((sc) && (Strcmp(nodeType(sc), "class") == 0)) {
811		if (SwigType_check_decl(type, "p.")) {
812		  /* Need to check if type is a const pointer */
813		  int isconst = 0;
814		  Delete(SwigType_pop(type));
815		  if (SwigType_isconst(type)) {
816		    isconst = !Getattr(inclass, "allocate:smartpointermutable");
817		    Setattr(inclass, "allocate:smartpointerconst", "1");
818		  }
819		  else {
820		    Setattr(inclass, "allocate:smartpointermutable", "1");
821		  }
822		  List *methods = smart_pointer_methods(sc, 0, isconst);
823		  Setattr(inclass, "allocate:smartpointer", methods);
824		  Setattr(inclass, "allocate:smartpointerbase", base);
825		} else {
826		  /* Hmmm.  The return value is not a pointer.  If the type is a value
827		     or reference.  We're going to chase it to see if another operator->()
828		     can be found */
829		  if ((SwigType_check_decl(type, "")) || (SwigType_check_decl(type, "r."))) {
830		    Node *nn = Swig_symbol_clookup((char *) "operator ->", Getattr(sc, "symtab"));
831		    if (nn) {
832		      Delete(base);
833		      Delete(type);
834		      sn = nn;
835		      continue;
836		    }
837		  }
838		}
839	      }
840	      Delete(base);
841	      Delete(type);
842	      break;
843	    }
844	  }
845	}
846      }
847    }
848    return SWIG_OK;
849  }
850
851  virtual int constructorDeclaration(Node *n) {
852    if (!inclass)
853      return SWIG_OK;
854    Parm *parms = Getattr(n, "parms");
855
856    process_exceptions(n);
857    if (!extendmode) {
858      if (!ParmList_numrequired(parms)) {
859	/* Class does define a default constructor */
860	/* However, we had better see where it is defined */
861	if (cplus_mode == PUBLIC) {
862	  Setattr(inclass, "allocate:default_constructor", "1");
863	} else if (cplus_mode == PROTECTED) {
864	  Setattr(inclass, "allocate:default_base_constructor", "1");
865	}
866      }
867      /* Class defines some kind of constructor. May or may not be public */
868      Setattr(inclass, "allocate:has_constructor", "1");
869      if (cplus_mode == PUBLIC) {
870	Setattr(inclass, "allocate:public_constructor", "1");
871      }
872    } else {
873      Setattr(inclass, "allocate:has_constructor", "1");
874      Setattr(inclass, "allocate:public_constructor", "1");
875    }
876
877
878    /* See if this is a copy constructor */
879    if (parms && (ParmList_numrequired(parms) == 1)) {
880      /* Look for a few cases. X(const X &), X(X &), X(X *) */
881      int copy_constructor = 0;
882      SwigType *type = Getattr(inclass, "name");
883      String *tn = NewStringf("r.q(const).%s", type);
884      String *cc = SwigType_typedef_resolve_all(tn);
885      SwigType *rt = SwigType_typedef_resolve_all(Getattr(parms, "type"));
886      if (SwigType_istemplate(type)) {
887	String *tmp = Swig_symbol_template_deftype(cc, 0);
888	Delete(cc);
889	cc = tmp;
890	tmp = Swig_symbol_template_deftype(rt, 0);
891	Delete(rt);
892	rt = tmp;
893      }
894      if (Strcmp(cc, rt) == 0) {
895	copy_constructor = 1;
896      } else {
897	Delete(cc);
898	cc = NewStringf("r.%s", Getattr(inclass, "name"));
899	if (Strcmp(cc, Getattr(parms, "type")) == 0) {
900	  copy_constructor = 1;
901	} else {
902	  Delete(cc);
903	  cc = NewStringf("p.%s", Getattr(inclass, "name"));
904	  String *ty = SwigType_strip_qualifiers(Getattr(parms, "type"));
905	  if (Strcmp(cc, ty) == 0) {
906	    copy_constructor = 1;
907	  }
908	  Delete(ty);
909	}
910      }
911      Delete(cc);
912      Delete(rt);
913      Delete(tn);
914
915      if (copy_constructor) {
916	Setattr(n, "copy_constructor", "1");
917	Setattr(inclass, "allocate:has_copy_constructor", "1");
918	if (cplus_mode == PUBLIC) {
919	  Setattr(inclass, "allocate:copy_constructor", "1");
920	} else if (cplus_mode == PROTECTED) {
921	  Setattr(inclass, "allocate:copy_base_constructor", "1");
922	}
923      }
924    }
925    return SWIG_OK;
926  }
927
928  virtual int destructorDeclaration(Node *n) {
929    (void) n;
930    if (!inclass)
931      return SWIG_OK;
932    if (!extendmode) {
933      Setattr(inclass, "allocate:has_destructor", "1");
934      if (cplus_mode == PUBLIC) {
935	Setattr(inclass, "allocate:default_destructor", "1");
936      } else if (cplus_mode == PROTECTED) {
937	Setattr(inclass, "allocate:default_base_destructor", "1");
938      }
939    } else {
940      Setattr(inclass, "allocate:has_destructor", "1");
941      Setattr(inclass, "allocate:default_destructor", "1");
942    }
943    return SWIG_OK;
944  }
945};
946
947void Swig_default_allocators(Node *n) {
948  if (!n)
949    return;
950  Allocate *a = new Allocate;
951  a->top(n);
952  delete a;
953}