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 public DataFlowNode(SimpleNode node, LinkedList dataFlow) {
35 this.dataFlow = dataFlow;
36 this.node = node;
37
38 node.setDataFlowNode(this);
39 this.line = node.getBeginLine();
40
41 if (!this.dataFlow.isEmpty()) {
42 DataFlowNode parent = (DataFlowNode) this.dataFlow.getLast();
43 parent.addPathToChild(this);
44 }
45 this.dataFlow.addLast(this);
46 }
47
48 public void addPathToChild(IDataFlowNode child) {
49 DataFlowNode thisChild = (DataFlowNode) child;
50
51 if (!this.children.contains(thisChild) || this.equals(thisChild)) {
52 this.children.add(thisChild);
53 thisChild.parents.add(this);
54 }
55 }
56
57 public boolean removePathToChild(IDataFlowNode child) {
58 DataFlowNode thisChild = (DataFlowNode) child;
59 thisChild.parents.remove(this);
60 return this.children.remove(thisChild);
61 }
62
63 public void reverseParentPathsTo(IDataFlowNode destination) {
64 while (!parents.isEmpty()) {
65 DataFlowNode parent = (DataFlowNode) parents.get(0);
66 parent.removePathToChild(this);
67 parent.addPathToChild(destination);
68 }
69 }
70
71 public int getLine() {
72 return this.line;
73 }
74
75 public void setType(int type) {
76 this.type.set(type);
77 }
78
79 public boolean isType(int intype) {
80 try {
81 return type.get(intype);
82 } catch (IndexOutOfBoundsException e) {
83 e.printStackTrace();
84 }
85 return false;
86 }
87
88 public SimpleNode getSimpleNode() {
89 return this.node;
90 }
91
92 public List getChildren() {
93 return this.children;
94 }
95
96 public List getParents() {
97 return this.parents;
98 }
99
100 public List getFlow() {
101 return this.dataFlow;
102 }
103
104 public int getIndex() {
105 return this.dataFlow.indexOf(this);
106 }
107
108 public void setVariableAccess(List variableAccess) {
109 if (this.variableAccess.isEmpty()) {
110 this.variableAccess = variableAccess;
111 } else {
112 this.variableAccess.addAll(variableAccess);
113 }
114 }
115
116 public List getVariableAccess() {
117 return this.variableAccess;
118 }
119
120 public String toString() {
121 String res = "DataFlowNode: line " + this.getLine() + ", ";
122 if (node instanceof ASTMethodDeclaration || node instanceof ASTConstructorDeclaration) {
123 res += (node instanceof ASTMethodDeclaration) ? "(method)" : "(constructor)";
124 } else {
125 String tmp = type.toString();
126 String newTmp = "";
127 for (int i=0; i<tmp.length(); i++) {
128 if (tmp.charAt(i) != '{' && tmp.charAt(i) != '}'&& tmp.charAt(i) != ' ') {
129 newTmp += tmp.charAt(i);
130 }
131 }
132 for (StringTokenizer st = new StringTokenizer(newTmp, ","); st.hasMoreTokens();) {
133 int newTmpInt = Integer.parseInt(st.nextToken());
134 res += "(" + stringFromType(newTmpInt) + ")";
135 }
136 res += ", " + this.node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.')+1);
137 res += (node.getImage() == null ? "" : "(" + this.node.getImage() + ")");
138 }
139 return res;
140 }
141
142 private String stringFromType(int intype) {
143 if (typeMap.isEmpty()) {
144 typeMap.put(new Integer(NodeType.IF_EXPR), "IF_EXPR");
145 typeMap.put(new Integer(NodeType.IF_LAST_STATEMENT), "IF_LAST_STATEMENT");
146 typeMap.put(new Integer(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE), "IF_LAST_STATEMENT_WITHOUT_ELSE");
147 typeMap.put(new Integer(NodeType.ELSE_LAST_STATEMENT), "ELSE_LAST_STATEMENT");
148 typeMap.put(new Integer(NodeType.WHILE_LAST_STATEMENT), "WHILE_LAST_STATEMENT");
149 typeMap.put(new Integer(NodeType.WHILE_EXPR), "WHILE_EXPR");
150 typeMap.put(new Integer(NodeType.SWITCH_START), "SWITCH_START");
151 typeMap.put(new Integer(NodeType.CASE_LAST_STATEMENT), "CASE_LAST_STATEMENT");
152 typeMap.put(new Integer(NodeType.SWITCH_LAST_DEFAULT_STATEMENT), "SWITCH_LAST_DEFAULT_STATEMENT");
153 typeMap.put(new Integer(NodeType.SWITCH_END), "SWITCH_END");
154 typeMap.put(new Integer(NodeType.FOR_INIT), "FOR_INIT");
155 typeMap.put(new Integer(NodeType.FOR_EXPR), "FOR_EXPR");
156 typeMap.put(new Integer(NodeType.FOR_UPDATE), "FOR_UPDATE");
157 typeMap.put(new Integer(NodeType.FOR_BEFORE_FIRST_STATEMENT), "FOR_BEFORE_FIRST_STATEMENT");
158 typeMap.put(new Integer(NodeType.FOR_END), "FOR_END");
159 typeMap.put(new Integer(NodeType.DO_BEFORE_FIRST_STATEMENT), "DO_BEFORE_FIRST_STATEMENT");
160 typeMap.put(new Integer(NodeType.DO_EXPR), "DO_EXPR");
161 typeMap.put(new Integer(NodeType.RETURN_STATEMENT), "RETURN_STATEMENT");
162 typeMap.put(new Integer(NodeType.BREAK_STATEMENT), "BREAK_STATEMENT");
163 typeMap.put(new Integer(NodeType.CONTINUE_STATEMENT), "CONTINUE_STATEMENT");
164 }
165 if (!typeMap.containsKey(new Integer(intype))) {
166 throw new RuntimeException("Couldn't find type id " + intype);
167 }
168 return (String)typeMap.get(new Integer(intype));
169 }
170
171 }