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