/*
 * The parse tree transformation module for SIP.
 *
 * Copyright (c) 2004
 * 	Riverbank Computing Limited <info@riverbankcomputing.co.uk>
 * 
 * This file is part of SIP.
 * 
 * This copy of SIP is licensed for use under the terms of the SIP License
 * Agreement.  See the file LICENSE for more details.
 * 
 * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */


#include <stddef.h>
#include <string.h>
#include <stdlib.h>

#include "sip.h"


#define	pyToBasicInt(t)	((t) == short_type || (t) == ushort_type || \
			 (t) == enum_type || (t) == bool_type || \
	    		 (t) == int_type || (t) == uint_type || \
	    		 (t) == long_type || (t) == ulong_type)

#define	pyToInt(t)	(pyToBasicInt(t) || (t) == cint_type)

#define	pyToDouble(t)	(pyToBasicInt(t) || \
			 (t) == float_type || (t) == cfloat_type || \
			 (t) == double_type || (t) == cdouble_type)


static int supportedType(classDef *,overDef *,argDef *,int);
static int sameOverload(overDef *od1,overDef *od2);
static int sameVirtualHandler(virtHandlerDef *vhd1,virtHandlerDef *vhd2);
static int isSubClass(classDef *cc,classDef *pc);
static void ensureInput(classDef *,overDef *,argDef *);
static void defaultInput(argDef *);
static void defaultOutput(classDef *,overDef *,argDef *);
static void assignClassNrs(sipSpec *,moduleDef *,nodeDef *);
static void positionClass(classDef *);
static void addNodeToParent(nodeDef *,classDef *);
static void addAutoOverload(sipSpec *,classDef *,overDef *);
static void ifaceFileIsUsed(ifaceFileDef *,argDef *);
static void ifaceFilesAreUsed(ifaceFileDef *,overDef *);
static void ifaceFilesAreUsedByMethod(classDef *,memberDef *);
static void ifaceFilesAreUsedByOther(sipSpec *pt,overDef *od);
static void scopeDefaultValue(sipSpec *,classDef *,argDef *);
static void setHierarchy(sipSpec *,classDef *,classDef *,classList **);
static void transformCtors(sipSpec *,classDef *);
static void addDefaultCopyCtor(classDef *);
static void transformOverloads(sipSpec *,classDef *,overDef *);
static void transformVariableList(sipSpec *);
static void transformMappedTypes(sipSpec *);
static void getVisibleMembers(sipSpec *,classDef *);
static void getVirtuals(sipSpec *pt,classDef *cd);
static void getClassVirtuals(classDef *,classDef *);
static void addSignalSignatures(sipSpec *,classDef *);
static void addSlotArguments(sipSpec *pt,overDef *od);
static void addSignal(sipSpec *,signatureDef *);
static void resolveMappedTypeTypes(sipSpec *,mappedTypeDef *);
static void resolveCtorTypes(sipSpec *,classDef *,ctorDef *);
static void resolveFuncTypes(sipSpec *,classDef *,overDef *);
static void resolvePySigTypes(sipSpec *,classDef *,overDef *,signatureDef *,
			      int);
static void resolveVariableType(sipSpec *,varDef *);
static void fatalNoDefinedType(scopedNameDef *);
static void getBaseType(sipSpec *,classDef *,argDef *);
static void searchScope(sipSpec *,classDef *,scopedNameDef *,argDef *);
static void searchMappedTypes(sipSpec *,scopedNameDef *,argDef *);
static void searchTypedefs(sipSpec *,scopedNameDef *,argDef *);
static void searchEnums(sipSpec *,scopedNameDef *,argDef *);
static void searchClasses(sipSpec *,scopedNameDef *,argDef *);
static void appendToMRO(mroDef *,mroDef ***,classDef *);
static void filterVirtualHandlers(sipSpec *pt,moduleDef *mod);
static ifaceFileDef *getIfaceFile(argDef *ad);


/*
 * Transform the parse tree.
 */

void transform(sipSpec *pt)
{
	int nr;
	moduleListDef *mld;
	classDef *cd, *rev, **tail;
	classList *newl;
	overDef *od;
	mappedTypeDef *mtd;

	if (pt -> module -> name == NULL)
		fatal("No %%Module has been specified for the module\n");

	/*
	 * The class list has the main module's classes at the front and the
	 * ones from the module at the most nested %Import at the end.  This
	 * affects some of the following algorithms, eg. when assigning class
	 * numbers.  We have to have consistency whenever a module is used.  To
	 * achieve this we reverse the order of the classes.
	 */
	rev = NULL;
	cd = pt -> classes;

	while (cd != NULL)
	{
		classDef *next = cd -> next;

		cd -> next = rev;
		rev = cd;

		cd = next;
	}

	pt -> classes = rev;

	/*
	 * Give each module directly imported from the main module a number
	 * that corresponds to its index in the main module's import table.
	 */
	nr = 0;

	for (mld = pt -> module -> imports; mld != NULL; mld = mld -> next)
		mld -> module -> modulenr = nr++;

	/* Check each class has been defined. */
	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		if (cd -> iff -> module == NULL)
		{
			fatalScopedName(cd -> iff -> fqname);
			fatal(" has not been defined\n");
		}

	/*
	 * Set the super-class hierarchy for each class and re-order the list
	 * of classes so that no class appears before a super class or an
	 * enclosing scope class.
	 */
	newl = NULL;

	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		setHierarchy(pt,cd,cd,&newl);

	/* Replace the old list with the new one. */
	tail = &pt -> classes;

	while (newl != NULL)
	{
		classList *cl = newl;

		*tail = cl -> cd;
		tail = &cl -> cd -> next;

		newl = cl -> next;
		free(cl);
	}

	*tail = NULL;

	/* Transform variables and global functions. */
	transformVariableList(pt);
	transformOverloads(pt,NULL,pt -> overs);

	/* Transform class ctors and functions. */
	if (!pt -> genc)
		for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		{
			transformCtors(pt,cd);
			transformOverloads(pt,cd,cd -> overs);
		}

	/* Transform mapped types based on templates. */
	transformMappedTypes(pt);

	/* Add default ctors now that the argument types are resolved. */
	if (!pt -> genc)
        	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
                	if (!isOpaque(cd))
                        	addDefaultCopyCtor(cd);

	/*
	 * Go through each class and add it to it's defining module's tree of
	 * classes.  The tree reflects the namespace hierarchy.
	 */
	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		addNodeToParent(&cd -> iff -> module -> root,cd);

	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		positionClass(cd);

	/*
	 * Assign module specific class numbers for this module and any we
	 * import directly.
	 */
	assignClassNrs(pt,pt -> module,&pt -> module -> root);

	for (mld = pt -> module -> imports; mld != NULL; mld = mld -> next)
		assignClassNrs(pt,mld -> module,&mld -> module -> root);

	/* Add any automatically generated methods. */
	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		for (od = cd -> overs; od != NULL; od = od -> next)
			if (isAutoGen(od))
				addAutoOverload(pt,cd,od);

	/* Allocate mapped types numbers. */
	for (mtd = pt -> mappedtypes; mtd != NULL; mtd = mtd -> next)
		mtd -> mappednr = mtd -> iff -> module -> nrmappedtypes++;

	/* Generate the different class views. */
	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
	{
		ifaceFileDef *iff = cd -> iff;

		if (iff -> type == class_iface)
		{
			/* Get the list of visible member functions. */
			getVisibleMembers(pt,cd);

			if (iff -> module == pt -> module)
				addSignalSignatures(pt,cd);

			/* Get the virtual members. */
			if (isComplex(cd))
				getVirtuals(pt,cd);
		}
		else if (iff -> type == namespace_iface && iff -> module == pt -> module)
		{
			memberDef *md;

			for (od = cd -> overs; od != NULL; od = od -> next)
				addSlotArguments(pt,od);

			for (md = cd -> members; md != NULL; md = md -> next)
				ifaceFilesAreUsedByMethod(cd,md);
		}
	}

        /*
	 * In case there are any global functions with slot arguments or that
	 * need external interface files.
	 */
	for (od = pt -> overs; od != NULL; od = od -> next)
	{
		addSlotArguments(pt,od);
		ifaceFilesAreUsedByOther(pt,od);
	}

	/*
	 * Remove redundant virtual handlers.  It's important that earlier,
	 * ie. those at the deepest level of %Import, are done first.
	 */
	for (mld = pt -> module -> imports; mld != NULL; mld = mld -> next)
		filterVirtualHandlers(pt,mld -> module);

	filterVirtualHandlers(pt,pt -> module);
}


