View Javadoc

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          // TODO - throw an exception if already contained in children list?
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 }