View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.dfa;
5   
6   import java.util.ArrayList;
7   import java.util.BitSet;
8   import java.util.HashMap;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.StringTokenizer;
12  
13  import net.sourceforge.pmd.lang.ast.Node;
14  
15  /**
16   * @author raik
17   *         <p/>
18   *         Each data flow contains a set of DataFlowNodes.
19   */
20  public abstract class AbstractDataFlowNode implements DataFlowNode {
21  
22      protected Node node;
23      protected Map<Integer, String> typeMap = new HashMap<Integer, String>();
24  
25      protected List<DataFlowNode> parents = new ArrayList<DataFlowNode>();
26      protected List<DataFlowNode> children = new ArrayList<DataFlowNode>();
27      protected BitSet type = new BitSet();
28      protected List<VariableAccess> variableAccess = new ArrayList<VariableAccess>();
29      protected List<DataFlowNode> dataFlow;
30      protected int line;
31  
32      public AbstractDataFlowNode(List<DataFlowNode> dataFlow) {
33  	this.dataFlow = dataFlow;
34  	if (!this.dataFlow.isEmpty()) {
35  	    DataFlowNode parent = this.dataFlow.get(this.dataFlow.size() - 1);
36  	    parent.addPathToChild(this);
37  	}
38  	this.dataFlow.add(this);
39      }
40  
41      public AbstractDataFlowNode(List<DataFlowNode> dataFlow, Node node) {
42  	this(dataFlow);
43  
44  	this.node = node;
45  	node.setDataFlowNode(this);
46  	this.line = node.getBeginLine();
47      }
48  
49      public void addPathToChild(DataFlowNode child) {
50  	DataFlowNode thisChild = child;
51  	// TODO - throw an exception if already contained in children list?
52  	if (!this.children.contains(thisChild) || this.equals(thisChild)) {
53  	    this.children.add(thisChild);
54  	    thisChild.getParents().add(this);
55  	}
56      }
57  
58      public boolean removePathToChild(DataFlowNode child) {
59  	DataFlowNode thisChild = child;
60  	thisChild.getParents().remove(this);
61  	return this.children.remove(thisChild);
62      }
63  
64      public void reverseParentPathsTo(DataFlowNode destination) {
65  	while (!parents.isEmpty()) {
66  	    DataFlowNode parent = 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 Node getNode() {
90  	return this.node;
91      }
92  
93      public List<DataFlowNode> getChildren() {
94  	return this.children;
95      }
96  
97      public List<DataFlowNode> getParents() {
98  	return this.parents;
99      }
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 }