/*
 * Go through the virtual handlers filtering those can duplicate earlier ones.
 * Make sure each virtual is numbered within its module, and according to their
 * position in the list (ignoring duplicates).
 */
static void filterVirtualHandlers(sipSpec *pt,moduleDef *mod)
{
	virtHandlerDef *vhd;

	for (vhd = mod -> virthandlers; vhd != NULL; vhd = vhd -> next)
	{
		virtHandlerDef *best, *best_thismod, *hd;

		best = best_thismod = NULL;

		/*
		 * If this has handwritten code then we will want to use it.
		 * Otherwise, look for a handler in earlier modules.
		 */
		if (vhd -> virtcode == NULL)
		{
			moduleListDef *mld;

			for (mld = pt -> module -> imports; mld != NULL && mld -> module != mod; mld = mld -> next)
			{
				for (hd = mld -> module -> virthandlers; hd != NULL; hd = hd -> next)
					if (sameVirtualHandler(vhd,hd))
					{
						best = hd;
						break;
					}

				/*
				 * No need to check later modules as this will
				 * either be the right one, or a duplicate of
				 * the right one.
				 */
				if (best != NULL)
					break;
			}
		}

		/*
		 * Find the best candidate in this module in case we want to
		 * give it our handwritten code.
		 */
		for (hd = mod -> virthandlers; hd != vhd; hd = hd -> next)
			if (sameVirtualHandler(vhd,hd))
			{
				best_thismod = hd;
				break;
			}

		/*
		 * We don't use this one if it doesn't have virtual code and
		 * there is an alternative, or if it does have virtual code and
		 * there is already an alternative in the same module which
		 * doesn't have virtual code.
		 */
		if ((vhd -> virtcode == NULL && (best != NULL || best_thismod != NULL)) ||
		    (vhd -> virtcode != NULL && best_thismod != NULL && best_thismod -> virtcode == NULL))
		{
			virtHandlerDef *saved;

			/*
			 * If the alternative is in the same module and we
			 * have virtual code then give it to the alternative.
			 * Note that there is a bug here.  If there are three
			 * handlers, the first without code and the second and
			 * third with code then which code is transfered to the
			 * first is down to luck.  We should really only
			 * transfer code to methods that are known to be
			 * re-implementations - just having the same signature
			 * isn't enough.
			 */
			if (best_thismod != NULL)
			{
				if (best_thismod -> virtcode == NULL && vhd -> virtcode != NULL)
				{
					best_thismod -> virtcode = vhd -> virtcode;
					resetIsDuplicateVH(best_thismod);
				}

				best = best_thismod;
			}

			/* Use the better one in place of this one. */
			saved = vhd -> next;
			*vhd = *best;
			setIsDuplicateVH(vhd);
			vhd -> next = saved;
		}
		else
			vhd -> virthandlernr = mod -> nrvirthandlers++;
	}
}


/*
 * Add an overload that is automatically generated (typically by Qt's moc).
 */
static void addAutoOverload(sipSpec *pt,classDef *autocd,overDef *autood)
{
	classDef *cd;

	/* Find every class that has this one in its hierarchy. */

	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
	{
		mroDef *mro;

		if (cd == autocd)
			continue;

		for (mro = cd -> mro; mro != NULL; mro = mro -> next)
			if (mro -> cd == autocd)
			{
				memberDef *md;
				overDef *od;

				/* Another overload may already exist. */

				for (md = cd -> members; md != NULL; md = md -> next)
					if (md -> pyname == autood -> common -> pyname)
						break;

				if (md == NULL)
				{
					md = sipMalloc(sizeof (memberDef));

					md -> pyname = autood -> common -> pyname;
					md -> memberflags = autood -> common -> memberflags;
					md -> slot = autood -> common -> slot;
					md -> module = cd -> iff -> module;
					md -> next = cd -> members;
					cd -> members = md;
				}

				od = sipMalloc(sizeof (overDef));

				*od = *autood;
				od -> common = md;
				od -> next = cd -> overs;
				cd -> overs = od;

				resetIsAutoGen(od);

				if (cd -> iff -> module == pt -> module)
					setIsUsedName(md -> pyname);

				break;
			}
	}
}


/*
 * Set the complete hierarchy for a class.
 */
static void setHierarchy(sipSpec *pt,classDef *base,classDef *cd,
			 classList **head)
{
	mroDef **tailp = &cd -> mro;

	/* See if it has already been done. */
	if (cd -> mro != NULL)
		return;

	if (cd -> ecd != NULL)
		setHierarchy(pt,base,cd -> ecd,head);

	if (cd -> iff -> type == class_iface)
	{
		classList *cl;

		/* The first thing is itself. */
		appendToMRO(cd -> mro,&tailp,cd);

		if (cd -> convtosubcode != NULL)
			cd -> subbase = cd;

		/* Now do it's superclasses. */
		for (cl = cd -> supers; cl != NULL; cl = cl -> next)
		{
			mroDef *mro;

			/*
			 * Make sure the super-class's hierarchy has been done.
			 */
			setHierarchy(pt,base,cl -> cd,head);

			/* Append the super-classes hierarchy. */
			for (mro = cl -> cd -> mro; mro != NULL; mro = mro -> next)
			{
				appendToMRO(cd -> mro,&tailp,mro -> cd);

				/* Ripple through the complex flag. */
				if (isComplex(mro -> cd))
					setIsComplex(cd);

				/*
				 * Ensure that the sub-class base class is the
				 * furthest up the hierarchy.
				 */
				if (mro -> cd -> subbase != NULL)
					cd -> subbase = mro -> cd -> subbase;
			}
		}
	}

	/* We can't derive from classes with private dtors. */
	if (isPrivateDtor(cd))
		resetIsComplex(cd);

	/* Add it to the new list. */
	appendToClassList(head,cd);
}


