private AttributedVertex addDataFlowFeatureGraph(PcodeOpAST pcode, int windowSize,
			AttributedGraph graph, boolean primaryBase) {
		Queue<DataflowQueueElement> varnodes = new LinkedList<>();
		VarnodeAST vn = (VarnodeAST) pcode.getOutput();

		Set<PcodeOpAST> featuredOps = provider.getModel().getFeaturedOps();
		Map<VarnodeAST, AttributedVertex> varnodesToVertices = new HashMap<>();
		Map<PcodeOpAST, AttributedVertex> opsToVertices = new HashMap<>();
		AttributedVertex baseVertex = null;
		if (vn == null) {
			baseVertex = graph.addVertex(
				BSimFeatureGraphType.DATAFLOW_PREFIX + Integer.toString(graph.getVertexCount()),
				BSimFeatureGraphType.VOID_BASE);
			vn = new VarnodeAST(Address.NO_ADDRESS, 0, 0);
		}
		else {
			baseVertex = graph.addVertex(
				BSimFeatureGraphType.DATAFLOW_PREFIX + Integer.toString(graph.getVertexCount()),
				vn.toString(plugin.getCurrentProgram().getLanguage()));
			baseVertex.setAttribute(BSimFeatureGraphType.SIZE, Integer.toString(vn.getSize()));
		}

		baseVertex.setVertexType(primaryBase ? BSimFeatureGraphType.BASE_VARNODE_VERTEX
				: BSimFeatureGraphType.SECONDARY_BASE_VARNODE_VERTEX);
		varnodesToVertices.put(vn, baseVertex);

		DataflowQueueElement base = new DataflowQueueElement(vn, windowSize);
		varnodes.add(base);

		//elements of queue should be correspond to varnodes (or artificial "base" varnode) which 
		//have a defining/corresponding pcode op
		//so no constants or function inputs in the queue (but they will be added to the *graph*)
		while (!varnodes.isEmpty()) {
			DataflowQueueElement currentElement = varnodes.poll();
			VarnodeAST outputVarnode = currentElement.vn;
			AttributedVertex varnodeVertex = varnodesToVertices.get(outputVarnode);
			PcodeOpAST currentPcode = null;
			if (outputVarnode.getAddress().equals(Address.NO_ADDRESS)) {
				//this can only happen when the pcode argument to this method has no output
				currentPcode = pcode;
			}
			else {
				currentPcode = (PcodeOpAST) outputVarnode.getDef();
			}
			//varnode vertex is collapsed if corresponding varnode is defined by a collapsed op
			//don't collapse special case where op has no output 
			boolean collapsedOp = false;
			if (!featuredOps.contains(currentPcode) && currentPcode != pcode) {
				collapsedOp = true;
			}
			if (collapsedOp) {
				varnodeVertex.setVertexType(BSimFeatureGraphType.COLLAPSED_VARNODE);
				if (opsToVertices.containsKey(currentPcode)) {
					continue; //avoid getting stuck in collapsed loop
				}
			}
			AttributedVertex pcodeVertex = opsToVertices.computeIfAbsent(currentPcode,
				x -> graph.addVertex(
					BSimFeatureGraphType.DATAFLOW_PREFIX + Integer.toString(graph.getVertexCount()),
					x.getMnemonic()));
			if (collapsedOp) {
				pcodeVertex.setVertexType(BSimFeatureGraphType.COLLAPSED_OP);
			}
			else {
				pcodeVertex.setVertexType(BSimFeatureGraphType.PCODE_OP_VERTEX);
			}
			pcodeVertex.setAttribute(BSimFeatureGraphType.OP_ADDRESS,
				currentPcode.getSeqnum().getTarget().toString());
			pcodeVertex.setAttribute(BSimFeatureGraphType.PCODE_OUTPUT,
				currentPcode.getOutput() == null ? BSimFeatureGraphType.VOID_BASE
						: currentPcode.getOutput()
								.toString(plugin.getCurrentProgram().getLanguage()));
			AttributedEdge edge = graph.addEdge(pcodeVertex, varnodeVertex);
			if (collapsedOp) {
				edge.setEdgeType(BSimFeatureGraphType.COLLAPSED_OUT);
			}
			else {
				edge.setEdgeType(BSimFeatureGraphType.DATAFLOW_OUT);
			}
			int start = 0;
			int stop = currentPcode.getNumInputs();
			switch (currentPcode.getOpcode()) {
				case PcodeOp.CPOOLREF:
					stop = 1;
					break;
				case PcodeOp.INDIRECT:
					stop -= 1;
					break;
				case PcodeOp.CALL:
				case PcodeOp.CALLIND:
				case PcodeOp.CALLOTHER:
				case PcodeOp.CBRANCH:     //should only occur with COMBINED or DUAL_FLOW features
				case PcodeOp.LOAD:
				case PcodeOp.RETURN:
				case PcodeOp.STORE:
					start += 1;
					break;
				case PcodeOp.INT_LEFT:
				case PcodeOp.INT_RIGHT:
				case PcodeOp.INT_SRIGHT:
				case PcodeOp.SUBPIECE:
					if (currentPcode.getInput(1).isConstant()) {
						stop -= 1;
					}
					break;
				default:
					break;
			}
			for (int j = start; j < stop; j++) {
				Varnode iv = currentPcode.getInput(j);
				if (iv == null) {
					Msg.info(this, "Null input for pcode " + currentPcode.getMnemonic());
					continue;
				}
				VarnodeAST inputVarnode = (VarnodeAST) iv;
				AttributedVertex inputVarnodeVertex =
					varnodesToVertices.computeIfAbsent(inputVarnode,
						x -> graph.addVertex(
							BSimFeatureGraphType.DATAFLOW_PREFIX +
								Integer.toString(graph.getVertexCount()),
							inputVarnode.toString(plugin.getCurrentProgram().getLanguage())));
				inputVarnodeVertex.setVertexType(BSimFeatureGraphType.DEFAULT_VERTEX);
				if (inputVarnode.isConstant() && inputVarnode.isInput()) {
					inputVarnodeVertex.setVertexType(BSimFeatureGraphType.CONSTANT_FUNCTION_INPUT);
				}
				else {
					if (inputVarnode.isConstant()) {
						inputVarnodeVertex.setVertexType(BSimFeatureGraphType.CONSTANT_VERTEX);
					}
					if (inputVarnode.isInput()) {
						inputVarnodeVertex.setVertexType(BSimFeatureGraphType.FUNCTION_INPUT);
					}
				}
				if (inputVarnode.isAddress()) {
					inputVarnodeVertex.setVertexType(BSimFeatureGraphType.VARNODE_ADDRESS);
				}
				inputVarnodeVertex.setAttribute(BSimFeatureGraphType.SIZE,
					Integer.toString(inputVarnode.getSize()));
				edge = graph.addEdge(inputVarnodeVertex, pcodeVertex);
				if (collapsedOp) {
					edge.setEdgeType(BSimFeatureGraphType.COLLAPSED_IN);
				}
				else {
					edge.setEdgeType(BSimFeatureGraphType.DATAFLOW_IN);
				}
				if (inputVarnode.getDef() != null) {
					int numHops = collapsedOp ? currentElement.remainingHops
							: currentElement.remainingHops - 1;
					if (numHops > 0) {
						DataflowQueueElement inputElement =
							new DataflowQueueElement(inputVarnode, numHops);
						varnodes.add(inputElement);
					}
				}
			}
		}
		return baseVertex;
	}
Returns the {@link AttributedGraph} created by (the last firing of) this action.
@return graph
Ghidra/Features/BSimFeatureVisualizer/src/main/java/ghidra/bsfv/HighlightAndGraphAction.java