001 /**
002 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003 */
004 package net.sourceforge.pmd.lang.dfa;
005
006 import java.util.ArrayList;
007 import java.util.BitSet;
008 import java.util.HashMap;
009 import java.util.List;
010 import java.util.Map;
011 import java.util.StringTokenizer;
012
013 import net.sourceforge.pmd.lang.ast.Node;
014
015 /**
016 * @author raik
017 * <p/>
018 * Each data flow contains a set of DataFlowNodes.
019 */
020 public abstract class AbstractDataFlowNode implements DataFlowNode {
021
022 protected Node node;
023 protected Map<Integer, String> typeMap = new HashMap<Integer, String>();
024
025 protected List<DataFlowNode> parents = new ArrayList<DataFlowNode>();
026 protected List<DataFlowNode> children = new ArrayList<DataFlowNode>();
027 protected BitSet type = new BitSet();
028 protected List<VariableAccess> variableAccess = new ArrayList<VariableAccess>();
029 protected List<DataFlowNode> dataFlow;
030 protected int line;
031
032 public AbstractDataFlowNode(List<DataFlowNode> dataFlow) {
033 this.dataFlow = dataFlow;
034 if (!this.dataFlow.isEmpty()) {
035 DataFlowNode parent = this.dataFlow.get(this.dataFlow.size() - 1);
036 parent.addPathToChild(this);
037 }
038 this.dataFlow.add(this);
039 }
040
041 public AbstractDataFlowNode(List<DataFlowNode> dataFlow, Node node) {
042 this(dataFlow);
043
044 this.node = node;
045 node.setDataFlowNode(this);
046 this.line = node.getBeginLine();
047 }
048
049 public void addPathToChild(DataFlowNode child) {
050 DataFlowNode thisChild = child;
051 // TODO - throw an exception if already contained in children list?
052 if (!this.children.contains(thisChild) || this.equals(thisChild)) {
053 this.children.add(thisChild);
054 thisChild.getParents().add(this);
055 }
056 }
057
058 public boolean removePathToChild(DataFlowNode child) {
059 DataFlowNode thisChild = child;
060 thisChild.getParents().remove(this);
061 return this.children.remove(thisChild);
062 }
063
064 public void reverseParentPathsTo(DataFlowNode destination) {
065 while (!parents.isEmpty()) {
066 DataFlowNode parent = parents.get(0);
067 parent.removePathToChild(this);
068 parent.addPathToChild(destination);
069 }
070 }
071
072 public int getLine() {
073 return this.line;
074 }
075
076 public void setType(int type) {
077 this.type.set(type);
078 }
079
080 public boolean isType(int intype) {
081 try {
082 return type.get(intype);
083 } catch (IndexOutOfBoundsException e) {
084 e.printStackTrace();
085 }
086 return false;
087 }
088
089 public Node getNode() {
090 return this.node;
091 }
092
093 public List<DataFlowNode> getChildren() {
094 return this.children;
095 }
096
097 public List<DataFlowNode> getParents() {
098 return this.parents;
099 }
100
101 public List<DataFlowNode> getFlow() {
102 return this.dataFlow;
103 }
104
105 public int getIndex() {
106 return this.dataFlow.indexOf(this);
107 }
108
109 public void setVariableAccess(List<VariableAccess> variableAccess) {
110 if (this.variableAccess.isEmpty()) {
111 this.variableAccess = variableAccess;
112 } else {
113 this.variableAccess.addAll(variableAccess);
114 }
115 }
116
117 public List<VariableAccess> getVariableAccess() {
118 return this.variableAccess;
119 }
120
121 @Override
122 public String toString() {
123 String res = "DataFlowNode: line " + this.getLine() + ", ";
124 String tmp = type.toString();
125 String newTmp = "";
126 for (char c : tmp.toCharArray()) {
127 if (c != '{' && c != '}' && c != ' ') {
128 newTmp += c;
129 }
130 }
131 for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) {
132 int newTmpInt = Integer.parseInt(st.nextToken());
133 res += "(" + stringFromType(newTmpInt) + ")";
134 }
135 res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1);
136 res += node.getImage() == null ? "" : "(" + this.node.getImage() + ")";
137 return res;
138 }
139
140 private String stringFromType(int intype) {
141 if (typeMap.isEmpty()) {
142 typeMap.put(NodeType.IF_EXPR, "IF_EXPR");
143 typeMap.put(NodeType.IF_LAST_STATEMENT, "IF_LAST_STATEMENT");
144 typeMap.put(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, "IF_LAST_STATEMENT_WITHOUT_ELSE");
145 typeMap.put(NodeType.ELSE_LAST_STATEMENT, "ELSE_LAST_STATEMENT");
146 typeMap.put(NodeType.WHILE_LAST_STATEMENT, "WHILE_LAST_STATEMENT");
147 typeMap.put(NodeType.WHILE_EXPR, "WHILE_EXPR");
148 typeMap.put(NodeType.SWITCH_START, "SWITCH_START");
149 typeMap.put(NodeType.CASE_LAST_STATEMENT, "CASE_LAST_STATEMENT");
150 typeMap.put(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, "SWITCH_LAST_DEFAULT_STATEMENT");
151 typeMap.put(NodeType.SWITCH_END, "SWITCH_END");
152 typeMap.put(NodeType.FOR_INIT, "FOR_INIT");
153 typeMap.put(NodeType.FOR_EXPR, "FOR_EXPR");
154 typeMap.put(NodeType.FOR_UPDATE, "FOR_UPDATE");
155 typeMap.put(NodeType.FOR_BEFORE_FIRST_STATEMENT, "FOR_BEFORE_FIRST_STATEMENT");
156 typeMap.put(NodeType.FOR_END, "FOR_END");
157 typeMap.put(NodeType.DO_BEFORE_FIRST_STATEMENT, "DO_BEFORE_FIRST_STATEMENT");
158 typeMap.put(NodeType.DO_EXPR, "DO_EXPR");
159 typeMap.put(NodeType.RETURN_STATEMENT, "RETURN_STATEMENT");
160 typeMap.put(NodeType.BREAK_STATEMENT, "BREAK_STATEMENT");
161 typeMap.put(NodeType.CONTINUE_STATEMENT, "CONTINUE_STATEMENT");
162 typeMap.put(NodeType.LABEL_STATEMENT, "LABEL_STATEMENT");
163 typeMap.put(NodeType.LABEL_LAST_STATEMENT, "LABEL_END");
164 typeMap.put(NodeType.THROW_STATEMENT, "THROW_STATEMENT");
165 }
166 if (!typeMap.containsKey(intype)) {
167 throw new RuntimeException("Couldn't find type id " + intype);
168 }
169 return typeMap.get(intype);
170 }
171
172 }
|