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