/*
 * Append a class definition to an mro list
 */
static void appendToMRO(mroDef *head,mroDef ***tailp,classDef *cd)
{
	mroDef *mro, *new;

	new = sipMalloc(sizeof (mroDef));

	new -> cd = cd;
	new -> mroflags = 0;
	new -> next = NULL;

	/* See if it is a duplicate. */

	for (mro = head; mro != NULL; mro = mro -> next)
		if (mro -> cd == cd)
		{
			setIsDuplicateSuper(new);

			if (!isDuplicateSuper(mro))
				setHasDuplicateSuper(mro);

			break;
		}

	/* Append to the list and update the tail pointer. */
	**tailp = new;
	*tailp = &new -> next;
}


/*
 * Transform the data types for mapped types based on a template.
 */
static void transformMappedTypes(sipSpec *pt)
{
	mappedTypeDef *mt;

	for (mt = pt -> mappedtypes; mt != NULL; mt = mt -> next)
	{
		/* Nothing to do if this isn't template based. */

		if (mt -> type.atype == template_type)
			resolveMappedTypeTypes(pt,mt);
	}
}


/*
 * Transform the data types for a list of ctors.
 */
static void transformCtors(sipSpec *pt,classDef *cd)
{
	ctorDef *ct;

	for (ct = cd -> ctors; ct != NULL; ct = ct -> next)
		resolveCtorTypes(pt,cd,ct);
}


/*
 * Add a default copy ctor is required.
 */
static void addDefaultCopyCtor(classDef *cd)
{
	ctorDef *copyct;
	mroDef *mro;

	/* See if there is a private copy ctor in the hierarchy. */
 
	copyct = NULL;
 
	for (mro = cd -> mro; mro != NULL; mro = mro -> next)
	{
		ctorDef *ct;

		if (isDuplicateSuper(mro))
			continue;

		for (ct = mro -> cd -> ctors; ct != NULL; ct = ct -> next)
		{
			argDef *ad = &ct -> pysig.args[0];
 
			/* See if is a copy ctor. */
			if (ct -> pysig.nrArgs != 1 || ad -> nrderefs != 0 ||
			    !isReference(ad) || ad -> atype != class_type ||
			    ad -> u.cd != mro -> cd)
				continue;

			/* Stop now if the copy ctor is private. */
			if (isPrivateCtor(ct))
				return;
 
			/*
			 * Remember if it's in the class we are dealing with.
			 */
			if (mro == cd -> mro)
				copyct = ct;
 
			break;
		}
	}
 
	if (copyct == NULL)
	{
		ctorDef **tailp;
 
		/* Create a default public copy ctor. */
 
		copyct = sipMalloc(sizeof (ctorDef));
 
		copyct -> ctorflags = SECT_IS_PUBLIC;
		copyct -> pysig.nrArgs = 1;
		copyct -> pysig.args[0].atype = class_type;
		copyct -> pysig.args[0].u.cd = cd;
		copyct -> pysig.args[0].argflags = (ARG_IS_REF | ARG_IS_CONST | ARG_IN);
		copyct -> pysig.args[0].nrderefs = 0;
		copyct -> pysig.args[0].defval = NULL;
 
		copyct -> cppsig = &copyct -> pysig;
		copyct -> exceptions = NULL;
		copyct -> methodcode = NULL;
		copyct -> prehook = NULL;
		copyct -> posthook = NULL;
		copyct -> next = NULL;
 
		/* Append it to the list. */
		for (tailp = &cd -> ctors; *tailp != NULL; tailp = &(*tailp) -> next)
			;
 
		*tailp = copyct;
	}
}


/*
 * Transform the data types for a list of overloads.
 */

static void transformOverloads(sipSpec *pt,classDef *scope,overDef *overs)
{
	overDef *od;

	for (od = overs; od != NULL; od = od -> next)
		resolveFuncTypes(pt,scope,od);
}


/*
 * Transform the data types for the variables.
 */
static void transformVariableList(sipSpec *pt)
{
	varDef *vd;

	for (vd = pt -> vars; vd != NULL; vd = vd -> next)
		resolveVariableType(pt,vd);
}


/*
 * Set the list of visible member functions for a class.
 */
static void getVisibleMembers(sipSpec *pt,classDef *cd)
{
	mroDef *mro;

	cd -> visible = NULL;

	for (mro = cd -> mro; mro != NULL; mro = mro -> next)
	{
		memberDef *md;
		classDef *mrocd;

		if (isDuplicateSuper(mro))
			continue;

		mrocd = mro -> cd;

		/*
		 * If the base class is in the main module, see if it needs to
		 * publish any protected enums.
		 */
		if (cd -> iff -> module == pt -> module)
		{
			enumDef *ed;

			for (ed = pt -> enums; ed != NULL; ed = ed -> next)
			{
				/* Skip unless we are the publisher. */
				if (ed -> pcd != mrocd)
					continue;

				/*
				 * If we are not in the main module then the
				 * base class must take over as the publisher.
				 */
				if (mrocd -> iff -> module != pt -> module)
					ed -> pcd = cd;
			}
		}

		for (md = mrocd -> members; md != NULL; md = md -> next)
		{
			visibleList *vl;

			if (md -> slot != no_slot)
			{
				if (mrocd == cd)
					ifaceFilesAreUsedByMethod(cd,md);

				continue;
			}

			/*
			 * See if it is already in the list.  This has the
			 * desired side effect of eliminating any functions
			 * that have an implementation closer to this class in
			 * the hierarchy.  This is the only reason to define
			 * private functions.
			 */
			for (vl = cd -> visible; vl != NULL; vl = vl -> next)
				if (vl -> m -> pyname == md -> pyname)
					break;

			/* See if it is a new member function. */

			if (vl == NULL)
			{
				overDef *od;

				/* We probably want the name. */
				setIsUsedName(md -> pyname);

				vl = sipMalloc(sizeof (visibleList));

				vl -> m = md;
				vl -> cd = mrocd;
				vl -> next = cd -> visible;

				cd -> visible = vl;

				for (od = mrocd -> overs; od != NULL; od = od -> next)
					if (od -> common == md)
						ifaceFilesAreUsed(cd -> iff,od);
			}
		}
	}
}


/*
 * Get all the virtuals for a particular class.
 */
