text: /* ###
   * IP: GHIDRA
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package ghidra.app.util.pdb.pdbapplicator;
  
  import java.math.BigInteger;
  import java.util.*;
  
  import ghidra.app.util.SymbolPath;
  import ghidra.app.util.SymbolPathParser;
  import ghidra.app.util.bin.format.pdb.DefaultCompositeMember;
  import ghidra.app.util.bin.format.pdb2.pdbreader.*;
  import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
  import ghidra.program.model.data.*;
  import ghidra.util.Msg;
  import ghidra.util.exception.AssertException;
  import ghidra.util.exception.CancelledException;
  
  /*
   * Non java-doc:
   * Some truths:
   *   For AbstractMsCompositeType: do not count on "count" to be zero when MsProperty is forward
   *     reference (we have seen example of count==0 and not forward reference, though the majority
   *     of the time the two go hand-in-hand.  When these did not equate, it might have been when
   *     there was no need for a forward reference and possibly only one definition--this would
   *     require a closer look).
   */
  /**
   * Applier for {@link AbstractCompositeMsType} types.
   */
  public class CompositeTypeApplier extends AbstractComplexTypeApplier {
  
  	// DO NOT DELETE.  Might eliminate one path or might make an analyzer option.
  	private static boolean applyBaseClasses = true;
  	//private static boolean applyBaseClasses = false;
  
  	private CppCompositeType classType;
  
  //	private final static DataType NO_TYPE_DATATYPE =
  //		new TypedefDataType("<NoType>", Undefined1DataType.dataType);
  //
  	private Map<Integer, String> componentComments;
  
  	private List<DefaultPdbUniversalMember> members;
  
  	/**
  	 * Constructor for composite type applier, for transforming a composite into a
  	 * Ghidra DataType.
  	 * @param applicator {@link PdbApplicator} for which this class is working.
  	 * @param msType {@link AbstractCompositeMsType} to process.
  	 */
  	public CompositeTypeApplier(PdbApplicator applicator, AbstractCompositeMsType msType) {
  		super(applicator, msType);
  		String fullPathName = msType.getName();
  		symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName));
  	}
  
  	CppCompositeType getClassType() {
  		if (definitionApplier != null) {
  			return ((CompositeTypeApplier) definitionApplier).getClassTypeInternal();
  		}
  		return classType;
  	}
  
  	CppCompositeType getClassTypeInternal() {
  		return classType;
  	}
  
  	List<DefaultPdbUniversalMember> getMembers() {
  		return members;
  	}
  
  	// Mapping of forwardReference/definition must be done prior to this call.
  	private void getOrCreateComposite() {
  		if (dataType != null) {
  			return;
  		}
  
  		AbstractComplexTypeApplier alternativeApplier = getAlternativeTypeApplier();
  		if (alternativeApplier != null) {
  			dataType = alternativeApplier.getDataTypeInternal();
  			classType = ((CompositeTypeApplier) alternativeApplier).getClassTypeInternal();
  		}
  		if (dataType != null) {
  			return;
  		}
  
  		dataType = createEmptyComposite((AbstractCompositeMsType) msType);
  		String mangledName = ((AbstractCompositeMsType) msType).getMangledName();
  		classType = new CppCompositeType((Composite) dataType, mangledName);
  		classType.setName(getName());
  		classType.setSize(PdbApplicator.bigIntegerToInt(applicator, getSize()));
  		if (msType instanceof AbstractClassMsType) {
  			classType.setClass();
  		}
  		else if (msType instanceof AbstractStructureMsType) {
  			classType.setStruct();
  		}
  		else if (msType instanceof AbstractUnionMsType) {
  			classType.setUnion();
  		}
  		classType.setFinal(isFinal());
  
  	}
  
  	@Override
  	void apply() throws PdbException, CancelledException {
  
  		getOrCreateComposite();
  
  		Composite composite = (Composite) dataType;
  
  		AbstractCompositeMsType type = (AbstractCompositeMsType) msType;
  		MsProperty property = type.getMsProperty();
  		if (property.isForwardReference() && definitionApplier != null) {
  			return;
  		}
  		if (!(composite instanceof CompositeDataTypeImpl)) {
  			return; // A resolved version exists (multiple definitions).
  		}
  		applyOrDeferForDependencies();
  	}
  
  	@Override
  	void resolve() {
  		if (!isForwardReference()) {
  			super.resolve();
  		}
  	}
  
  	private void applyOrDeferForDependencies() throws PdbException, CancelledException {
  		AbstractCompositeMsType type = (AbstractCompositeMsType) msType;
  		MsProperty property = type.getMsProperty();
  		if (property.isForwardReference() && definitionApplier != null) {
  			return;
  		}
  
  		// Add self
  		applicator.addApplierDependency(this);
  
  		// Add any dependees: base classes and members
  		FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial(
  			applicator, type.getFieldDescriptorListRecordNumber());
  
  		// Currently do not need this dependency, as we currently do not need any contents
  		// of the base class for filling in this class
  		for (MsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) {
  			if (baseApplierIterated instanceof BaseClassTypeApplier) {
  				BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated;
  				MsTypeApplier applier =
  					applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber());
  				if (applier instanceof CompositeTypeApplier) {
  					CompositeTypeApplier dependencyApplier =
  						((CompositeTypeApplier) applier).getDependencyApplier();
  					applicator.addApplierDependency(this, dependencyApplier);
  //					CompositeTypeApplier defApplier =
  //						((CompositeTypeApplier) applier).getDefinitionApplier();
  //					if (defApplier != null) {
  //						applicator.addApplierDependency(this, defApplier);
  //					}
  //					else {
  //						applicator.addApplierDependency(this, applier);
  //					}
  					setDeferred();
  				}
  			}
  		}
  		for (MsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) {
  			applicator.checkCanceled();
  			if (memberTypeApplierIterated instanceof MemberTypeApplier) {
  				MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated;
  				MsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier();
  				recurseAddDependency(fieldApplier);
  			}
  //			if (memberTypeApplierIterated instanceof NestedTypeApplier) {
  //				recurseAddDependency(memberTypeApplierIterated);
  //			}
  			else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) {
  				applicator.addApplierDependency(this, memberTypeApplierIterated);
  			}
  		}
  		if (!isDeferred()) {
  			applyInternal();
  		}
  	}
  
  	private void recurseAddDependency(MsTypeApplier dependee)
  			throws CancelledException, PdbException {
  		// TODO: evaluate this and make changes... this work might be being taken care of in
  		//  ModifierTypeApplier
  		if (dependee instanceof ModifierTypeApplier) {
  			ModifierTypeApplier modifierApplier = (ModifierTypeApplier) dependee;
  			recurseAddDependency(modifierApplier.getModifiedTypeApplier());
  		}
  		else if (dependee instanceof CompositeTypeApplier) {
  			CompositeTypeApplier defApplier =
  				((CompositeTypeApplier) dependee).getDefinitionApplier(CompositeTypeApplier.class);
  			if (defApplier != null) {
  				applicator.addApplierDependency(this, defApplier);
  			}
  			else {
  				applicator.addApplierDependency(this, dependee);
  			}
  			setDeferred();
  		}
  		// TODO: evaluate this and make changes... this work might be being taken care of in
  		//  ArrayTypeApplier
  		else if (dependee instanceof ArrayTypeApplier) {
  			applicator.addApplierDependency(this, dependee);
  			setDeferred();
  		}
  //		else if (dependee instanceof NestedTypeApplier) {
  //			NestedTypeApplier nestedTypeApplier = (NestedTypeApplier) dependee;
  //			AbstractMsTypeApplier nestedDefinitionApplier =
  //				nestedTypeApplier.getNestedTypeDefinitionApplier();
  //			// Need to make sure that "this" class id dependent on all elements composing the
  //			// nested definition, but we need to create the nested definition during the
  //			// creation of this class. (NestedTypeApplier and NestedTypeMsType do not really
  //			// have their own RecordNumber).
  //			applicator.addApplierDependency(this, nestedDefinitionApplier);
  //			setDeferred();
  //		}
  		else if (dependee instanceof BitfieldTypeApplier) {
  			RecordNumber recNum =
  				((AbstractBitfieldMsType) ((BitfieldTypeApplier) dependee).getMsType()).getElementRecordNumber();
  			MsTypeApplier underlyingApplier = applicator.getTypeApplier(recNum);
  			if (underlyingApplier instanceof EnumTypeApplier) {
  				applicator.addApplierDependency(this, underlyingApplier);
  				setDeferred();
  			}
  		}
  		//We are assuming that bitfields on typedefs will not be defined.
  	}
  
  	private void applyInternal() throws CancelledException, PdbException {
  
  		if (isApplied()) {
  			return;
  		}
  		Composite composite = (Composite) dataType;
  
  		AbstractCompositeMsType type = (AbstractCompositeMsType) msType;
  
  		boolean applyCpp = applyBaseClasses;
  		if (type instanceof AbstractUnionMsType) {
  			applyCpp = false;
  			if (hasBaseClasses()) {
  				pdbLogAndInfoMessage(this,
  					"Unexpected base classes for union type: " + type.getName());
  			}
  		}
  		if (applyCpp) {
  			applyCpp(composite, type);
  		}
  		else {
  			applyBasic(composite, type);
  		}
  		setApplied();
  	}
  
  	//==============================================================================================
  	private void applyBasic(Composite composite, AbstractCompositeMsType type)
  			throws CancelledException, PdbException {
  
  		//boolean isClass = (type instanceof AbstractClassMsType || actsLikeClass(applicator, type));
  		boolean isClass = (type instanceof AbstractClassMsType);
  
  		int size = getSizeInt();
  
  		// Fill in composite definition details.
  		FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial(
  			applicator, type.getFieldDescriptorListRecordNumber());
  
  		clearComponents(composite);
  		members = new ArrayList<>();
  		componentComments = new HashMap<>();
  
  		addMembers(composite, fieldListApplier);
  
  		if (!DefaultCompositeMember.applyDataTypeMembers(composite, isClass, size, members,
  			msg -> reconstructionWarn(msg), applicator.getCancelOnlyWrappingMonitor())) {
  			clearComponents(composite);
  		}
  
  		setComponentComments(composite);
  	}
  
  	private void setComponentComments(Composite composite) {
  		if (composite instanceof Structure) {
  			Structure structure = (Structure) composite;
  			for (Map.Entry<Integer, String> entry : componentComments.entrySet()) {
  				DataTypeComponent component = structure.getComponentAt(entry.getKey());
  				if (component == null) {
  					pdbLogAndInfoMessage(this, "Could not set comment for 'missing' componenent " +
  						entry.getKey() + " for: " + structure.getName());
  					return;
  				}
  				component.setComment(entry.getValue());
  			}
  		}
  	}
  
  	//==============================================================================================
  	private void applyCpp(Composite composite, AbstractCompositeMsType type)
  			throws PdbException, CancelledException {
  		// Fill in composite definition details.
  		FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial(
  			applicator, type.getFieldDescriptorListRecordNumber());
  		clearComponents(composite);
  		members = new ArrayList<>(); // TODO: temporary for old "basic" mechanism
  		componentComments = new HashMap<>(); // TODO: temporary for old "basic" mechanism
  
  		addClassTypeBaseClasses(composite, fieldListApplier);
  		addMembers(composite, fieldListApplier);
  
  		if (!classType.validate()) {
  			// TODO: Investigate.  We should do this check for some classes somewhere.  Should
  			// we do it here.  Set breakpoint here to investigate.
  		}
  		classType.createLayout(applicator.getPdbApplicatorOptions().getClassLayout(),
  			applicator.getVbtManager(), applicator.getCancelOnlyWrappingMonitor());
  	}
  
  	//==============================================================================================
  	private void reconstructionWarn(String msg) {
  		//TODO: if statement/contents temporary
  		if (msg.contains("failed to align") && hasHiddenComponents()) {
  			msg = msg.replaceFirst("PDB", "PDB CLASS");
  		}
  		Msg.warn(this, msg);
  	}
  
  	//==============================================================================================
  	@Override
  	void deferredApply() throws PdbException, CancelledException {
  		if (isDeferred()) {
  			applyInternal();
  		}
  	}
  
  	//==============================================================================================
  	//==============================================================================================
  	@Override
  	CompositeTypeApplier getDependencyApplier() {
  		if (definitionApplier != null && definitionApplier instanceof CompositeTypeApplier) {
  			return (CompositeTypeApplier) definitionApplier;
  		}
  		return this;
  	}
  
  	String getName() {
  		return getMsType().getName();
  	}
  
  	@Override
  	DataType getDataType() {
  		if (resolved) {
  			return resolvedDataType;
  		}
  		getOrCreateComposite();
  		return dataType;
  	}
  
  	@Override
  	DataType getCycleBreakType() {
  		if (isForwardReference() && definitionApplier != null && definitionApplier.isApplied()) {
  			return definitionApplier.getDataType();
  		}
  		return dataType;
  	}
  
  	boolean hasUniqueName() {
  		return ((AbstractCompositeMsType) msType).getMsProperty().hasUniqueName();
  	}
  
  	@Override
  	BigInteger getSize() {
  		return ((AbstractCompositeMsType) getDependencyApplier().getMsType()).getSize();
  	}
  
  	// TODO: 
  	// Taken from PdbUtil without change.  Would have had to change access on class PdbUtil and
  	//  this ensureSize method to public to make it accessible.  Can revert to using PdbUtil
  	//  once we move this new module from Contrib to Features/PDB.
  	final static void clearComponents(Composite composite) {
  		if (composite instanceof Structure) {
  			((Structure) composite).deleteAll();
  		}
  		else {
  			while (composite.getNumComponents() > 0) {
  				composite.delete(0);
  			}
  		}
  	}
  
  	private Composite createEmptyComposite(AbstractCompositeMsType type) {
  
  		SymbolPath fixedPath = getFixedSymbolPath();
  		CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent());
  
  		Composite composite;
  		if (type instanceof AbstractClassMsType) {
  			applicator.predefineClass(fixedPath);
  			composite = new StructureDataType(categoryPath, fixedPath.getName(), 0,
  				applicator.getDataTypeManager());
  		}
  		else if (type instanceof AbstractStructureMsType) {
  			composite = new StructureDataType(categoryPath, fixedPath.getName(), 0,
  				applicator.getDataTypeManager());
  		}
  		else if (type instanceof AbstractUnionMsType) {
  			composite = new UnionDataType(categoryPath, fixedPath.getName(),
  				applicator.getDataTypeManager());
  		}
  		else { // InterfaceMsType
  			String message = "Unsupported datatype (" + type.getClass().getSimpleName() + "): " +
  				fixedPath.getPath();
  			applicator.appendLogMsg(message);
  			return null;
  		}
  		return composite;
  	}
  
  	private boolean hasBaseClasses() {
  		AbstractCompositeMsType defType;
  		if (definitionApplier == null) {
  			if (isForwardReference()) {
  				return false;
  			}
  			defType = (AbstractCompositeMsType) msType;
  		}
  		else {
  			defType = (AbstractCompositeMsType) definitionApplier.getMsType();
  		}
  		MsTypeApplier applier =
  			applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber());
  		if (!(applier instanceof FieldListTypeApplier)) {
  			return false;
  		}
  		FieldListTypeApplier fieldListApplier = (FieldListTypeApplier) applier;
  		AbstractFieldListMsType fieldListType =
  			((AbstractFieldListMsType) fieldListApplier.getMsType());
  		if (fieldListType.getBaseClassList().size() != 0) {
  			return true;
  		}
  		return (fieldListType.getBaseClassList().size() != 0);
  	}
  
  	private boolean hasHiddenComponents() {
  		AbstractCompositeMsType defType;
  		if (definitionApplier == null) {
  			if (isForwardReference()) {
  				return false;
  			}
  			defType = (AbstractCompositeMsType) msType;
  		}
  		else {
  			defType = (AbstractCompositeMsType) definitionApplier.getMsType();
  		}
  
  		// Note: if a "class" only has structure fields--does not have member functions, base
  		//  class, virtual inheritance, etc., then it acts like a structure, meaning that there
  		//  should be no extra fields for pvft, pvbt, base and virtual class components.
  		//  So... it might not be good to return "true" for just checking if the type is an
  		//  instanceof AbstractClassMsType.
  
  		MsTypeApplier applier =
  			applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber());
  		if (!(applier instanceof FieldListTypeApplier)) {
  			return false;
  		}
  		FieldListTypeApplier fieldListApplier = (FieldListTypeApplier) applier;
  		AbstractFieldListMsType fieldListType =
  			((AbstractFieldListMsType) fieldListApplier.getMsType());
  
  		return (fieldListType.getMethodList().size() != 0 ||
  			fieldListType.getBaseClassList().size() != 0);
  	}
  
  	private void addClassTypeBaseClasses(Composite composite, FieldListTypeApplier fieldListApplier)
  			throws PdbException {
  
  		AbstractCompositeMsType type = (AbstractCompositeMsType) msType;
  
  		for (MsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) {
  			if (!(baseApplierIterated instanceof BaseClassTypeApplier)) {
  				applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() +
  					" seen where BaseClassTypeApplier expected for " + type.getName());
  				continue;
  			}
  			BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated;
  			MsTypeApplier baseClassTypeApplier =
  				applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber());
  			if (!(baseClassTypeApplier instanceof CompositeTypeApplier)) {
  				applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() +
  					" seen where CompositeTypeApplier expected for " + type.getName());
  				continue;
  			}
  
  			AbstractMsType baseClassMsType = baseTypeApplier.getMsType();
  			if (baseClassMsType instanceof AbstractBaseClassMsType) {
  				applyDirectBaseClass((AbstractBaseClassMsType) baseClassMsType);
  			}
  			else if (baseClassMsType instanceof AbstractVirtualBaseClassMsType) {
  				applyDirectVirtualBaseClass((AbstractVirtualBaseClassMsType) baseClassMsType);
  			}
  			else if (baseClassMsType instanceof AbstractIndirectVirtualBaseClassMsType) {
  				applyIndirectVirtualBaseClass(
  					(AbstractIndirectVirtualBaseClassMsType) baseClassMsType);
  			}
  			else {
  				throw new AssertException(
  					"Unknown base class type: " + baseClassMsType.getClass().getSimpleName());
  			}
  		}
  	}
  
  	private void applyDirectBaseClass(AbstractBaseClassMsType base) throws PdbException {
  		CppCompositeType underlyingClassType =
  			getUnderlyingClassType(base.getBaseClassRecordNumber());
  		if (underlyingClassType == null) {
  			return;
  		}
  		ClassFieldMsAttributes atts = base.getAttributes();
  		int offset = PdbApplicator.bigIntegerToInt(applicator, base.getOffset());
  		classType.addDirectBaseClass(underlyingClassType, convertAttributes(atts), offset);
  	}
  
  	private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base)
  			throws PdbException {
  		CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber());
  		if (underlyingCt == null) {
  			return;
  		}
  		DataType vbtptr =
  			getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber());
  		ClassFieldMsAttributes atts = base.getAttributes();
  		int basePointerOffset =
  			PdbApplicator.bigIntegerToInt(applicator, base.getBasePointerOffset());
  		int offsetFromVbt = PdbApplicator.bigIntegerToInt(applicator, base.getBaseOffsetFromVbt());
  		classType.addDirectVirtualBaseClass(underlyingCt, convertAttributes(atts),
  			basePointerOffset, vbtptr, offsetFromVbt);
  	}
  
  	private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base)
  			throws PdbException {
  		CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber());
  		if (underlyingCt == null) {
  			return;
  		}
  		DataType vbtptr =
  			getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber());
  		ClassFieldMsAttributes atts = base.getAttributes();
  		int basePointerOffset =
  			PdbApplicator.bigIntegerToInt(applicator, base.getBasePointerOffset());
  		int offsetFromVbt = PdbApplicator.bigIntegerToInt(applicator, base.getBaseOffsetFromVbt());
  		classType.addIndirectVirtualBaseClass(underlyingCt, convertAttributes(atts),
  			basePointerOffset, vbtptr, offsetFromVbt);
  	}
  
  	private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber) {
  		MsTypeApplier baseUnderlyingApplier = applicator.getTypeApplier(recordNumber);
  		if (!(baseUnderlyingApplier instanceof CompositeTypeApplier)) {
  			applicator.appendLogMsg(baseUnderlyingApplier.getClass().getSimpleName() +
  				" seen where CompositeTypeApplier expected for base class.");
  			return null;
  		}
  		CompositeTypeApplier baseApplier = (CompositeTypeApplier) baseUnderlyingApplier;
  		CppCompositeType underlyingClassType = baseApplier.getClassType();
  		if (underlyingClassType == null) {
  			applicator.appendLogMsg("Underlying base class type is null.");
  		}
  		return underlyingClassType;
  	}
  
  	private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber) {
  		MsTypeApplier vbptrApplier = applicator.getTypeApplier(recordNumber);
  		if (vbptrApplier != null) {
  			if (vbptrApplier instanceof PointerTypeApplier) {
  				return vbptrApplier.getDataType();
  			}
  		}
  		applicator.appendLogMsg("Generating a generic Virtual Base Table Pointer.");
  		return new PointerDataType();
  	}
  
  	private static CppCompositeType.ClassFieldAttributes convertAttributes(
  			ClassFieldMsAttributes atts) {
  		CppCompositeType.Access myAccess;
  		switch (atts.getAccess()) {
  			case PUBLIC:
  				myAccess = CppCompositeType.Access.PUBLIC;
  				break;
  			case PROTECTED:
  				myAccess = CppCompositeType.Access.PROTECTED;
  				break;
  			case PRIVATE:
  				myAccess = CppCompositeType.Access.PRIVATE;
  				break;
  			default:
  				myAccess = CppCompositeType.Access.BLANK;
  				break;
  		}
  		CppCompositeType.Property myProperty;
  		switch (atts.getProperty()) {
  			case VIRTUAL:
  				myProperty = CppCompositeType.Property.VIRTUAL;
  				break;
  			case STATIC:
  				myProperty = CppCompositeType.Property.STATIC;
  				break;
  			case FRIEND:
  				myProperty = CppCompositeType.Property.FRIEND;
  				break;
  			default:
  				myProperty = CppCompositeType.Property.BLANK;
  				break;
  		}
  		return new CppCompositeType.ClassFieldAttributes(myAccess, myProperty);
  	}
  
  	private void addMembers(Composite composite, FieldListTypeApplier fieldListApplier) {
  
  		AbstractCompositeMsType type = (AbstractCompositeMsType) msType;
  
  		for (MsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) {
  			boolean handled = true;
  			if (memberTypeApplierIterated instanceof MemberTypeApplier) {
  				MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated;
  				String memberName = memberTypeApplier.getName();
  
  				int offset =
  					PdbApplicator.bigIntegerToInt(applicator, memberTypeApplier.getOffset());
  				ClassFieldMsAttributes memberAttributes = memberTypeApplier.getAttribute();
  				memberAttributes.getAccess(); // TODO: do something with this and other attributes
  				MsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier();
  
  				if (fieldApplier instanceof CompositeTypeApplier) {
  					CompositeTypeApplier defApplier =
  						((CompositeTypeApplier) fieldApplier).getDefinitionApplier(
  							CompositeTypeApplier.class);
  					if (defApplier != null) {
  						fieldApplier = defApplier;
  					}
  				}
  				DataType fieldDataType = fieldApplier.getDataType();
  				boolean isFlexibleArray;
  				if (fieldApplier instanceof ArrayTypeApplier) {
  					isFlexibleArray = ((ArrayTypeApplier) fieldApplier).isFlexibleArray();
  				}
  				else {
  					isFlexibleArray = false;
  				}
  				if (fieldDataType == null) {
  					if (fieldApplier instanceof PrimitiveTypeApplier &&
  						((PrimitiveTypeApplier) fieldApplier).isNoType()) {
  						DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator,
  							memberName, fieldApplier, offset);
  						members.add(member);
  						componentComments.put(offset, "NO_TYPE");
  					}
  					else {
  						applicator.appendLogMsg("PDB Warning: No conversion for " + memberName +
  							" " + fieldApplier.getMsType().getClass().getSimpleName() +
  							" in composite " + composite.getName());
  					}
  				}
  				else {
  					DefaultPdbUniversalMember member =
  						new DefaultPdbUniversalMember(applicator, memberName, fieldApplier, offset);
  					members.add(member);
  					classType.addMember(memberName, fieldDataType, isFlexibleArray,
  						convertAttributes(memberAttributes), offset);
  				}
  			}
  			else if (memberTypeApplierIterated instanceof EnumerateTypeApplier) {
  				EnumerateTypeApplier enumerateTypeApplier =
  					(EnumerateTypeApplier) memberTypeApplierIterated;
  				String fieldName = enumerateTypeApplier.getName();
  				Numeric numeric = enumerateTypeApplier.getNumeric();
  				// TODO: some work
  				pdbLogAndInfoMessage(this,
  					"Don't know how to apply EnumerateTypeApplier fieldName " + fieldName +
  						" and value " + numeric + " within " + msType.getName());
  			}
  			else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) {
  				VirtualFunctionTablePointerTypeApplier vtPtrApplier =
  					(VirtualFunctionTablePointerTypeApplier) memberTypeApplierIterated;
  				String vftPtrMemberName = vtPtrApplier.getMemberName();
  				int offset = vtPtrApplier.getOffset();
  				DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator,
  					vftPtrMemberName, vtPtrApplier, offset);
  				members.add(member);
  				//classType.addMember(vftPtrMemberName, vtPtrApplier.getDataType(), false, offset);
  				classType.addVirtualFunctionTablePointer(vftPtrMemberName,
  					vtPtrApplier.getDataType(), offset);
  			}
  			else if (memberTypeApplierIterated instanceof NestedTypeApplier) {
  				// Need to make sure that "this" class id dependent on all elements composing the
  				// nested definition, but we need to create the nested definition during the
  				// creation of this class. (NestedTypeApplier and NestedTypeMsType do not really
  				// have their own RecordNumber).
  				// 20200114: think this is a nested typedef.
  				NestedTypeApplier nestedTypeApplier = (NestedTypeApplier) memberTypeApplierIterated;
  				String memberTypeName = nestedTypeApplier.getTypeName();
  				String memberName = nestedTypeApplier.getMemberName();  // use this
  				// TODO: we are assuming that the offset is zero (0) for the call.  Need to dig
  				//  more to confirm this.  Is ever anything but just one nested type?  The pdb.exe
  				//  generates these all at offset 0.
  				// TODO: Nested types are currently an issue for
  				//  DefaultCompositeMember.applyDataTypeMembers().
  				//  Need to investigate what to do here.  It could be just when the specific
  				//  composite is a member of itself.
  				if (type.getName().equals(memberTypeName)) {
  					// We are skipping because we've had issues and do not know what is going on
  					//  at the moment. (I think they were dependency issues... been a while.)
  					//  See not above the "if" condition.
  //					pdbLogAndInfoMessage(this, "Skipping Composite Nested type member: " +
  //						memberName + " within " + type.getName());
  					// TODO: Investigate.  What does it mean when the internally defined type
  					//  conficts with the name of the outer type.
  					continue;
  				}
  				// TODO: believe the thing to do is to show that these are types that are
  				//  defined within the namespace of this containing type.  This might be
  				//  the place to do it... that is if we don't identify them separately
  				//  falling under the namespace of this composite.
  
  //				AbstractMsTypeApplier nestedDefinitionApplier =
  //					nestedTypeApplier.getNestedTypeDefinitionApplier().getDependencyApplier();
  //
  //				DataType ndt = nestedDefinitionApplier.getDataType(); //use this
  //				int ndtl = ndt.getLength(); //use this
  //
  //				AbstractMsType ndms = nestedTypeApplier.getMsType();
  //
  //				BigInteger val = nestedTypeApplier.getSize();
  //				int offset = 0; // ???? TODO..,
  //				DataType nt = nestedTypeApplier.getDataType();
  //				ClassFieldMsAttributes a = nestedTypeApplier.getAttributes();
  //
  //				// TODO: hoping this is right... 20200521... how/where do we get offset?
  //				Default2PdbMember member =
  //					new Default2PdbMember(applicator, memberName, nestedDefinitionApplier, offset);
  //				members.add(member);
  			}
  			else if (memberTypeApplierIterated instanceof NoTypeApplier) {
  				AbstractMsType msNoType = memberTypeApplierIterated.getMsType();
  				if (msNoType instanceof AbstractStaticMemberMsType) {
  					// TODO: Investigate anything that hits here (set break point), see if we
  					//  see dot apply the information.  If so, probably should create an applier
  					//  for the contained MS type.
  				}
  				else {
  					handled = false;
  				}
  			}
  			else {
  				handled = false;
  			}
  			if (!handled) {
  				applicator.appendLogMsg(
  					memberTypeApplierIterated.getClass().getSimpleName() + " with contained " +
  						memberTypeApplierIterated.getMsType().getClass().getSimpleName() +
  						" unexpected for " + msType.getName());
  			}
  		}
  	}
  
  //	/**
  //	 * <code>NoType</code> provides ability to hang NoType into a composite type by faking
  //	 * it with a zero-length bitfield.  This is a bit of a kludge
  //	 * This will be transformed to a normal BitFieldDataType when cloned.
  //	 */
  //	private class NoType extends PdbBitField {
  //		private NoType(PdbApplicator applicator) throws InvalidDataTypeException {
  //			super(new CharDataType(applicator.getDataTypeManager()), 0, 0);
  //		}
  //	}
  //
  }
  