private StringBuffer createClassInfoString(RecoveredClass recoveredClass)
			throws CancelledException {

		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("\r\n");
		stringBuffer.append("\r\n");

		stringBuffer.append("*** Recovered Class:  " + recoveredClass.getName() + "  ***\r\n");
		stringBuffer.append("\r\n");

		// print parent classes
		stringBuffer.append("parent class(es):\r\n");
		if (recoveredClass.hasParentClass()) {

			// use this to get direct  parents
			Map<RecoveredClass, List<RecoveredClass>> classHierarchyMap =
				recoveredClass.getClassHierarchyMap();
			Set<RecoveredClass> directParents = classHierarchyMap.keySet();

			// use this to get correct parent order and to get the type of parent
			Map<RecoveredClass, Boolean> parentToBaseTypeMap =
				recoveredClass.getParentToBaseTypeMap();
			Set<RecoveredClass> ancestors = parentToBaseTypeMap.keySet();
			for (RecoveredClass ancestor : ancestors) {
				monitor.checkCancelled();
				if (directParents.contains(ancestor)) {

					Boolean isVirtualParent = parentToBaseTypeMap.get(ancestor);
					if (isVirtualParent != null && isVirtualParent) {
						stringBuffer.append("\t virtual " + ancestor.getName() + "\r\n");
					}
					else {
						stringBuffer.append("\t" + ancestor.getName() + "\r\n");
					}
				}
			}
		}
		else {
			stringBuffer.append("\tNone\r\n");
		}

		// print child classes
		stringBuffer.append("\r\n");
		stringBuffer.append("child class(es):\r\n");
		if (recoveredClass.hasChildClass()) {
			List<RecoveredClass> childClasses = recoveredClass.getChildClasses();
			for (RecoveredClass element : childClasses) {
				monitor.checkCancelled();
				stringBuffer.append("\t" + element.getName() + "\r\n");
			}

		}
		stringBuffer.append("\r\n");

		// print constructors
		stringBuffer.append("constructor(s):\r\n");
		List<Function> constructorList = recoveredClass.getConstructorList();
		for (Function constructorFunction : constructorList) {
			monitor.checkCancelled();
			stringBuffer.append("\t" + constructorFunction.getName() + " " +
				constructorFunction.getEntryPoint().toString() + "\r\n");
		}
		stringBuffer.append("\r\n");

		// print inlined constructors
		List<Function> inlinedConstructorList = recoveredClass.getInlinedConstructorList();
		if (inlinedConstructorList.size() > 0) {
			stringBuffer.append("inlined constructor(s):\r\n");
			for (Function inlinedConstructorFunction : inlinedConstructorList) {
				monitor.checkCancelled();
				stringBuffer.append("\t" + inlinedConstructorFunction.getName() + " " +
					inlinedConstructorFunction.getEntryPoint().toString() + "\r\n");
			}
		}
		stringBuffer.append("\r\n");

		// print destructors
		stringBuffer.append("destructor(s):\r\n");
		List<Function> destructorList = recoveredClass.getDestructorList();
		for (Function destructorFunction : destructorList) {
			monitor.checkCancelled();
			stringBuffer.append("\t" + destructorFunction.getName() + " " +
				destructorFunction.getEntryPoint().toString() + "\r\n");
		}
		stringBuffer.append("\r\n");

		// print inlined destructors
		List<Function> inlinedDestructorList = recoveredClass.getInlinedDestructorList();
		if (inlinedDestructorList.size() > 0) {
			stringBuffer.append("inlined destructor(s):\r\n");
			for (Function inlinedDestructorFunction : inlinedDestructorList) {
				monitor.checkCancelled();
				stringBuffer.append("\t" + inlinedDestructorFunction.getName() + " " +
					inlinedDestructorFunction.getEntryPoint().toString() + "\r\n");
			}
		}

		// print const/dest that couldn't be classified correctly
		List<Function> indeterminateList = recoveredClass.getIndeterminateList();
		if (indeterminateList.size() > 0) {
			stringBuffer.append("\r\nindeterminate constructor(s) or destructor(s):\r\n");
			for (Function indeterminateFunction : indeterminateList) {
				monitor.checkCancelled();
				stringBuffer.append("\t" + indeterminateFunction.getName() + " " +
					indeterminateFunction.getEntryPoint().toString() + "\r\n");
			}
			stringBuffer.append("\r\n");
		}
		stringBuffer.append("\r\n");

		// print virtual function signatures
		stringBuffer.append("member function(s):\r\n");
		List<Function> virtualFunctions = recoveredClass.getAllVirtualFunctions();
		for (Function vfunction : virtualFunctions) {
			monitor.checkCancelled();
			stringBuffer.append(
				"\t" + vfunction.getName() + " " + vfunction.getEntryPoint().toString() + "\r\n");
		}
		stringBuffer.append("\r\n");

		// print class member data
		stringBuffer.append("member data:\r\n");

		DataType classMemberDataType = dataTypeManager.getDataType(recoveredClass.getClassPath(),
			recoveredClass.getName() + CLASS_DATA_STRUCT_NAME);

		if (classMemberDataType != null && classMemberDataType instanceof Structure) {

			Structure memberDataStructure = (Structure) classMemberDataType;
			int numDefinedComponents = memberDataStructure.getNumDefinedComponents();

			DataTypeComponent[] definedComponents = memberDataStructure.getDefinedComponents();
			for (int i = 0; i < numDefinedComponents; i++) {
				monitor.checkCancelled();

				stringBuffer.append("\t" + definedComponents[i].getDataType() + " " +
					definedComponents[i].getFieldName() + "\r\n");
			}
		}
		stringBuffer.append("\r\n");

		// Then recursively process the child classes
		if (recoveredClass.hasChildClass()) {
			List<RecoveredClass> childClasses = recoveredClass.getChildClasses();
			for (RecoveredClass element : childClasses) {
				monitor.checkCancelled();
				stringBuffer.append(createClassInfoString(element));
			}
		}

		return stringBuffer;
	}
Method to create a string containing class info for the given class including parents, 
children, constructors, destructors inlined constructors, inlined destructors, member 
functions, member data and the same info for each child class
@param recoveredClass the given class
@return string buffer containing class info for the given class
@throws CancelledException if cancelled
Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java