static void getVirtuals(sipSpec *pt,classDef *cd)
{
	mroDef *mro;

	for (mro = cd -> mro; mro != NULL; mro = mro -> next)
	{
		if (isDuplicateSuper(mro))
			continue;

		getClassVirtuals(cd,mro -> cd);
	}

	/*
	 * If this class is defined in the main module make sure we get the API
	 * files for all the visible virtuals.
	 */
	if (cd -> iff -> module == pt -> module)
	{
		virtOverDef *vod;

		for (vod = cd -> vmembers; vod != NULL; vod = vod -> next)
		{
			/* Make sure we get the name. */
			setIsUsedName(vod -> o.common -> pyname);

			ifaceFilesAreUsed(cd -> iff,&vod -> o);
		}
	}
}


/*
 * Get the list of visible virtual functions for a class.
 */
static void getClassVirtuals(classDef *base,classDef *cd)
{
	overDef *od;

	for (od = cd -> overs; od != NULL; od = od -> next)
	{
		virtOverDef **tailp, *vod;

		if (!isVirtual(od) || isPrivate(od))
			continue;

		/*
		 * See if a virtual of this name and signature is already in
		 * the list.
		 */
		for (tailp = &base -> vmembers; (vod = *tailp) != NULL; tailp = &vod -> next)
			if (strcmp(vod -> o.cppname,od -> cppname) == 0 && sameOverload(&vod -> o,od))
				break;
 
		if (vod == NULL)
		{
			/*
			 * See if there is a non-virtual reimplementation
			 * nearer in the class hierarchy.
			 */

			mroDef *mro;
			classDef *scope = NULL;
			overDef *eod;

			for (mro = base -> mro; mro -> cd != cd; mro = mro -> next)
			{
				if (isDuplicateSuper(mro))
					continue;

				/*
				 * Ignore classes that are on a different
				 * branch of the class hierarchy.
				 */
				if (!isSubClass(mro -> cd,cd))
					continue;

				for (eod = mro -> cd -> overs; eod != NULL; eod = eod -> next)
					if (strcmp(eod -> cppname,od -> cppname) == 0 && sameSignature(eod -> cppsig,od -> cppsig,TRUE) && isConst(eod) == isConst(od) && !isAbstract(eod))
					{
						scope = mro -> cd;
						break;
					}

				if (scope != NULL)
					break;
			}

			vod = sipMalloc(sizeof (virtOverDef));
 
			vod -> o = *od;
			vod -> scope = (scope != NULL ? scope : cd);
			vod -> next = NULL;
 
			*tailp = vod;

			/*
			 * If there was a nearer reimplementation then we use
			 * its protection and abstract flags.
			 */
			if (scope != NULL)
			{
				vod -> o.overflags &= ~(SECT_MASK | OVER_IS_ABSTRACT);
				vod -> o.overflags |= (SECT_MASK | OVER_IS_ABSTRACT) & eod -> overflags;
			}
		}
	}
}


/*
 * Return TRUE is a class is derived from another.
 */
static int isSubClass(classDef *cc,classDef *pc)
{
	mroDef *mro;

	/*
	 * In other words, does the parent class appear in the child class's
	 * MRO list.
	 */
	for (mro = cc -> mro; mro != NULL; mro = mro -> next)
		if (mro -> cd == pc)
			return TRUE;

	return FALSE;
}


/*
 * Resolve the types of a mapped type based on a template.
 */
static void resolveMappedTypeTypes(sipSpec *pt,mappedTypeDef *mt)
{
	int a;
	templateDef *td = mt -> type.u.td;

	for (a = 0; a < td -> types.nrArgs; ++a)
	{
		getBaseType(pt,NULL,&td -> types.args[a]);

		ifaceFileIsUsed(mt -> iff,&td -> types.args[a]);
	}
}


/*
 * Resolve the types of a ctor.
 */
static void resolveCtorTypes(sipSpec *pt,classDef *scope,ctorDef *ct)
{
	int a;

	/* Handle any C++ signature. */
	if (ct -> cppsig != &ct -> pysig)
		for (a = 0; a < ct -> cppsig -> nrArgs; ++a)
			getBaseType(pt,scope,&ct -> cppsig -> args[a]);
 
	/* Handle the Python signature. */
	for (a = 0; a < ct -> pysig.nrArgs; ++a)
	{
		argDef *ad = &ct -> pysig.args[a];

		getBaseType(pt,scope,ad);

		if (!supportedType(scope,NULL,ad,FALSE) && (ct -> cppsig == &ct -> pysig || ct -> methodcode == NULL))
		{
			fatalScopedName(scope -> iff -> fqname);
			fatal(" unsupported ctor argument type - provide %%MethodCode and a C++ signature\n");
		}

		ifaceFileIsUsed(scope -> iff,ad);
		scopeDefaultValue(pt,scope,ad);
	}
}


/*
 * Resolve the types of a function.
 */
static void resolveFuncTypes(sipSpec *pt,classDef *scope,overDef *od)
{
	argDef *res;

	/* Handle any C++ signature. */
	if (od -> cppsig != &od -> pysig)
	{
		int a;

		getBaseType(pt,scope,&od -> cppsig -> result);

		for (a = 0; a < od -> cppsig -> nrArgs; ++a)
			getBaseType(pt,scope,&od -> cppsig -> args[a]);
	}
 
	/* Handle the Python signature. */
	resolvePySigTypes(pt,scope,od,&od -> pysig,isSignal(od));

	/* These slots must return int. */
	res = &od -> pysig.result;

	if (od -> common -> slot == len_slot ||
	    od -> common -> slot == cmp_slot ||
	    od -> common -> slot == contains_slot ||
	    od -> common -> slot == nonzero_slot)
		if (res -> atype != int_type || res -> nrderefs != 0 ||
		    isReference(res) || isConstArg(res))
			fatal("%s slots must return int\n",od -> common -> pyname -> text);

	/* These slots must return void. */
	if (od -> common -> slot == setitem_slot ||
	    od -> common -> slot == delitem_slot)
		if (res -> atype != void_type || res -> nrderefs != 0 ||
		    isReference(res) || isConstArg(res))
			fatal("%s slots must return void\n",od -> common -> pyname -> text);
}


/*
 * Resolve the types of a Python signature.
 */
