public void fillInAndApplyVftableStructAndNameVfunctions(RecoveredClass recoveredClass,
			Map<Address, DataType> vftableToStructureMap, Structure classStruct)
			throws CancelledException, Exception {

		//create function definition for each virtual function and put in vftable structure and
		// data subfolder
		CategoryPath classPath = recoveredClass.getClassPath();

		List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
		for (Address vftableAddress : vftableAddresses) {
			monitor.checkCancelled();
			PointerDataType vftablePointerDataType =
				(PointerDataType) vftableToStructureMap.get(vftableAddress);

			if (vftablePointerDataType == null) {
				Msg.debug(this,
					"vftablePointerDataType is null for vftableAddress: " + vftableAddress);
			}

			DataType vftableDataType = vftablePointerDataType.getDataType();

			String vftableStructureName = vftableDataType.getName();
			vftableDataType = dataTypeManager.getDataType(vftableDataType.getCategoryPath(),
				vftableStructureName);

			Structure vftableStruct = (Structure) vftableDataType;

			if (nameVfunctions) {
				// if no pdb info, name all the vfunctions for this vftable and put in class namespace
				nameVfunctions(recoveredClass, vftableAddress, vftableStructureName);
			}

			List<Function> vFunctions = recoveredClass.getVirtualFunctions(vftableAddress);
			int vfunctionNumber = 1;
			for (Function vfunction : vFunctions) {

				monitor.checkCancelled();
				if (vfunction == null) {
					Pointer nullPointer = dataTypeManager.getPointer(DataType.DEFAULT);
					vftableStruct.add(nullPointer, "null pointer", null);
					continue;
				}

				String forClassSuffix = getForClassSuffix(vftableStructureName);
				String functionDefName = vfunction.getName();
				int indexOfSuffix = functionDefName.indexOf(forClassSuffix);

				// if vfunction name has the "for_parent" suffix, strip it off for the function definition name
				if (indexOfSuffix > 0) {
					functionDefName = functionDefName.substring(0, indexOfSuffix);

				}

				// get the classPath of highest level parent with vfAddress in their vftable
				classPath = getCategoryPathForFunctionSignature(vfunction, functionDefName,
					recoveredClass, vftableAddress);

				Symbol vfunctionSymbol = symbolTable.getPrimarySymbol(vfunction.getEntryPoint());
				Namespace parentNamespace = vfunctionSymbol.getParentNamespace();

				String classCommentPrefix = "";

				if (!parentNamespace.equals(globalNamespace)) {
					RecoveredClass vfunctionClass = getClass(parentNamespace);

					// this is null when there is a class from somewhere other than RTTI so it is
					// not stored in the map. Just use the parent namespace name in this case
					if (vfunctionClass == null) {
						classCommentPrefix = parentNamespace.getName();
					}
					else if (vfunctionClass.getShortenedTemplateName() != null &&
						useShortTemplates && !vfunctionClass.getShortenedTemplateName().isEmpty()) {
						classCommentPrefix = vfunctionClass.getShortenedTemplateName();
					}
					else {
						classCommentPrefix = vfunctionClass.getName();
					}

				}

				// Create comment to indicate it is a virtual function and which number in the table
				String comment = VFUNCTION_COMMENT + vfunctionNumber;

				// add comment suffix for multi classes to distinguish which vftable it is for

				if (!forClassSuffix.isEmpty()) {

					int index = forClassSuffix.indexOf("for_");
					String commentSuffix = "";
					if (index > 0) {
						commentSuffix = " for parent class " + forClassSuffix.substring(index + 4);
					}
					comment = comment + commentSuffix;
				}

				// if function is "purecall" function make the class field name "vfunction #n" instead
				// of using the function name of "purecall" and prepend "pure" to the comment so
				// they know it is pure virtual function, ie not actually implemented in the parent class
				String nameField = vfunction.getName();

				FunctionDefinition functionDataType =
					new FunctionDefinitionDataType(vfunction, false);

				if (!vfunction.getName().equals(functionDefName)) {
					functionDataType.setName(functionDefName);
				}

				functionDataType.setReturnType(vfunction.getReturnType());

				// if the function is a purecall need to create the function definition using
				// the equivalent child virtual function signature
				if (nameField.contains("purecall")) {

					nameField = DEFAULT_VFUNCTION_PREFIX + vfunctionNumber;

					// get function sig from a child class
					Function childVirtualFunction =
						getChildVirtualFunction(recoveredClass, vfunctionNumber);

					// if it is null it will just use the purecall function definition since
					// it can't find a child one to use to replace it
					if (childVirtualFunction != null) {
						functionDataType =
							new FunctionDefinitionDataType(childVirtualFunction, false);
						functionDataType.setReturnType(childVirtualFunction.getReturnType());
						Symbol childFunctionSymbol =
							symbolTable.getPrimarySymbol(childVirtualFunction.getEntryPoint());

						// if the child function has a default name, rename the function definition
						// data type to the "vfunction<vfunctionNumber>" name
						if (childFunctionSymbol.getSource() != SourceType.DEFAULT) {
							nameField = childFunctionSymbol.getName();
						}
					}
					functionDataType.setName(nameField);
					comment = recoveredClass.getName() + " pure " + comment;
				}

				ParameterDefinition[] arguments = functionDataType.getArguments();

				// if the vfunction is a thiscall then replace the classStruct* this with voidPtr
				// so that it can be used generically for all related members of the class family
				if (arguments.length > 0 && arguments[0].getName().equals("this")) {
					VoidDataType voidDT = new VoidDataType();
					PointerDataType voidPtr = new PointerDataType(voidDT);
					ParameterDefinition parameterDefinition = arguments[0];
					parameterDefinition.setDataType(voidPtr);
				}

				PointerDataType functionPointerDataType =
					createFunctionSignaturePointerDataType(functionDataType, classPath);

				vftableStruct.add(functionPointerDataType, nameField,
					classCommentPrefix + " " + comment);
				vfunctionNumber++;
			}

			// align the structure then add it to the data type manager
			vftableStruct.setPackingEnabled(true);
			vftableStruct = (Structure) dataTypeManager.addDataType(vftableStruct,
				DataTypeConflictHandler.DEFAULT_HANDLER);

			// clear the array or unprocessed structure at the current vftable location and
			// apply the structure. It has to be one or the other and the correct length
			// because of the check at the beginning of the script that checked for either
			// array or structure of pointers and got size from them initially
			api.clearListing(vftableAddress, vftableAddress.add(vftableStruct.getLength() - 1));
			api.createData(vftableAddress, vftableStruct);

		}
	}
Method to fill in the vftable structure with pointers to virtual function signature data types
@param recoveredClass the current class to be processed
@param vftableToStructureMap the map from the class's vftables to the correct vftable structure data type
@param classStruct the class structure for the given class
@throws CancelledException when cancelled
@throws Exception if other exception
Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java