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