static void resolvePySigTypes(sipSpec *pt,classDef *scope,overDef *od,
			      signatureDef *pysig,int issignal)
{
	int a;
	argDef *res = &pysig -> result;

	if (res -> atype != void_type || res -> nrderefs != 0)
	{
		if (issignal)
		{
			if (scope != NULL)
			{
				fatalScopedName(scope -> iff -> fqname);
				fatal("::");
			}

			fatal("%s() signals must return void\n",od -> cppname);
		}

		getBaseType(pt,scope,res);

		/* Results must be simple. */
		if (!supportedType(scope,od,res,FALSE) && (od -> cppsig == &od -> pysig || od -> methodcode == NULL))
		{
			if (scope != NULL)
			{
				fatalScopedName(scope -> iff -> fqname);
				fatal("::");
			}

			fatal("%s() unsupported function return type - provide %%MethodCode and a %s signature\n",od -> cppname,(pt -> genc ? "C" : "C++"));
		}
	}

	for (a = 0; a < pysig -> nrArgs; ++a)
	{
		argDef *ad = &pysig -> args[a];

		getBaseType(pt,scope,ad);

		if (ad -> atype == slotcon_type)
			resolvePySigTypes(pt,scope,od,ad -> u.sa,TRUE);

		/*
		 * Note signal arguments are restricted in their types because
		 * we don't (yet) support handwritten code for them.
		 */
		if (issignal)
		{
			if (!supportedType(scope,od,ad,FALSE))
			{
				if (scope != NULL)
				{
					fatalScopedName(scope -> iff -> fqname);
					fatal("::");
				}

				fatal("%s() unsupported signal argument type\n");
			}
		}
		else if (!supportedType(scope,od,ad,TRUE) && (od -> cppsig == &od -> pysig || od -> methodcode == NULL || (isVirtual(od) && od -> virthandler -> virtcode == NULL)))
		{
			if (scope != NULL)
			{
				fatalScopedName(scope -> iff -> fqname);
				fatal("::");
			}

			if (isVirtual(od))
				fatal("%s() unsupported function argument type - provide %%Method code, a valid %%VirtualCatcherCode and a valid C++ signature\n",od -> cppname);

			fatal("%s() unsupported function argument type - provide %%Method code and a valid %s signature\n",od -> cppname,(pt -> genc ? "C" : "C++"));
		}

		if (scope != NULL)
			scopeDefaultValue(pt,scope,ad);
	}
}


/*
 * Resolve the type of a variable.
 */
static void resolveVariableType(sipSpec *pt,varDef *vd)
{
	int bad = TRUE;
	argDef *vtype = &vd -> type;

	getBaseType(pt,vd -> ecd,vtype);

	switch (vtype -> atype)
	{
	case mapped_type:
	case class_type:
		/* Class, Class & and Class * are supported. */

		if (vtype -> nrderefs <= 1)
			bad = FALSE;
		break;

	case ustring_type:
	case string_type:
		/* (unsigned) char, (unsigned) char * are supported. */

		if (!isReference(vtype) && vtype -> nrderefs <= 1)
			bad = FALSE;
		break;

	case float_type:
	case double_type:
	case enum_type:
	case bool_type:
	case ushort_type:
	case short_type:
	case uint_type:
	case cint_type:
	case int_type:
	case ulong_type:
	case long_type:
	case pyobject_type:
		/* These are supported without pointers or references. */

		if (!isReference(vtype) && vtype -> nrderefs == 0)
			bad = FALSE;
		break;

	case struct_type:
	case void_type:
		/* A simple pointer is supported. */

		if (!isReference(vtype) && vtype -> nrderefs == 1)
			bad = FALSE;
		break;
	}

	if (bad)
	{
		fatalScopedName(vd -> fqname);
		fatal(" has an unsupported type\n");
	}
 
	if (vtype -> atype != class_type && vd -> accessfunc != NULL)
	{
		fatalScopedName(vd -> fqname);
		fatal(" has %%AccessCode but isn't a class instance\n");
	}

	if (vd -> ecd != NULL)
		ifaceFileIsUsed(vd -> ecd -> iff,vtype);

	/*
	 * Instance variables or static class variables (unless they are
	 * constants) need a handler.
	 */
	if (vd -> ecd != NULL && vd -> accessfunc == NULL &&
	    (!isStaticVar(vd) || vtype -> nrderefs != 0 || !isConstArg(vtype)))
	{
		setNeedsHandler(vd);
		setHasVarHandlers(vd -> ecd);
	}
}



/*
 * Add any signal signatures defined by a class to the list that the module's
 * proxy needs to deal with.
 */
static void addSignalSignatures(sipSpec *pt,classDef *cd)
{
	visibleList *vl;

	for (vl = cd -> visible; vl != NULL; vl = vl -> next)
	{
		overDef *od;

		for (od = vl -> cd -> overs; od != NULL; od = od -> next)
			if (od -> common != vl -> m)
			{
				if (isSignal(od))
					addSignal(pt,od -> cppsig);

				addSlotArguments(pt,od);
			}
	}
}


/*
 * Add any argument slots to the list of module signals.
 */
static void addSlotArguments(sipSpec *pt,overDef *od)
{
	int a;

	for (a = 0; a < od -> cppsig -> nrArgs; ++a)
		if (od -> cppsig -> args[a].atype == slotcon_type)
			addSignal(pt,od -> cppsig -> args[a].u.sa);
}


/*
 * Add a signature to the list of signals that might be emitted by this module.
 */
static void addSignal(sipSpec *pt,signatureDef *sd)
{
	signatureList *sl;

	for (sl = pt -> sigargs; sl != NULL; sl = sl -> next)
		if (sameSignature(sd,sl -> sd,TRUE))
			break;
 
	/* Add if it is a new signature. */
	if (sl == NULL)
	{
		sl = sipMalloc(sizeof (signatureList));
		sl -> sd = sd;
		sl -> next = pt -> sigargs;
 
		pt -> sigargs = sl;
	}
}


/*
 * See if a type is supported by the generated code.
 */
static int supportedType(classDef *cd,overDef *od,argDef *ad,int outputs)
{
	switch (ad -> atype)
	{
	case signal_type:
	case slot_type:
	case rxcon_type:
	case rxdis_type:
	case slotcon_type:
	case slotdis_type:
	case qobject_type:
		/* These can only appear in argument lists without * or &. */

		ensureInput(cd,od,ad);
		return TRUE;

	case ustring_type:
	case string_type:
		if (isReference(ad))
		{
			if (outputs && ad -> nrderefs <= 1)
			{
				defaultOutput(cd,od,ad);
				return TRUE;
			}
		}
		else if (ad -> nrderefs == 0)
		{
			ensureInput(cd,od,ad);
			return TRUE;
		}
		else if (ad -> nrderefs == 1)
		{
			if (outputs)
				defaultInput(ad);
			else
				ensureInput(cd,od,ad);

			return TRUE;
		}
		else if (ad -> nrderefs == 2 && outputs)
		{
			defaultOutput(cd,od,ad);
			return TRUE;
		}

		break;

	case float_type:
	case double_type:
	case enum_type:
	case bool_type:
	case ushort_type:
	case short_type:
	case uint_type:
	case cint_type:
	case int_type:
	case ulong_type:
	case long_type:
	case pyobject_type:
	case pytuple_type:
	case pylist_type:
	case pydict_type:
	case pycallable_type:
	case pyslice_type:
		if (isReference(ad))
		{
			if (ad -> nrderefs == 0 && outputs)
			{
				defaultOutput(cd,od,ad);
				return TRUE;
			}
		}
		else if (ad -> nrderefs == 0)
		{
			ensureInput(cd,od,ad);
			return TRUE;
		}
		else if (ad -> nrderefs == 1 && outputs)
		{
			defaultOutput(cd,od,ad);
			return TRUE;
		}

		break;

	case mapped_type:
	case class_type:
		if (isReference(ad))
		{
			if (ad -> nrderefs == 0)
			{
				defaultInput(ad);
				return TRUE;
			}
			else if (ad -> nrderefs == 1 && outputs)
			{
				defaultOutput(cd,od,ad);
				return TRUE;
			}
		}
		else if (ad -> nrderefs == 0)
		{
			ensureInput(cd,od,ad);
			return TRUE;
		}
		else if (ad -> nrderefs == 1)
		{
			if (outputs)
				defaultInput(ad);
			else
				ensureInput(cd,od,ad);

			return TRUE;
		}
		else if (ad -> nrderefs == 2 && outputs)
		{
			defaultOutput(cd,od,ad);
			return TRUE;
		}

		break;

	case struct_type:
	case void_type:
		if (isReference(ad))
		{
			if (ad -> nrderefs == 1 && outputs)
			{
				defaultOutput(cd,od,ad);
				return TRUE;
			}
		}
		else if (ad -> nrderefs == 1)
		{
			ensureInput(cd,od,ad);
			return TRUE;
		}
		else if (ad -> nrderefs == 2 && outputs)
		{
			defaultOutput(cd,od,ad);
			return TRUE;
		}

		break;
	}

	/* Unsupported if we got this far. */
	return FALSE;
}


