private boolean recursiveMatchesDataTypePredicate(DataType dt) {
		if (matchesDataTypePredicate(dt)) {
			return true;
		}
		if (dt instanceof Array) {
			Array arrayDT = (Array) dt;
			DataType elementDT = arrayDT.getDataType();
			return recursiveMatchesDataTypePredicate(elementDT);
		}
		else if (dt instanceof Structure) {
			// handle Structures and general Composite's separately so
			// we can focus on just the defined elements of a structure
			Structure comp = (Structure) dt;
			for (DataTypeComponent dtc : comp.getDefinedComponents()) {
				if (recursiveMatchesDataTypePredicate(dtc.getDataType())) {
					return true;
				}
			}
			return false;
		}
		else if (dt instanceof Composite) {
			Composite comp = (Composite) dt;
			for (DataTypeComponent dtc : comp.getComponents()) {
				if (recursiveMatchesDataTypePredicate(dtc.getDataType())) {
					return true;
				}
			}
			return false;
		}
		else if (dt instanceof TypeDef) {
			TypeDef tdDT = (TypeDef) dt;
			return recursiveMatchesDataTypePredicate(tdDT.getBaseDataType());
		}
		return false;
	}
LIFO stack of iterators.  Newly found iterators of sub-components are
pushed onto the end and become the current iterator.  When an iterator is exhausted, 
it is popped of the end and the uncovered iterator is now the current.
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/DefinedDataIterator.java