/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.dfa; import java.util.ArrayList; import java.util.BitSet; import java.util.List; import java.util.StringTokenizer; import net.sourceforge.pmd.lang.ast.Node; /** * Each data flow contains a set of DataFlowNodes. * * @author raik */ public abstract class AbstractDataFlowNode implements DataFlowNode { protected Node node; protected List<DataFlowNode> parents = new ArrayList<>(); protected List<DataFlowNode> children = new ArrayList<>(); protected BitSet type = new BitSet(); protected List<VariableAccess> variableAccess = new ArrayList<>(); protected List<DataFlowNode> dataFlow; protected int line; public AbstractDataFlowNode(List<DataFlowNode> dataFlow) { this.dataFlow = dataFlow; if (!this.dataFlow.isEmpty()) { DataFlowNode parent = this.dataFlow.get(this.dataFlow.size() - 1); parent.addPathToChild(this); } this.dataFlow.add(this); } public AbstractDataFlowNode(List<DataFlowNode> dataFlow, Node node) { this(dataFlow); this.node = node; node.setDataFlowNode(this); this.line = node.getBeginLine(); } @Override public void addPathToChild(DataFlowNode child) { DataFlowNode thisChild = child; // TODO - throw an exception if already contained in children list? if (!this.children.contains(thisChild) || this.equals(thisChild)) { this.children.add(thisChild); thisChild.getParents().add(this); } } @Override public boolean removePathToChild(DataFlowNode child) { DataFlowNode thisChild = child; thisChild.getParents().remove(this); return this.children.remove(thisChild); } @Override public void reverseParentPathsTo(DataFlowNode destination) { while (!parents.isEmpty()) { DataFlowNode parent = parents.get(0); parent.removePathToChild(this); parent.addPathToChild(destination); } } @Override public int getLine() { return this.line; } @Override public void setType(int type) { this.type.set(type); } @Override public boolean isType(int intype) { try { return type.get(intype); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } return false; } @Override public Node getNode() { return this.node; } @Override public List<DataFlowNode> getChildren() { return this.children; } @Override public List<DataFlowNode> getParents() { return this.parents; } @Override public List<DataFlowNode> getFlow() { return this.dataFlow; } @Override public int getIndex() { return this.dataFlow.indexOf(this); } @Override public void setVariableAccess(List<VariableAccess> variableAccess) { if (this.variableAccess.isEmpty()) { this.variableAccess = variableAccess; } else { this.variableAccess.addAll(variableAccess); } } @Override public List<VariableAccess> getVariableAccess() { return this.variableAccess; } @Override public String toString() { String res = "DataFlowNode: line " + this.getLine() + ", "; String tmp = type.toString(); String newTmp = ""; for (char c : tmp.toCharArray()) { if (c != '{' && c != '}' && c != ' ') { newTmp += c; } } for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) { int newTmpInt = Integer.parseInt(st.nextToken()); res += "(" + stringFromType(newTmpInt) + ")"; } res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1); res += node.getImage() == null ? "" : "(" + this.node.getImage() + ")"; return res; } private String stringFromType(int intype) { return NodeType.stringFromType(intype); } }