/*
 * Ensure the direction of an argument is an input.
 */
static void ensureInput(classDef *cd,overDef *od,argDef *ad)
{
	if (isOutArg(ad))
	{
		if (cd != NULL)
		{
			fatalScopedName(cd -> iff -> fqname);
			fatal("::");
		}

		if (od != NULL)
			fatal("%s",od -> cppname);

		fatal("() invalid argument type for /Out/\n");
	}

	setIsInArg(ad);
}


/*
 * Default the direction of an argument to an input.
 */
static void defaultInput(argDef *ad)
{
	if (!isInArg(ad) && !isOutArg(ad))
		setIsInArg(ad);
}


/*
 * Default the direction of an argument to an output unless the argument is
 * const.
 */
static void defaultOutput(classDef *cd,overDef *od,argDef *ad)
{
	if (isOutArg(ad))
	{
		if (isConstArg(ad))
		{
			if (cd != NULL)
			{
				fatalScopedName(cd -> iff -> fqname);
				fatal("::");
			}

			if (od != NULL)
				fatal("%s",od -> cppname);

			fatal("() const argument cannot have /Out/ specified\n");
		}
	}
	else if (!isInArg(ad))
		if (isConstArg(ad))
			setIsInArg(ad);
		else
			setIsOutArg(ad);
}


/*
 * Put a scoped name to stderr.
 */
void fatalScopedName(scopedNameDef *snd)
{
	while (snd != NULL)
	{
		fatal("%s",snd -> name);

		snd = snd -> next;

		if (snd != NULL)
			fatal("::");
	}
}


/*
 * Compare two overloads and return TRUE if they are the same.
 */
static int sameOverload(overDef *od1,overDef *od2)
{
	/* They must both be const, or both not. */
	if (isConst(od1) != isConst(od2))
		return FALSE;

	return sameSignature(&od1 -> pysig,&od2 -> pysig,TRUE);
}


/*
 * Compare two virtual handlers and return TRUE if they are the same.
 */
static int sameVirtualHandler(virtHandlerDef *vhd1,virtHandlerDef *vhd2)
{
	if (isTransferVH(vhd1) != isTransferVH(vhd2))
		return FALSE;

	if (!sameArgType(&vhd1 -> sd -> result,&vhd2 -> sd -> result,TRUE))
		return FALSE;

	return sameSignature(vhd1 -> sd,vhd2 -> sd,TRUE);
}


/*
 * Compare two signatures and return TRUE if they are the same.
 */
int sameSignature(signatureDef *sd1,signatureDef *sd2,int strict)
{
	int a;

	if (strict)
	{
		/* The number of arguments must be the same. */
		if (sd1 -> nrArgs != sd2 -> nrArgs)
			return FALSE;
	}
	else
	{
		int na1, na2;

		/* We only count the compulsory arguments. */
		na1 = 0;

		for (a = 0; a < sd1 -> nrArgs; ++a)
		{
			if (sd1 -> args[a].defval != NULL)
				break;

			++na1;
		}

		na2 = 0;

		for (a = 0; a < sd2 -> nrArgs; ++a)
		{
			if (sd2 -> args[a].defval != NULL)
				break;

			++na2;
		}

		if (na1 != na2)
			return FALSE;
	}

	/* The arguments must be the same. */
	for (a = 0; a < sd1 -> nrArgs; ++a)
	{
		if (!strict && sd1 -> args[a].defval != NULL)
			break;

		if (!sameArgType(&sd1 -> args[a],&sd2 -> args[a],strict))
			return FALSE;
	}

	/* Must be the same if we've got this far. */
	return TRUE;
}


/*
 * Compare two argument types and return TRUE if they are the same.
 */

int sameArgType(argDef *a1,argDef *a2,int strict)
{
	/* The indirection and the references must be the same. */

	if (isReference(a1) != isReference(a2) || a1 -> nrderefs != a2 -> nrderefs)
		return FALSE;

	/* The const should be the same. */

	if (isConstArg(a1) != isConstArg(a2))
		return FALSE;

	/*
	 * In non-strict, just check if they are subject to Python conversions.
	 */

	if (!strict)
		if ((pyToInt(a1 -> atype) && pyToInt(a2 -> atype)) ||
		    (pyToDouble(a1 -> atype) && pyToDouble(a2 -> atype)))
		return TRUE;

	return sameBaseType(a1,a2,strict);
}


/*
 * Compare two basic types and return TRUE if they are the same.
 */

int sameBaseType(argDef *a1,argDef *a2,int strict)
{
	/* The types must be the same. */

	if (a1 -> atype != a2 ->atype)
		return FALSE;

	switch (a1 -> atype)
	{
	case class_type:
		if (a1 -> u.cd != a2 -> u.cd)
			return FALSE;

		break;

	case enum_type:
		if (strict && a1 -> u.ed != a2 -> u.ed)
			return FALSE;

		break;

	case slotcon_type:
	case slotdis_type:
		if (!sameSignature(a1 -> u.sa,a2 -> u.sa,strict))
			return FALSE;

		break;

	case template_type:
		{
			int a;
			templateDef *td1, *td2;

			td1 = a1 -> u.td;
			td2 = a2 -> u.td;

			if (!sameScopedName(td1 -> fqname,td2 -> fqname) != 0 ||
			    td1 -> types.nrArgs != td2 -> types.nrArgs)
				return FALSE;

			for (a = 0; a < td1 -> types.nrArgs; ++a)
				if (!sameBaseType(&td1 -> types.args[a],&td2 -> types.args[a],strict))
					return FALSE;

			break;
		}

	case struct_type:
		if (!sameScopedName(a1 -> u.sname,a2 -> u.sname) != 0)
			return FALSE;

		break;

	case defined_type:
		if (!sameScopedName(a1 -> u.snd,a2 -> u.snd))
			return FALSE;

		break;

	case mapped_type:
		if (a1 -> u.mtd != a2 -> u.mtd)
			return FALSE;

		break;
	}

	/* Must be the same if we've got this far. */

	return TRUE;
}


