private List<RecoveredClass> recoverClassesFromClassHierarchyDescriptors(
			List<Symbol> vftableSymbols) throws CancelledException, Exception {

		List<RecoveredClass> recoveredClasses = new ArrayList<RecoveredClass>();

		List<Symbol> classHierarchyDescriptorList = getListOfClassHierarchyDescriptors();

		for (Symbol classHierarchyDescriptorSymbol : classHierarchyDescriptorList) {
			monitor.checkCancelled();
			Address classHierarchyDescriptorAddress = classHierarchyDescriptorSymbol.getAddress();

			// Get class name from class vftable is in
			Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
			if (classNamespace.isGlobal()) {
				Msg.warn(this, "ClassHierarchyDescriptor at " + classHierarchyDescriptorAddress +
					" is unexpectedly in the Global namespace so processing cannot continue for " +
					"this class");
				continue;
			}
			// get the data type category associated with the given class namespace
			Category category = getDataTypeCategory(classNamespace);

			// if it already exists, continue since this class has already been recovered
			if (category != null) {
				continue;
			}

			if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
				classNamespace = promoteToClassNamespace(classNamespace);
				if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
					Msg.debug(this,
						classHierarchyDescriptorAddress.toString() + " Could not promote " +
							classNamespace.getName(true) + " to a class namespace.");
					continue;
				}
			}

			List<Symbol> vftableSymbolsInNamespace = getClassVftableSymbols(classNamespace);

			//if there are no vftables in this class then create a new class object and make it 
			// non-vftable class
			if (vftableSymbolsInNamespace.size() == 0) {
				String className = classNamespace.getName();

				// Make a CategoryPath for given class
				CategoryPath classPath = extendedFlatAPI
						.createDataTypeCategoryPath(classDataTypesCategoryPath, classNamespace);

				RecoveredClass nonVftableClass =
					new RecoveredClass(className, classPath, classNamespace, dataTypeManager);
				nonVftableClass.setHasVftable(false);
				// add recovered class to map
				if (getClass(classNamespace) == null) {
					updateNamespaceToClassMap(classNamespace, nonVftableClass);

					// add it to the running list of RecoveredClass objects
					recoveredClasses.add(nonVftableClass);
				}
			}
			// if there are vftables in the class, call the method to make
			// a new class object using the vftable info 
			else {
				List<RecoveredClass> classesWithVftablesInNamespace =
					recoverClassesFromVftables(vftableSymbolsInNamespace, false, false);
				if (classesWithVftablesInNamespace.size() == 0) {
					Msg.debug(this, "No class recovered for namespace " + classNamespace.getName());
					continue;
				}
				if (classesWithVftablesInNamespace.size() > 1) {
					Msg.debug(this, "Unexpected multiple classes recovered for namespace " +
						classNamespace.getName());
					continue;
				}

				recoveredClasses.add(classesWithVftablesInNamespace.get(0));

			}

		}

		return recoveredClasses;
	}
Method to recover the class information for each vftable symbol on the list
* For each virtual function table:
1. get vftable's existing class
2. create matching data type category folder in dt manager
3. get list of virtual functions
4. create RecoveredClass object for the vftable class
5. add mapping from vftableAddress to class
6. add list of const/dest functions to RecoveredClass object
7. update list of all const/dest functions in currenetProgram
8. set RecoveredClass indeterminate list to const/dest list 
9. update list of all indeterminate const/dest
@param vftableSymbols List of vftable symbols
@return List of RecoveredClass objects created corresponding to the vftable symbols
@throws CancelledException if cancelled
@throws Exception if issue creating data
Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java