1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.dfa;
5
6 import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
7 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
8 import net.sourceforge.pmd.ast.SimpleNode;
9 import net.sourceforge.pmd.dfa.variableaccess.VariableAccess;
10
11 import java.util.ArrayList;
12 import java.util.BitSet;
13 import java.util.HashMap;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.StringTokenizer;
18
19 /**
20 * @author raik
21 * <p/>
22 * Each data flow contains a set of DataFlowNodes.
23 */
24 public class DataFlowNode implements IDataFlowNode {
25
26 private SimpleNode node;
27 private Map<Integer, String> typeMap = new HashMap<Integer, String>();
28
29 protected List<DataFlowNode> parents = new ArrayList<DataFlowNode>();
30 protected List<DataFlowNode> children = new ArrayList<DataFlowNode>();
31 protected BitSet type = new BitSet();
32 protected List<VariableAccess> variableAccess = new ArrayList<VariableAccess>();
33 protected LinkedList<DataFlowNode> dataFlow;
34 protected int line;
35
36 protected DataFlowNode() {
37 }
38
39 public DataFlowNode(SimpleNode node, LinkedList<DataFlowNode> dataFlow) {
40 this.dataFlow = dataFlow;
41 this.node = node;
42
43 node.setDataFlowNode(this);
44 this.line = node.getBeginLine();
45
46 if (!this.dataFlow.isEmpty()) {
47 DataFlowNode parent = this.dataFlow.getLast();
48 parent.addPathToChild(this);
49 }
50 this.dataFlow.addLast(this);
51 }
52
53 public void addPathToChild(IDataFlowNode child) {
54 DataFlowNode thisChild = (DataFlowNode) child;
55
56 if (!this.children.contains(thisChild) || this.equals(thisChild)) {
57 this.children.add(thisChild);
58 thisChild.parents.add(this);
59 }
60 }
61
62 public boolean removePathToChild(IDataFlowNode child) {
63 DataFlowNode thisChild = (DataFlowNode) child;
64 thisChild.parents.remove(this);
65 return this.children.remove(thisChild);
66 }
67
68 public void reverseParentPathsTo(IDataFlowNode destination) {
69 while (!parents.isEmpty()) {
70 DataFlowNode parent = parents.get(0);
71 parent.removePathToChild(this);
72 parent.addPathToChild(destination);
73 }
74 }
75
76 public int getLine() {
77 return this.line;
78 }
79
80 public void setType(int type) {
81 this.type.set(type);
82 }
83
84 public boolean isType(int intype) {
85 try {
86 return type.get(intype);
87 } catch (IndexOutOfBoundsException e) {
88 e.printStackTrace();
89 }
90 return false;
91 }
92
93 public SimpleNode getSimpleNode() {
94 return this.node;
95 }
96
97 public List<DataFlowNode> getChildren() {
98 return this.children;
99 }
100
101 public List<DataFlowNode> getParents() {
102 return this.parents;
103 }
104
105 public List<DataFlowNode> getFlow() {
106 return this.dataFlow;
107 }
108
109 public int getIndex() {
110 return this.dataFlow.indexOf(this);
111 }
112
113 public void setVariableAccess(List<VariableAccess> variableAccess) {
114 if (this.variableAccess.isEmpty()) {
115 this.variableAccess = variableAccess;
116 } else {
117 this.variableAccess.addAll(variableAccess);
118 }
119 }
120
121 public List<VariableAccess> getVariableAccess() {
122 return this.variableAccess;
123 }
124
125 public String toString() {
126 String res = "DataFlowNode: line " + this.getLine() + ", ";
127 if (node instanceof ASTMethodDeclaration || node instanceof ASTConstructorDeclaration) {
128 res += (node instanceof ASTMethodDeclaration) ? "(method)" : "(constructor)";
129 } else {
130 String tmp = type.toString();
131 String newTmp = "";
132 for (char c : tmp.toCharArray()) {
133 if (c != '{' && c != '}' && c != ' ') {
134 newTmp += c;
135 }
136 }
137 for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) {
138 int newTmpInt = Integer.parseInt(st.nextToken());
139 res += "(" + stringFromType(newTmpInt) + ")";
140 }
141 res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1);
142 res += (node.getImage() == null ? "" : "(" + this.node.getImage() + ")");
143 }
144 return res;
145 }
146
147 private String stringFromType(int intype) {
148 if (typeMap.isEmpty()) {
149 typeMap.put(NodeType.IF_EXPR, "IF_EXPR");
150 typeMap.put(NodeType.IF_LAST_STATEMENT, "IF_LAST_STATEMENT");
151 typeMap.put(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, "IF_LAST_STATEMENT_WITHOUT_ELSE");
152 typeMap.put(NodeType.ELSE_LAST_STATEMENT, "ELSE_LAST_STATEMENT");
153 typeMap.put(NodeType.WHILE_LAST_STATEMENT, "WHILE_LAST_STATEMENT");
154 typeMap.put(NodeType.WHILE_EXPR, "WHILE_EXPR");
155 typeMap.put(NodeType.SWITCH_START, "SWITCH_START");
156 typeMap.put(NodeType.CASE_LAST_STATEMENT, "CASE_LAST_STATEMENT");
157 typeMap.put(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, "SWITCH_LAST_DEFAULT_STATEMENT");
158 typeMap.put(NodeType.SWITCH_END, "SWITCH_END");
159 typeMap.put(NodeType.FOR_INIT, "FOR_INIT");
160 typeMap.put(NodeType.FOR_EXPR, "FOR_EXPR");
161 typeMap.put(NodeType.FOR_UPDATE, "FOR_UPDATE");
162 typeMap.put(NodeType.FOR_BEFORE_FIRST_STATEMENT, "FOR_BEFORE_FIRST_STATEMENT");
163 typeMap.put(NodeType.FOR_END, "FOR_END");
164 typeMap.put(NodeType.DO_BEFORE_FIRST_STATEMENT, "DO_BEFORE_FIRST_STATEMENT");
165 typeMap.put(NodeType.DO_EXPR, "DO_EXPR");
166 typeMap.put(NodeType.RETURN_STATEMENT, "RETURN_STATEMENT");
167 typeMap.put(NodeType.BREAK_STATEMENT, "BREAK_STATEMENT");
168 typeMap.put(NodeType.CONTINUE_STATEMENT, "CONTINUE_STATEMENT");
169 typeMap.put(NodeType.LABEL_STATEMENT, "LABEL_STATEMENT");
170 typeMap.put(NodeType.LABEL_LAST_STATEMENT, "LABEL_END");
171 typeMap.put(NodeType.THROW_STATEMENT, "THROW_STATEMENT");
172 }
173 if (!typeMap.containsKey(intype)) {
174 throw new RuntimeException("Couldn't find type id " + intype);
175 }
176 return typeMap.get(intype);
177 }
178
179 }