/*
 * Return TRUE if two scoped names are the same.
 */

int sameScopedName(scopedNameDef *snd1,scopedNameDef *snd2)
{
	while (snd1 != NULL && snd2 != NULL && strcmp(snd1 -> name,snd2 -> name) == 0)
	{
		snd1 = snd1 -> next;
		snd2 = snd2 -> next;
	}

	return (snd1 == NULL && snd2 == NULL);
}


/*
 * Add an explicit scope to the default value of an argument if possible.
 */

static void scopeDefaultValue(sipSpec *pt,classDef *cd,argDef *ad)
{
	valueDef *vd, **tailp, *newvd;

	/*
	 * We do a quick check to see if we need to do anything.  This means
	 * we can limit the times we need to copy the default value.  It needs
	 * to be copied because it will be shared by class versions that have
	 * been created on the fly and it may need to be scoped differently for
	 * each of those versions.
	 */

	for (vd = ad -> defval; vd != NULL; vd = vd -> next)
		if (vd -> vtype == scoped_value && vd -> u.vscp -> next == NULL)
			break;

	if (vd == NULL)
		return;

	/*
	 * It's not certain that we will do anything, but we assume we will and
	 * start copying.
	 */

	newvd = NULL;
	tailp = &newvd;

	for (vd = ad -> defval; vd != NULL; vd = vd -> next)
	{
		mroDef *mro;
		scopedNameDef *origname;
		valueDef *new;

		/* Make the copy. */

		new = sipMalloc(sizeof (valueDef));

		*new = *vd;
		*tailp = new;
		tailp = &new -> next;

		/*
		 * Skip this part of the expression if it isn't a named value
		 * or it already has a scope.
		 */

		if (vd -> vtype != scoped_value || vd -> u.vscp -> next != NULL)
			continue;

		/*
		 * Search the class hierarchy for an enum value with the same
		 * name.  If we don't find one, leave it as it is (the compiler
		 * will find out if this is a problem).
		 */

		origname = vd -> u.vscp;

		for (mro = cd -> mro; mro != NULL; mro = mro -> next)
		{
			enumDef *ed;

			if (isDuplicateSuper(mro))
				continue;

			for (ed = pt -> enums; ed != NULL; ed = ed -> next)
			{
				enumValueDef *evd;

				if (ed -> ecd != mro -> cd)
					continue;

				for (evd = ed -> values; evd != NULL; evd = evd -> next)
					if (strcmp(evd -> name -> text,origname -> name) == 0)
					{
						scopedNameDef *snd;

						/*
						 * Take the scope from the
						 * class that the enum was
						 * defined in.
						 */

						snd = copyScopedName(mro -> cd -> iff -> fqname);
						appendScopedName(&snd,origname);

						new -> u.vscp = snd;

						/* Nothing more to do. */

						break;
					}

				if (evd != NULL)
					break;
			}

			if (ed != NULL)
				break;
		}
	}

	ad -> defval = newvd;
}


/*
 * Make sure a type is a base type.
 */

static void getBaseType(sipSpec *pt,classDef *defscope,argDef *type)
{
	/* Loop until we've got to a base type. */

	while (type -> atype == defined_type)
	{
		scopedNameDef *snd = type -> u.snd;

		type -> atype = no_type;

		if (defscope != NULL)
			searchScope(pt,defscope,snd,type);

		if (type -> atype == no_type)
			searchMappedTypes(pt,snd,type);

		if (type -> atype == no_type)
			searchTypedefs(pt,snd,type);

		if (type -> atype == no_type)
			searchEnums(pt,snd,type);

		if (type -> atype == no_type)
			searchClasses(pt,snd,type);

		if (type -> atype == no_type)
			fatalNoDefinedType(snd);
	}

	/* Get the base of type of any slot arguments. */

	if (type -> atype == slotcon_type || type -> atype == slotdis_type)
	{
		int sa;

		for (sa = 0; sa < type -> u.sa -> nrArgs; ++sa)
			getBaseType(pt,defscope,&type -> u.sa -> args[sa]);
	}

	/* Replace the base type if it has been mapped. */

	if (type -> atype == struct_type || type -> atype == template_type)
		searchMappedTypes(pt,NULL,type);
}


/*
 * Search for a name in a scope and return the corresponding type.
 */

static void searchScope(sipSpec *pt,classDef *scope,scopedNameDef *snd,
			argDef *ad)
{
	scopedNameDef *tmpsnd = NULL;
	mroDef *mro;

	for (mro = scope -> mro; mro != NULL; mro = mro -> next)
	{
		if (isDuplicateSuper(mro))
			continue;

		/* Append the name to the scope and see if it exists. */

		tmpsnd = copyScopedName(classFQName(mro -> cd));
		appendScopedName(&tmpsnd,copyScopedName(snd));

		searchMappedTypes(pt,tmpsnd,ad);

		if (ad -> atype != no_type)
			break;

		searchTypedefs(pt,tmpsnd,ad);

		if (ad -> atype != no_type)
			break;

		searchEnums(pt,tmpsnd,ad);

		if (ad -> atype != no_type)
			break;

		searchClasses(pt,tmpsnd,ad);

		if (ad -> atype != no_type)
			break;

		freeScopedName(tmpsnd);
		tmpsnd = NULL;
	}

	if (tmpsnd != NULL)
		freeScopedName(tmpsnd);
}


/*
 * Search the mapped types for a name and return the type.
 */

static void searchMappedTypes(sipSpec *pt,scopedNameDef *snd,argDef *ad)
{
	mappedTypeDef *mtd;
	scopedNameDef *oname;

	/* Patch back to defined types so we can use sameBaseType(). */

	if (snd != NULL)
	{
		oname = ad -> u.snd;
		ad -> u.snd = snd;
		ad -> atype = defined_type;
	}

	for (mtd = pt -> mappedtypes; mtd != NULL; mtd = mtd -> next)
		if (sameBaseType(ad,&mtd -> type,TRUE))
		{
			/* Copy the type. */

			ad -> atype = mapped_type;
			ad -> u.mtd = mtd;

			return;
		}

	/* Restore because we didn't find anything. */

	if (snd != NULL)
	{
		ad -> u.snd = oname;
		ad -> atype = no_type;
	}
}


/*
 * Search the typedefs for a name and return the type.
 */

static void searchTypedefs(sipSpec *pt,scopedNameDef *snd,argDef *ad)
{
	typedefDef *td;

	for (td = pt -> typedefs; td != NULL; td = td -> next)
		if (sameScopedName(td -> fqname,snd))
		{
			/* Copy the type. */

			ad -> atype = td -> type.atype;
			ad -> argflags |= td -> type.argflags;
			ad -> nrderefs += td -> type.nrderefs;
			ad -> u = td -> type.u;

			break;
		}
}


/*
 * Search the enums for a name and return the type.
 */

static void searchEnums(sipSpec *pt,scopedNameDef *snd,argDef *ad)
{
	enumDef *ed;

	for (ed = pt -> enums; ed != NULL; ed = ed -> next)
	{
		if (ed -> fqname == NULL)
			continue;

		if (sameScopedName(ed -> fqname,snd))
		{
			ad -> atype = enum_type;
			ad -> u.ed = ed;

			break;
		}
	}
}


/*
 * Search the classes for a name and return the type.
 */

static void searchClasses(sipSpec *pt,scopedNameDef *snd,argDef *ad)
{
	classDef *cd;

	for (cd = pt -> classes; cd != NULL; cd = cd -> next)
		if (sameScopedName(classFQName(cd),snd))
		{
			ad -> atype = class_type;
			ad -> u.cd = cd;

			break;
		}
}


/*
 * Print an error message describing an undefined type to stderr and terminate.
 */

static void fatalNoDefinedType(scopedNameDef *snd)
{
	fatalScopedName(snd);
	fatal(" is undefined\n");
}


/*
 * Make sure all external interface files for all other functions of a module
 * are used.
 */
static void ifaceFilesAreUsedByOther(sipSpec *pt,overDef *od)
{
	int a;
	ifaceFileDef *iff;

	if ((iff = getIfaceFile(&od -> pysig.result)) != NULL && iff -> module != pt -> module)
		addToUsedList(&pt -> used,iff);

	for (a = 0; a < od -> pysig.nrArgs; ++a)
		if ((iff = getIfaceFile(&od -> pysig.args[a])) != NULL && iff -> module != pt -> module)
			addToUsedList(&pt -> used,iff);
}


/*
 * Make sure all interface files for all overloads of a method are used.
 */
static void ifaceFilesAreUsedByMethod(classDef *cd,memberDef *md)
{
	overDef *od;

	for (od = cd -> overs; od != NULL; od = od -> next)
		if (od -> common == md)
			ifaceFilesAreUsed(cd -> iff,od);
}


/*
 * Make sure all interface files for a signature are used.
 */
static void ifaceFilesAreUsed(ifaceFileDef *iff,overDef *od)
{
	int a;

	ifaceFileIsUsed(iff,&od -> pysig.result);

	for (a = 0; a < od -> pysig.nrArgs; ++a)
		ifaceFileIsUsed(iff,&od -> pysig.args[a]);
}


/*
 * If a type has an interface file then add it to the appropriate list of used
 * interface files so that the header file is #included in the generated code.
 */
static void ifaceFileIsUsed(ifaceFileDef *iff,argDef *ad)
{
	ifaceFileDef *usediff;

	if ((usediff = getIfaceFile(ad)) != NULL && usediff != iff)
		addToUsedList(&iff -> used,usediff);
}


/*
 * Return the interface file for a type, or NULL if it doesn't have one.
 */
static ifaceFileDef *getIfaceFile(argDef *ad)
{
	ifaceFileDef *iff;

	switch (ad -> atype)
	{
	case class_type:
		iff = ad -> u.cd -> iff;
		break;

	case mapped_type:
		iff = ad -> u.mtd -> iff;
		break;

	default:
		iff = NULL;
	}

	return iff;
}


/*
 * Position a class so that it is after all its super-classes.
 */
static void positionClass(classDef *cd)
{
	classList *cl;

	/* See if it has already been done. */
	if (cd -> node -> ordered)
		return;

	for (cl = cd -> supers; cl != NULL; cl = cl -> next)
	{
		nodeDef **ndp, *nd1, *nd2, *rp;

		/* Ignore super-classes from different modules. */
		if (cl -> cd -> iff -> module != cd -> iff -> module)
			continue;

		/* Make sure the super-class is positioned. */
		positionClass(cl -> cd);

		/*
		 * Find ancestors of the two that are siblings (ie. they have a
		 * common parent).
		 */
		rp = &cd -> iff -> module -> root;

		for (nd1 = cd -> node; nd1 != rp; nd1 = nd1 -> parent)
		{
			for (nd2 = cl -> cd -> node; nd2 != rp; nd2 = nd2 -> parent)
				if (nd1 -> parent == nd2 -> parent)
					break;

			if (nd2 != rp)
				break;
		}

		/*
		 * The first node must appear after the second in the common
		 * parent's list of children.
		 */
		for (ndp = &nd1 -> parent -> child; *ndp != NULL; ndp = &(*ndp) -> next)
		{
			nodeDef *nd = *ndp;

			if (nd == nd2)
				break;

			if (nd == nd1)
			{
				/* Remove this one from the list. */
				*ndp = nd -> next;

				/* Find the super-class ancestor. */
				while (*ndp != nd2)
					ndp = &(*ndp) -> next;

				/*
				 * Put this one back after the super-class
				 * ancestor.
				 */
				nd -> next = (*ndp) -> next;
				(*ndp) -> next = nd;

				break;
			}
		}
	}

	cd -> node -> ordered = TRUE;
}


/*
 * Make sure a class is in the namespace tree.
 */
static void addNodeToParent(nodeDef *root,classDef *cd)
{
	nodeDef *nd, *parent;

	/* Skip classes already in the tree. */
	if (cd -> node != NULL)
		return;

	/* Add this child to the parent. */
	nd = sipMalloc(sizeof (nodeDef));

	nd -> ordered = FALSE;
	nd -> cd = cd;
	nd -> child = NULL;

	/* Get the address of the parent node. */
	if (cd -> ecd == NULL)
		parent = root;
	else
	{
		/* Make sure the parent is in the tree. */
		addNodeToParent(root,cd -> ecd);

		parent = cd -> ecd -> node;
	}

	nd -> parent = parent;

	/* Insert this at the head of the parent's children. */
	nd -> next = parent -> child;
	parent -> child = nd;

	/* Remember where we are in the tree. */
	cd -> node = nd;
}


/*
 * Assign the module specific class number for a class and all it's children.
 */
static void assignClassNrs(sipSpec *pt,moduleDef *mod,nodeDef *nd)
{
	classDef *cd;
	nodeDef *cnd;

	/* Assign the class if it's not the root. */
	if ((cd = nd -> cd) != NULL)
	{
		cd -> classnr = mod -> nrclasses++;

		/*
		 * If we find a class defined in the main module called
		 * QObject, assume it's Qt.
		 */
		if (mod == pt -> module && strcmp(cd -> iff -> name -> text,"QObject") == 0)
			pt -> qobjclass = cd -> classnr;
	}

	/* Assign all it's children. */
	for (cnd = nd -> child; cnd != NULL; cnd = cnd -> next)
		assignClassNrs(pt,mod,cnd);
}
